mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-16 10:59:46 +12:00
metal: initial support
This commit is contained in:
parent
29d9ed7224
commit
f0547d1a71
167 changed files with 28839 additions and 1271 deletions
|
@ -26,12 +26,13 @@ endif()
|
||||||
|
|
||||||
if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-format-nonliteral -Wno-format-security")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-format-nonliteral -Wno-format-security")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(DISABLE_PANIC_DEV "Make a build with fewer and less intrusive asserts" ON)
|
option(DISABLE_PANIC_DEV "Make a build with fewer and less intrusive asserts" ON)
|
||||||
option(GPU_DEBUG_INFO "Enable additional GPU debugging info" OFF)
|
option(GPU_DEBUG_INFO "Enable additional GPU debugging info" OFF)
|
||||||
option(ENABLE_OPENGL "Enable OpenGL rendering backend" ON)
|
option(ENABLE_OPENGL "Enable OpenGL rendering backend" ON)
|
||||||
option(ENABLE_VULKAN "Enable Vulkan rendering backend" ON)
|
option(ENABLE_VULKAN "Enable Vulkan rendering backend" ON)
|
||||||
|
option(ENABLE_METAL "Enable Metal rendering backend (if available)" ON)
|
||||||
option(ENABLE_LTO "Enable link-time optimization" OFF)
|
option(ENABLE_LTO "Enable link-time optimization" OFF)
|
||||||
option(ENABLE_TESTS "Compile unit-tests" OFF)
|
option(ENABLE_TESTS "Compile unit-tests" OFF)
|
||||||
option(ENABLE_USER_BUILD "Make a user-facing build. These builds have various assertions disabled, LTO, and more" OFF)
|
option(ENABLE_USER_BUILD "Make a user-facing build. These builds have various assertions disabled, LTO, and more" OFF)
|
||||||
|
@ -224,7 +225,7 @@ set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/termcolor.hpp
|
||||||
include/services/mic.hpp include/services/cecd.hpp include/services/ac.hpp
|
include/services/mic.hpp include/services/cecd.hpp include/services/ac.hpp
|
||||||
include/services/am.hpp include/services/boss.hpp include/services/frd.hpp include/services/nim.hpp
|
include/services/am.hpp include/services/boss.hpp include/services/frd.hpp include/services/nim.hpp
|
||||||
include/fs/archive_ext_save_data.hpp include/fs/archive_ncch.hpp include/services/mcu/mcu_hwc.hpp
|
include/fs/archive_ext_save_data.hpp include/fs/archive_ncch.hpp include/services/mcu/mcu_hwc.hpp
|
||||||
include/colour.hpp include/services/y2r.hpp include/services/cam.hpp include/services/ssl.hpp
|
include/colour.hpp include/services/y2r.hpp include/services/cam.hpp include/services/ssl.hpp
|
||||||
include/services/ldr_ro.hpp include/ipc.hpp include/services/act.hpp include/services/nfc.hpp
|
include/services/ldr_ro.hpp include/ipc.hpp include/services/act.hpp include/services/nfc.hpp
|
||||||
include/system_models.hpp include/services/dlp_srvr.hpp include/PICA/dynapica/pica_recs.hpp
|
include/system_models.hpp include/services/dlp_srvr.hpp include/PICA/dynapica/pica_recs.hpp
|
||||||
include/PICA/dynapica/x64_regs.hpp include/PICA/dynapica/vertex_loader_rec.hpp include/PICA/dynapica/shader_rec.hpp
|
include/PICA/dynapica/x64_regs.hpp include/PICA/dynapica/vertex_loader_rec.hpp include/PICA/dynapica/shader_rec.hpp
|
||||||
|
@ -235,7 +236,7 @@ set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/termcolor.hpp
|
||||||
include/config.hpp include/services/ir_user.hpp include/http_server.hpp include/cheats.hpp
|
include/config.hpp include/services/ir_user.hpp include/http_server.hpp include/cheats.hpp
|
||||||
include/action_replay.hpp include/renderer_sw/renderer_sw.hpp include/compiler_builtins.hpp
|
include/action_replay.hpp include/renderer_sw/renderer_sw.hpp include/compiler_builtins.hpp
|
||||||
include/fs/romfs.hpp include/fs/ivfc.hpp include/discord_rpc.hpp include/services/http.hpp include/result/result_cfg.hpp
|
include/fs/romfs.hpp include/fs/ivfc.hpp include/discord_rpc.hpp include/services/http.hpp include/result/result_cfg.hpp
|
||||||
include/applets/applet.hpp include/applets/mii_selector.hpp include/math_util.hpp include/services/soc.hpp
|
include/applets/applet.hpp include/applets/mii_selector.hpp include/math_util.hpp include/services/soc.hpp
|
||||||
include/services/news_u.hpp include/applets/software_keyboard.hpp include/applets/applet_manager.hpp include/fs/archive_user_save_data.hpp
|
include/services/news_u.hpp include/applets/software_keyboard.hpp include/applets/applet_manager.hpp include/fs/archive_user_save_data.hpp
|
||||||
include/services/amiibo_device.hpp include/services/nfc_types.hpp include/swap.hpp include/services/csnd.hpp include/services/nwm_uds.hpp
|
include/services/amiibo_device.hpp include/services/nfc_types.hpp include/swap.hpp include/services/csnd.hpp include/services/nwm_uds.hpp
|
||||||
include/fs/archive_system_save_data.hpp include/lua_manager.hpp include/memory_mapped_file.hpp include/hydra_icon.hpp
|
include/fs/archive_system_save_data.hpp include/lua_manager.hpp include/memory_mapped_file.hpp include/hydra_icon.hpp
|
||||||
|
@ -400,8 +401,36 @@ if(ENABLE_VULKAN)
|
||||||
target_link_libraries(AlberCore PRIVATE Vulkan::Vulkan resources_renderer_vk)
|
target_link_libraries(AlberCore PRIVATE Vulkan::Vulkan resources_renderer_vk)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(ENABLE_METAL AND APPLE)
|
||||||
|
set(RENDERER_MTL_INCLUDE_FILES include/renderer_mtl/renderer_mtl.hpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(RENDERER_MTL_SOURCE_FILES src/core/renderer_mtl/metal_cpp_impl.cpp
|
||||||
|
src/core/renderer_mtl/renderer_mtl.cpp
|
||||||
|
src/host_shaders/metal_display.metal
|
||||||
|
)
|
||||||
|
|
||||||
|
set(HEADER_FILES ${HEADER_FILES} ${RENDERER_MTL_INCLUDE_FILES})
|
||||||
|
source_group("Source Files\\Core\\Metal Renderer" FILES ${RENDERER_MTL_SOURCE_FILES})
|
||||||
|
|
||||||
|
# TODO: compile Metal shaders to .metallib
|
||||||
|
|
||||||
|
cmrc_add_resource_library(
|
||||||
|
resources_renderer_mtl
|
||||||
|
NAMESPACE RendererMTL
|
||||||
|
WHENCE "src/host_shaders/"
|
||||||
|
"src/host_shaders/metal_display.metal"
|
||||||
|
)
|
||||||
|
|
||||||
|
target_sources(AlberCore PRIVATE ${RENDERER_MTL_SOURCE_FILES})
|
||||||
|
target_compile_definitions(AlberCore PUBLIC "PANDA3DS_ENABLE_METAL=1")
|
||||||
|
target_include_directories(AlberCore PRIVATE third_party/metal-cpp)
|
||||||
|
# TODO: check if all of them are needed
|
||||||
|
target_link_libraries(AlberCore PRIVATE "-framework Metal" "-framework Foundation" "-framework QuartzCore" resources_renderer_mtl)
|
||||||
|
endif()
|
||||||
|
|
||||||
source_group("Header Files\\Core" FILES ${HEADER_FILES})
|
source_group("Header Files\\Core" FILES ${HEADER_FILES})
|
||||||
set(ALL_SOURCES ${SOURCE_FILES} ${FS_SOURCE_FILES} ${CRYPTO_SOURCE_FILES} ${KERNEL_SOURCE_FILES}
|
set(ALL_SOURCES ${SOURCE_FILES} ${FS_SOURCE_FILES} ${CRYPTO_SOURCE_FILES} ${KERNEL_SOURCE_FILES}
|
||||||
${LOADER_SOURCE_FILES} ${SERVICE_SOURCE_FILES} ${APPLET_SOURCE_FILES} ${RENDERER_SW_SOURCE_FILES} ${PICA_SOURCE_FILES} ${THIRD_PARTY_SOURCE_FILES}
|
${LOADER_SOURCE_FILES} ${SERVICE_SOURCE_FILES} ${APPLET_SOURCE_FILES} ${RENDERER_SW_SOURCE_FILES} ${PICA_SOURCE_FILES} ${THIRD_PARTY_SOURCE_FILES}
|
||||||
${AUDIO_SOURCE_FILES} ${HEADER_FILES} ${FRONTEND_HEADER_FILES})
|
${AUDIO_SOURCE_FILES} ${HEADER_FILES} ${FRONTEND_HEADER_FILES})
|
||||||
target_sources(AlberCore PRIVATE ${ALL_SOURCES})
|
target_sources(AlberCore PRIVATE ${ALL_SOURCES})
|
||||||
|
|
|
@ -33,8 +33,8 @@ namespace Audio {
|
||||||
SampleFormat format;
|
SampleFormat format;
|
||||||
SourceType sourceType;
|
SourceType sourceType;
|
||||||
|
|
||||||
bool fromQueue = false; // Is this buffer from the buffer queue or an embedded buffer?
|
bool fromQueue = false; // Is this buffer from the buffer queue or an embedded buffer?
|
||||||
bool hasPlayedOnce = false; // Has the buffer been played at least once before?
|
bool hasPlayedOnce = false; // Has the buffer been played at least once before?
|
||||||
|
|
||||||
bool operator<(const Buffer& other) const {
|
bool operator<(const Buffer& other) const {
|
||||||
// Lower ID = Higher priority
|
// Lower ID = Higher priority
|
||||||
|
@ -136,7 +136,7 @@ namespace Audio {
|
||||||
const auto counter0 = dspRam.region0.frameCounter;
|
const auto counter0 = dspRam.region0.frameCounter;
|
||||||
const auto counter1 = dspRam.region1.frameCounter;
|
const auto counter1 = dspRam.region1.frameCounter;
|
||||||
|
|
||||||
// Handle wraparound cases first
|
// HandleType wraparound cases first
|
||||||
if (counter0 == 0xffff && counter1 != 0xfffe) {
|
if (counter0 == 0xffff && counter1 != 0xfffe) {
|
||||||
return 1;
|
return 1;
|
||||||
} else if (counter1 == 0xffff && counter0 != 0xfffe) {
|
} else if (counter1 == 0xffff && counter0 != 0xfffe) {
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
class CapstoneDisassembler {
|
class CapstoneDisassembler {
|
||||||
csh handle; // Handle to our disassembler object
|
csh handle; // HandleType to our disassembler object
|
||||||
cs_insn* instructions = nullptr; // Pointer to instruction object
|
cs_insn* instructions = nullptr; // Pointer to instruction object
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
#include "memory.hpp"
|
#include "memory.hpp"
|
||||||
#include "result.hpp"
|
#include "result.hpp"
|
||||||
|
@ -15,13 +16,13 @@
|
||||||
using Result::HorizonResult;
|
using Result::HorizonResult;
|
||||||
|
|
||||||
namespace PathType {
|
namespace PathType {
|
||||||
enum : u32 {
|
enum : u32 {
|
||||||
Invalid = 0,
|
Invalid = 0,
|
||||||
Empty = 1,
|
Empty = 1,
|
||||||
Binary = 2,
|
Binary = 2,
|
||||||
ASCII = 3,
|
ASCII = 3,
|
||||||
UTF16 = 4,
|
UTF16 = 4,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ArchiveID {
|
namespace ArchiveID {
|
||||||
|
@ -42,83 +43,81 @@ namespace ArchiveID {
|
||||||
UserSaveData2 = 0x567890B4,
|
UserSaveData2 = 0x567890B4,
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::string toString(u32 id) {
|
static std::string toString(u32 id) {
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case SelfNCCH: return "SelfNCCH";
|
case SelfNCCH: return "SelfNCCH";
|
||||||
case SaveData: return "SaveData";
|
case SaveData: return "SaveData";
|
||||||
case ExtSaveData: return "ExtSaveData";
|
case ExtSaveData: return "ExtSaveData";
|
||||||
case SharedExtSaveData: return "SharedExtSaveData";
|
case SharedExtSaveData: return "SharedExtSaveData";
|
||||||
case SystemSaveData: return "SystemSaveData";
|
case SystemSaveData: return "SystemSaveData";
|
||||||
case SDMC: return "SDMC";
|
case SDMC: return "SDMC";
|
||||||
case SDMCWriteOnly: return "SDMC (Write-only)";
|
case SDMCWriteOnly: return "SDMC (Write-only)";
|
||||||
case SavedataAndNcch: return "Savedata & NCCH (archive 0x2345678A)";
|
case SavedataAndNcch: return "Savedata & NCCH (archive 0x2345678A)";
|
||||||
default: return "Unknown archive";
|
default: return "Unknown archive";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} // namespace ArchiveID
|
||||||
|
|
||||||
struct FSPath {
|
struct FSPath {
|
||||||
u32 type = PathType::Invalid;
|
u32 type = PathType::Invalid;
|
||||||
|
|
||||||
std::vector<u8> binary; // Path data for binary paths
|
std::vector<u8> binary; // Path data for binary paths
|
||||||
std::string string; // Path data for ASCII paths
|
std::string string; // Path data for ASCII paths
|
||||||
std::u16string utf16_string;
|
std::u16string utf16_string;
|
||||||
|
|
||||||
FSPath() {}
|
FSPath() {}
|
||||||
|
|
||||||
FSPath(u32 type, const std::vector<u8>& vec) : type(type) {
|
FSPath(u32 type, const std::vector<u8>& vec) : type(type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case PathType::Binary:
|
case PathType::Binary: binary = std::move(vec); break;
|
||||||
binary = std::move(vec);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PathType::ASCII:
|
case PathType::ASCII:
|
||||||
string.resize(vec.size() - 1); // -1 because of the null terminator
|
string.resize(vec.size() - 1); // -1 because of the null terminator
|
||||||
std::memcpy(string.data(), vec.data(), vec.size() - 1); // Copy string data
|
std::memcpy(string.data(), vec.data(), vec.size() - 1); // Copy string data
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PathType::UTF16: {
|
case PathType::UTF16: {
|
||||||
const size_t size = vec.size() / sizeof(u16) - 1; // Character count. -1 because null terminator here too
|
const size_t size = vec.size() / sizeof(u16) - 1; // Character count. -1 because null terminator here too
|
||||||
utf16_string.resize(size);
|
utf16_string.resize(size);
|
||||||
std::memcpy(utf16_string.data(), vec.data(), size * sizeof(u16));
|
std::memcpy(utf16_string.data(), vec.data(), size * sizeof(u16));
|
||||||
break;
|
break;
|
||||||
}
|
};
|
||||||
; }
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FilePerms {
|
struct FilePerms {
|
||||||
u32 raw;
|
u32 raw;
|
||||||
|
|
||||||
FilePerms(u32 val) : raw(val) {}
|
FilePerms(u32 val) : raw(val) {}
|
||||||
bool read() const { return (raw & 1) != 0; }
|
bool read() const { return (raw & 1) != 0; }
|
||||||
bool write() const { return (raw & 2) != 0; }
|
bool write() const { return (raw & 2) != 0; }
|
||||||
bool create() const { return (raw & 4) != 0; }
|
bool create() const { return (raw & 4) != 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class ArchiveBase;
|
class ArchiveBase;
|
||||||
struct FileSession {
|
struct FileSession {
|
||||||
ArchiveBase* archive = nullptr;
|
ArchiveBase* archive = nullptr;
|
||||||
FILE* fd = nullptr; // File descriptor for file sessions that require them.
|
FILE* fd = nullptr; // File descriptor for file sessions that require them.
|
||||||
FSPath path;
|
FSPath path;
|
||||||
FSPath archivePath;
|
FSPath archivePath;
|
||||||
u32 priority = 0; // TODO: What does this even do
|
u32 priority = 0; // TODO: What does this even do
|
||||||
bool isOpen;
|
bool isOpen;
|
||||||
|
|
||||||
FileSession(ArchiveBase* archive, const FSPath& filePath, const FSPath& archivePath, FILE* fd, bool isOpen = true) :
|
FileSession(ArchiveBase* archive, const FSPath& filePath, const FSPath& archivePath, FILE* fd, bool isOpen = true)
|
||||||
archive(archive), path(filePath), archivePath(archivePath), fd(fd), isOpen(isOpen), priority(0) {}
|
: archive(archive), path(filePath), archivePath(archivePath), fd(fd), isOpen(isOpen), priority(0) {}
|
||||||
|
|
||||||
// For cloning a file session
|
// For cloning a file session
|
||||||
FileSession(const FileSession& other) : archive(other.archive), path(other.path),
|
FileSession(const FileSession& other)
|
||||||
archivePath(other.archivePath), fd(other.fd), isOpen(other.isOpen), priority(other.priority) {}
|
: archive(other.archive), path(other.path), archivePath(other.archivePath), fd(other.fd), isOpen(other.isOpen), priority(other.priority) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ArchiveSession {
|
struct ArchiveSession {
|
||||||
ArchiveBase* archive = nullptr;
|
ArchiveBase* archive = nullptr;
|
||||||
FSPath path;
|
FSPath path;
|
||||||
bool isOpen;
|
bool isOpen;
|
||||||
|
|
||||||
ArchiveSession(ArchiveBase* archive, const FSPath& filePath, bool isOpen = true) : archive(archive), path(filePath), isOpen(isOpen) {}
|
ArchiveSession(ArchiveBase* archive, const FSPath& filePath, bool isOpen = true) : archive(archive), path(filePath), isOpen(isOpen) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DirectoryEntry {
|
struct DirectoryEntry {
|
||||||
|
@ -156,106 +155,104 @@ struct DirectorySession {
|
||||||
using FileDescriptor = std::optional<FILE*>;
|
using FileDescriptor = std::optional<FILE*>;
|
||||||
|
|
||||||
class ArchiveBase {
|
class ArchiveBase {
|
||||||
public:
|
public:
|
||||||
struct FormatInfo {
|
struct FormatInfo {
|
||||||
u32 size; // Archive size
|
u32 size; // Archive size
|
||||||
u32 numOfDirectories; // Number of directories
|
u32 numOfDirectories; // Number of directories
|
||||||
u32 numOfFiles; // Number of files
|
u32 numOfFiles; // Number of files
|
||||||
bool duplicateData; // Whether to duplicate data or not
|
bool duplicateData; // Whether to duplicate data or not
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
using Handle = u32;
|
using HandleType = u32;
|
||||||
|
|
||||||
static constexpr FileDescriptor NoFile = nullptr;
|
static constexpr FileDescriptor NoFile = nullptr;
|
||||||
static constexpr FileDescriptor FileError = std::nullopt;
|
static constexpr FileDescriptor FileError = std::nullopt;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
|
|
||||||
// Returns if a specified 3DS path in UTF16 or ASCII format is safe or not
|
// Returns if a specified 3DS path in UTF16 or ASCII format is safe or not
|
||||||
// A 3DS path is considered safe if its first character is '/' which means we're not trying to access anything outside the root of the fs
|
// A 3DS path is considered safe if its first character is '/' which means we're not trying to access anything outside the root of the fs
|
||||||
// And if it doesn't contain enough instances of ".." (Indicating "climb up a folder" in filesystems) to let the software climb up the directory tree
|
// And if it doesn't contain enough instances of ".." (Indicating "climb up a folder" in filesystems) to let the software climb up the directory
|
||||||
// And access files outside of the emulator's app data folder
|
// tree And access files outside of the emulator's app data folder
|
||||||
template <u32 format>
|
template <u32 format>
|
||||||
bool isPathSafe(const FSPath& path) {
|
bool isPathSafe(const FSPath& path) {
|
||||||
static_assert(format == PathType::ASCII || format == PathType::UTF16);
|
static_assert(format == PathType::ASCII || format == PathType::UTF16);
|
||||||
using String = typename std::conditional<format == PathType::UTF16, std::u16string, std::string>::type; // String type for the path
|
using String = typename std::conditional<format == PathType::UTF16, std::u16string, std::string>::type; // String type for the path
|
||||||
using Char = typename String::value_type; // Char type for the path
|
using Char = typename String::value_type; // Char type for the path
|
||||||
|
|
||||||
String pathString, dots;
|
String pathString, dots;
|
||||||
if constexpr (std::is_same<String, std::u16string>()) {
|
if constexpr (std::is_same<String, std::u16string>()) {
|
||||||
pathString = path.utf16_string;
|
pathString = path.utf16_string;
|
||||||
dots = u"..";
|
dots = u"..";
|
||||||
} else {
|
} else {
|
||||||
pathString = path.string;
|
pathString = path.string;
|
||||||
dots = "..";
|
dots = "..";
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the path string doesn't begin with / then that means it's accessing outside the FS root, which is invalid & unsafe
|
// If the path string doesn't begin with / then that means it's accessing outside the FS root, which is invalid & unsafe
|
||||||
if (pathString[0] != Char('/')) return false;
|
if (pathString[0] != Char('/')) return false;
|
||||||
|
|
||||||
// Counts how many folders sans the root our file is nested under.
|
// Counts how many folders sans the root our file is nested under.
|
||||||
// If it's < 0 at any point of parsing, then the path is unsafe and tries to crawl outside our file sandbox.
|
// If it's < 0 at any point of parsing, then the path is unsafe and tries to crawl outside our file sandbox.
|
||||||
// If it's 0 then this is the FS root.
|
// If it's 0 then this is the FS root.
|
||||||
// If it's > 0 then we're in a subdirectory of the root.
|
// If it's > 0 then we're in a subdirectory of the root.
|
||||||
int level = 0;
|
int level = 0;
|
||||||
|
|
||||||
// Split the string on / characters and see how many of the substrings are ".."
|
// Split the string on / characters and see how many of the substrings are ".."
|
||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
while ((pos = pathString.find(Char('/'))) != String::npos) {
|
while ((pos = pathString.find(Char('/'))) != String::npos) {
|
||||||
String token = pathString.substr(0, pos);
|
String token = pathString.substr(0, pos);
|
||||||
pathString.erase(0, pos + 1);
|
pathString.erase(0, pos + 1);
|
||||||
|
|
||||||
if (token == dots) {
|
if (token == dots) {
|
||||||
level--;
|
level--;
|
||||||
if (level < 0) return false;
|
if (level < 0) return false;
|
||||||
} else {
|
} else {
|
||||||
level++;
|
level++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual std::string name() = 0;
|
virtual std::string name() = 0;
|
||||||
virtual u64 getFreeBytes() = 0;
|
virtual u64 getFreeBytes() = 0;
|
||||||
virtual HorizonResult createFile(const FSPath& path, u64 size) = 0;
|
virtual HorizonResult createFile(const FSPath& path, u64 size) = 0;
|
||||||
virtual HorizonResult deleteFile(const FSPath& path) = 0;
|
virtual HorizonResult deleteFile(const FSPath& path) = 0;
|
||||||
|
|
||||||
virtual Rust::Result<FormatInfo, HorizonResult> getFormatInfo(const FSPath& path) {
|
virtual Rust::Result<FormatInfo, HorizonResult> getFormatInfo(const FSPath& path) {
|
||||||
Helpers::panic("Unimplemented GetFormatInfo for %s archive", name().c_str());
|
Helpers::panic("Unimplemented GetFormatInfo for %s archive", name().c_str());
|
||||||
// Return a dummy struct just to avoid the UB of not returning anything, even if we panic
|
// Return a dummy struct just to avoid the UB of not returning anything, even if we panic
|
||||||
return Ok(FormatInfo{ .size = 0, .numOfDirectories = 0, .numOfFiles = 0, .duplicateData = false });
|
return Ok(FormatInfo{.size = 0, .numOfDirectories = 0, .numOfFiles = 0, .duplicateData = false});
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual HorizonResult createDirectory(const FSPath& path) {
|
virtual HorizonResult createDirectory(const FSPath& path) {
|
||||||
Helpers::panic("Unimplemented CreateDirectory for %s archive", name().c_str());
|
Helpers::panic("Unimplemented CreateDirectory for %s archive", name().c_str());
|
||||||
return Result::FS::AlreadyExists;
|
return Result::FS::AlreadyExists;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns nullopt if opening the file failed, otherwise returns a file descriptor to it (nullptr if none is needed)
|
// Returns nullopt if opening the file failed, otherwise returns a file descriptor to it (nullptr if none is needed)
|
||||||
virtual FileDescriptor openFile(const FSPath& path, const FilePerms& perms) = 0;
|
virtual FileDescriptor openFile(const FSPath& path, const FilePerms& perms) = 0;
|
||||||
virtual Rust::Result<ArchiveBase*, HorizonResult> openArchive(const FSPath& path) = 0;
|
virtual Rust::Result<ArchiveBase*, HorizonResult> openArchive(const FSPath& path) = 0;
|
||||||
|
|
||||||
virtual Rust::Result<DirectorySession, HorizonResult> openDirectory(const FSPath& path) {
|
virtual Rust::Result<DirectorySession, HorizonResult> openDirectory(const FSPath& path) {
|
||||||
Helpers::panic("Unimplemented OpenDirectory for %s archive", name().c_str());
|
Helpers::panic("Unimplemented OpenDirectory for %s archive", name().c_str());
|
||||||
return Err(Result::FS::FileNotFoundAlt);
|
return Err(Result::FS::FileNotFoundAlt);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void format(const FSPath& path, const FormatInfo& info) {
|
virtual void format(const FSPath& path, const FormatInfo& info) { Helpers::panic("Unimplemented Format for %s archive", name().c_str()); }
|
||||||
Helpers::panic("Unimplemented Format for %s archive", name().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual HorizonResult renameFile(const FSPath& oldPath, const FSPath& newPath) {
|
virtual HorizonResult renameFile(const FSPath& oldPath, const FSPath& newPath) {
|
||||||
Helpers::panic("Unimplemented RenameFile for %s archive", name().c_str());
|
Helpers::panic("Unimplemented RenameFile for %s archive", name().c_str());
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read size bytes from a file starting at offset "offset" into a certain buffer in memory
|
// Read size bytes from a file starting at offset "offset" into a certain buffer in memory
|
||||||
// Returns the number of bytes read, or nullopt if the read failed
|
// Returns the number of bytes read, or nullopt if the read failed
|
||||||
virtual std::optional<u32> readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) = 0;
|
virtual std::optional<u32> readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) = 0;
|
||||||
|
|
||||||
ArchiveBase(Memory& mem) : mem(mem) {}
|
ArchiveBase(Memory& mem) : mem(mem) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ArchiveResource {
|
struct ArchiveResource {
|
||||||
|
@ -263,4 +260,4 @@ struct ArchiveResource {
|
||||||
u32 clusterSize; // Size of a cluster in bytes
|
u32 clusterSize; // Size of a cluster in bytes
|
||||||
u32 partitionCapacityInClusters;
|
u32 partitionCapacityInClusters;
|
||||||
u32 freeSpaceInClusters;
|
u32 freeSpaceInClusters;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,23 +1,23 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
|
|
||||||
using Handle = u32;
|
using HandleType = u32;
|
||||||
|
|
||||||
namespace KernelHandles {
|
namespace KernelHandles {
|
||||||
enum : u32 {
|
enum : u32 {
|
||||||
Max = 0xFFFF7FFF, // Max handle the kernel can automagically allocate
|
Max = 0xFFFF7FFF, // Max handle the kernel can automagically allocate
|
||||||
|
|
||||||
// Hardcoded handles
|
// Hardcoded handles
|
||||||
CurrentThread = 0xFFFF8000, // Used by the original kernel
|
CurrentThread = 0xFFFF8000, // Used by the original kernel
|
||||||
CurrentProcess = 0xFFFF8001, // Used by the original kernel
|
CurrentProcess = 0xFFFF8001, // Used by the original kernel
|
||||||
AC, // Something network related
|
AC, // Something network related
|
||||||
ACT, // Handles NNID accounts
|
ACT, // Handles NNID accounts
|
||||||
AM, // Application manager
|
AM, // Application manager
|
||||||
APT, // App Title something service?
|
APT, // App Title something service?
|
||||||
BOSS, // Streetpass stuff?
|
BOSS, // Streetpass stuff?
|
||||||
CAM, // Camera service
|
CAM, // Camera service
|
||||||
CECD, // More Streetpass stuff?
|
CECD, // More Streetpass stuff?
|
||||||
CFG_U, // CFG service (Console & region info)
|
CFG_U, // CFG service (Console & region info)
|
||||||
CFG_I,
|
CFG_I,
|
||||||
CFG_S, // Used by most system apps in lieu of cfg:u
|
CFG_S, // Used by most system apps in lieu of cfg:u
|
||||||
CSND, // Plays audio directly from PCM samples
|
CSND, // Plays audio directly from PCM samples
|
||||||
|
@ -50,10 +50,10 @@ namespace KernelHandles {
|
||||||
MinServiceHandle = AC,
|
MinServiceHandle = AC,
|
||||||
MaxServiceHandle = Y2R,
|
MaxServiceHandle = Y2R,
|
||||||
|
|
||||||
GSPSharedMemHandle = MaxServiceHandle + 1, // Handle for the GSP shared memory
|
GSPSharedMemHandle = MaxServiceHandle + 1, // HandleType for the GSP shared memory
|
||||||
FontSharedMemHandle,
|
FontSharedMemHandle,
|
||||||
CSNDSharedMemHandle,
|
CSNDSharedMemHandle,
|
||||||
APTCaptureSharedMemHandle, // Shared memory for display capture info,
|
APTCaptureSharedMemHandle, // Shared memory for display capture info,
|
||||||
HIDSharedMemHandle,
|
HIDSharedMemHandle,
|
||||||
|
|
||||||
MinSharedMemHandle = GSPSharedMemHandle,
|
MinSharedMemHandle = GSPSharedMemHandle,
|
||||||
|
@ -61,17 +61,13 @@ namespace KernelHandles {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns whether "handle" belongs to one of the OS services
|
// Returns whether "handle" belongs to one of the OS services
|
||||||
static constexpr bool isServiceHandle(Handle handle) {
|
static constexpr bool isServiceHandle(HandleType handle) { return handle >= MinServiceHandle && handle <= MaxServiceHandle; }
|
||||||
return handle >= MinServiceHandle && handle <= MaxServiceHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns whether "handle" belongs to one of the OS services' shared memory areas
|
// Returns whether "handle" belongs to one of the OS services' shared memory areas
|
||||||
static constexpr bool isSharedMemHandle(Handle handle) {
|
static constexpr bool isSharedMemHandle(HandleType handle) { return handle >= MinSharedMemHandle && handle <= MaxSharedMemHandle; }
|
||||||
return handle >= MinSharedMemHandle && handle <= MaxSharedMemHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the name of a handle as a string based on the given handle
|
// Returns the name of a handle as a string based on the given handle
|
||||||
static const char* getServiceName(Handle handle) {
|
static const char* getServiceName(HandleType handle) {
|
||||||
switch (handle) {
|
switch (handle) {
|
||||||
case AC: return "AC";
|
case AC: return "AC";
|
||||||
case ACT: return "ACT";
|
case ACT: return "ACT";
|
||||||
|
@ -110,4 +106,4 @@ namespace KernelHandles {
|
||||||
default: return "Unknown";
|
default: return "Unknown";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} // namespace KernelHandles
|
||||||
|
|
|
@ -34,22 +34,22 @@ class Kernel {
|
||||||
static_assert(appResourceLimits.maxThreads <= 63, "The waitlist system is built on the premise that <= 63 threads max can be active");
|
static_assert(appResourceLimits.maxThreads <= 63, "The waitlist system is built on the premise that <= 63 threads max can be active");
|
||||||
|
|
||||||
std::vector<KernelObject> objects;
|
std::vector<KernelObject> objects;
|
||||||
std::vector<Handle> portHandles;
|
std::vector<HandleType> portHandles;
|
||||||
std::vector<Handle> mutexHandles;
|
std::vector<HandleType> mutexHandles;
|
||||||
std::vector<Handle> timerHandles;
|
std::vector<HandleType> timerHandles;
|
||||||
|
|
||||||
// Thread indices, sorted by priority
|
// Thread indices, sorted by priority
|
||||||
std::vector<int> threadIndices;
|
std::vector<int> threadIndices;
|
||||||
|
|
||||||
Handle currentProcess;
|
HandleType currentProcess;
|
||||||
Handle mainThread;
|
HandleType mainThread;
|
||||||
int currentThreadIndex;
|
int currentThreadIndex;
|
||||||
Handle srvHandle; // Handle for the special service manager port "srv:"
|
HandleType srvHandle; // HandleType for the special service manager port "srv:"
|
||||||
Handle errorPortHandle; // Handle for the err:f port used for displaying errors
|
HandleType errorPortHandle; // HandleType for the err:f port used for displaying errors
|
||||||
|
|
||||||
u32 arbiterCount;
|
u32 arbiterCount;
|
||||||
u32 threadCount; // How many threads in our thread pool have been used as of now (Up to 32)
|
u32 threadCount; // How many threads in our thread pool have been used as of now (Up to 32)
|
||||||
u32 aliveThreadCount; // How many of these threads are actually alive?
|
u32 aliveThreadCount; // How many of these threads are actually alive?
|
||||||
ServiceManager serviceManager;
|
ServiceManager serviceManager;
|
||||||
|
|
||||||
// Top 8 bits are the major version, bottom 8 are the minor version
|
// Top 8 bits are the major version, bottom 8 are the minor version
|
||||||
|
@ -58,29 +58,29 @@ class Kernel {
|
||||||
// Shows whether a reschedule will be need
|
// Shows whether a reschedule will be need
|
||||||
bool needReschedule = false;
|
bool needReschedule = false;
|
||||||
|
|
||||||
Handle makeArbiter();
|
HandleType makeArbiter();
|
||||||
Handle makeProcess(u32 id);
|
HandleType makeProcess(u32 id);
|
||||||
Handle makePort(const char* name);
|
HandleType makePort(const char* name);
|
||||||
Handle makeSession(Handle port);
|
HandleType makeSession(HandleType port);
|
||||||
Handle makeThread(u32 entrypoint, u32 initialSP, u32 priority, ProcessorID id, u32 arg,ThreadStatus status = ThreadStatus::Dormant);
|
HandleType makeThread(u32 entrypoint, u32 initialSP, u32 priority, ProcessorID id, u32 arg, ThreadStatus status = ThreadStatus::Dormant);
|
||||||
Handle makeMemoryBlock(u32 addr, u32 size, u32 myPermission, u32 otherPermission);
|
HandleType makeMemoryBlock(u32 addr, u32 size, u32 myPermission, u32 otherPermission);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Needs to be public to be accessible to the APT/HID services
|
// Needs to be public to be accessible to the APT/HID services
|
||||||
Handle makeEvent(ResetType resetType, Event::CallbackType callback = Event::CallbackType::None);
|
HandleType makeEvent(ResetType resetType, Event::CallbackType callback = Event::CallbackType::None);
|
||||||
// Needs to be public to be accessible to the APT/DSP services
|
// Needs to be public to be accessible to the APT/DSP services
|
||||||
Handle makeMutex(bool locked = false);
|
HandleType makeMutex(bool locked = false);
|
||||||
// Needs to be public to be accessible to the service manager port
|
// Needs to be public to be accessible to the service manager port
|
||||||
Handle makeSemaphore(u32 initialCount, u32 maximumCount);
|
HandleType makeSemaphore(u32 initialCount, u32 maximumCount);
|
||||||
Handle makeTimer(ResetType resetType);
|
HandleType makeTimer(ResetType resetType);
|
||||||
void pollTimers();
|
void pollTimers();
|
||||||
|
|
||||||
// Signals an event, returns true on success or false if the event does not exist
|
// Signals an event, returns true on success or false if the event does not exist
|
||||||
bool signalEvent(Handle e);
|
bool signalEvent(HandleType e);
|
||||||
// Run the callback for "special" events that have callbacks
|
// Run the callback for "special" events that have callbacks
|
||||||
void runEventCallback(Event::CallbackType callback);
|
void runEventCallback(Event::CallbackType callback);
|
||||||
|
|
||||||
void clearEvent(Handle e) {
|
void clearEvent(HandleType e) {
|
||||||
KernelObject* object = getObject(e, KernelObjectType::Event);
|
KernelObject* object = getObject(e, KernelObjectType::Event);
|
||||||
if (object != nullptr) {
|
if (object != nullptr) {
|
||||||
object->getData<Event>()->fired = false;
|
object->getData<Event>()->fired = false;
|
||||||
|
@ -99,19 +99,19 @@ public:
|
||||||
bool shouldWaitOnObject(KernelObject* object);
|
bool shouldWaitOnObject(KernelObject* object);
|
||||||
void releaseMutex(Mutex* moo);
|
void releaseMutex(Mutex* moo);
|
||||||
void cancelTimer(Timer* timer);
|
void cancelTimer(Timer* timer);
|
||||||
void signalTimer(Handle timerHandle, Timer* timer);
|
void signalTimer(HandleType timerHandle, Timer* timer);
|
||||||
u64 getWakeupTick(s64 ns);
|
u64 getWakeupTick(s64 ns);
|
||||||
|
|
||||||
// Wake up the thread with the highest priority out of all threads in the waitlist
|
// Wake up the thread with the highest priority out of all threads in the waitlist
|
||||||
// Returns the index of the woken up thread
|
// Returns the index of the woken up thread
|
||||||
// Do not call this function with an empty waitlist!!!
|
// Do not call this function with an empty waitlist!!!
|
||||||
int wakeupOneThread(u64 waitlist, Handle handle);
|
int wakeupOneThread(u64 waitlist, HandleType handle);
|
||||||
void wakeupAllThreads(u64 waitlist, Handle handle);
|
void wakeupAllThreads(u64 waitlist, HandleType handle);
|
||||||
|
|
||||||
std::optional<Handle> getPortHandle(const char* name);
|
std::optional<HandleType> getPortHandle(const char* name);
|
||||||
void deleteObjectData(KernelObject& object);
|
void deleteObjectData(KernelObject& object);
|
||||||
|
|
||||||
KernelObject* getProcessFromPID(Handle handle);
|
KernelObject* getProcessFromPID(HandleType handle);
|
||||||
s32 getCurrentResourceValue(const KernelObject* limit, u32 resourceName);
|
s32 getCurrentResourceValue(const KernelObject* limit, u32 resourceName);
|
||||||
u32 getMaxForResource(const KernelObject* limit, u32 resourceName);
|
u32 getMaxForResource(const KernelObject* limit, u32 resourceName);
|
||||||
u32 getTLSPointer();
|
u32 getTLSPointer();
|
||||||
|
@ -178,22 +178,22 @@ public:
|
||||||
void waitSynchronizationN();
|
void waitSynchronizationN();
|
||||||
|
|
||||||
// File operations
|
// File operations
|
||||||
void handleFileOperation(u32 messagePointer, Handle file);
|
void handleFileOperation(u32 messagePointer, HandleType file);
|
||||||
void closeFile(u32 messagePointer, Handle file);
|
void closeFile(u32 messagePointer, HandleType file);
|
||||||
void flushFile(u32 messagePointer, Handle file);
|
void flushFile(u32 messagePointer, HandleType file);
|
||||||
void readFile(u32 messagePointer, Handle file);
|
void readFile(u32 messagePointer, HandleType file);
|
||||||
void writeFile(u32 messagePointer, Handle file);
|
void writeFile(u32 messagePointer, HandleType file);
|
||||||
void getFileSize(u32 messagePointer, Handle file);
|
void getFileSize(u32 messagePointer, HandleType file);
|
||||||
void openLinkFile(u32 messagePointer, Handle file);
|
void openLinkFile(u32 messagePointer, HandleType file);
|
||||||
void setFileSize(u32 messagePointer, Handle file);
|
void setFileSize(u32 messagePointer, HandleType file);
|
||||||
void setFilePriority(u32 messagePointer, Handle file);
|
void setFilePriority(u32 messagePointer, HandleType file);
|
||||||
|
|
||||||
// Directory operations
|
// Directory operations
|
||||||
void handleDirectoryOperation(u32 messagePointer, Handle directory);
|
void handleDirectoryOperation(u32 messagePointer, HandleType directory);
|
||||||
void closeDirectory(u32 messagePointer, Handle directory);
|
void closeDirectory(u32 messagePointer, HandleType directory);
|
||||||
void readDirectory(u32 messagePointer, Handle directory);
|
void readDirectory(u32 messagePointer, HandleType directory);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Kernel(CPU& cpu, Memory& mem, GPU& gpu, const EmulatorConfig& config);
|
Kernel(CPU& cpu, Memory& mem, GPU& gpu, const EmulatorConfig& config);
|
||||||
void initializeFS() { return serviceManager.initializeFS(); }
|
void initializeFS() { return serviceManager.initializeFS(); }
|
||||||
void setVersion(u8 major, u8 minor);
|
void setVersion(u8 major, u8 minor);
|
||||||
|
@ -209,7 +209,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle makeObject(KernelObjectType type) {
|
HandleType makeObject(KernelObjectType type) {
|
||||||
if (handleCounter > KernelHandles::Max) [[unlikely]] {
|
if (handleCounter > KernelHandles::Max) [[unlikely]] {
|
||||||
Helpers::panic("Hlep we somehow created enough kernel objects to overflow this thing");
|
Helpers::panic("Hlep we somehow created enough kernel objects to overflow this thing");
|
||||||
}
|
}
|
||||||
|
@ -219,12 +219,10 @@ public:
|
||||||
return handleCounter++;
|
return handleCounter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<KernelObject>& getObjects() {
|
std::vector<KernelObject>& getObjects() { return objects; }
|
||||||
return objects;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get pointer to the object with the specified handle
|
// Get pointer to the object with the specified handle
|
||||||
KernelObject* getObject(Handle handle) {
|
KernelObject* getObject(HandleType handle) {
|
||||||
// Accessing an object that has not been created
|
// Accessing an object that has not been created
|
||||||
if (handle >= objects.size()) [[unlikely]] {
|
if (handle >= objects.size()) [[unlikely]] {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -234,7 +232,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get pointer to the object with the specified handle and type
|
// Get pointer to the object with the specified handle and type
|
||||||
KernelObject* getObject(Handle handle, KernelObjectType type) {
|
KernelObject* getObject(HandleType handle, KernelObjectType type) {
|
||||||
if (handle >= objects.size() || objects[handle].type != type) [[unlikely]] {
|
if (handle >= objects.size() || objects[handle].type != type) [[unlikely]] {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -246,4 +244,4 @@ public:
|
||||||
|
|
||||||
void sendGPUInterrupt(GPUInterrupt type) { serviceManager.sendGPUInterrupt(type); }
|
void sendGPUInterrupt(GPUInterrupt type) { serviceManager.sendGPUInterrupt(type); }
|
||||||
void clearInstructionCache();
|
void clearInstructionCache();
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,98 +1,102 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#include "fs/archive_base.hpp"
|
#include "fs/archive_base.hpp"
|
||||||
#include "handles.hpp"
|
#include "handles.hpp"
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
#include "result/result.hpp"
|
#include "result/result.hpp"
|
||||||
|
|
||||||
enum class KernelObjectType : u8 {
|
enum class KernelObjectType : u8 {
|
||||||
AddressArbiter, Archive, Directory, File, MemoryBlock, Process, ResourceLimit, Session, Dummy,
|
AddressArbiter,
|
||||||
// Bundle waitable objects together in the enum to let the compiler optimize certain checks better
|
Archive,
|
||||||
Event, Mutex, Port, Semaphore, Timer, Thread
|
Directory,
|
||||||
|
File,
|
||||||
|
MemoryBlock,
|
||||||
|
Process,
|
||||||
|
ResourceLimit,
|
||||||
|
Session,
|
||||||
|
Dummy,
|
||||||
|
// Bundle waitable objects together in the enum to let the compiler optimize certain checks better
|
||||||
|
Event,
|
||||||
|
Mutex,
|
||||||
|
Port,
|
||||||
|
Semaphore,
|
||||||
|
Timer,
|
||||||
|
Thread
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ResourceLimitCategory : int {
|
enum class ResourceLimitCategory : int { Application = 0, SystemApplet = 1, LibraryApplet = 2, Misc = 3 };
|
||||||
Application = 0,
|
|
||||||
SystemApplet = 1,
|
|
||||||
LibraryApplet = 2,
|
|
||||||
Misc = 3
|
|
||||||
};
|
|
||||||
|
|
||||||
// Reset types (for use with events and timers)
|
// Reset types (for use with events and timers)
|
||||||
enum class ResetType {
|
enum class ResetType {
|
||||||
OneShot = 0, // When the primitive is signaled, it will wake up exactly one thread and will clear itself automatically.
|
OneShot = 0, // When the primitive is signaled, it will wake up exactly one thread and will clear itself automatically.
|
||||||
Sticky = 1, // When the primitive is signaled, it will wake up all threads and it won't clear itself automatically.
|
Sticky = 1, // When the primitive is signaled, it will wake up all threads and it won't clear itself automatically.
|
||||||
Pulse = 2, // Only meaningful for timers: same as ONESHOT but it will periodically signal the timer instead of just once.
|
Pulse = 2, // Only meaningful for timers: same as ONESHOT but it will periodically signal the timer instead of just once.
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ArbitrationType {
|
enum class ArbitrationType { Signal = 0, WaitIfLess = 1, DecrementAndWaitIfLess = 2, WaitIfLessTimeout = 3, DecrementAndWaitIfLessTimeout = 4 };
|
||||||
Signal = 0,
|
|
||||||
WaitIfLess = 1,
|
|
||||||
DecrementAndWaitIfLess = 2,
|
|
||||||
WaitIfLessTimeout = 3,
|
|
||||||
DecrementAndWaitIfLessTimeout = 4
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class ProcessorID : s32 {
|
enum class ProcessorID : s32 {
|
||||||
AllCPUs = -1,
|
AllCPUs = -1,
|
||||||
Default = -2,
|
Default = -2,
|
||||||
|
|
||||||
AppCore = 0,
|
AppCore = 0,
|
||||||
Syscore = 1,
|
Syscore = 1,
|
||||||
New3DSExtra1 = 2,
|
New3DSExtra1 = 2,
|
||||||
New3DSExtra2 = 3
|
New3DSExtra2 = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AddressArbiter {};
|
struct AddressArbiter {};
|
||||||
|
|
||||||
struct ResourceLimits {
|
struct ResourceLimits {
|
||||||
Handle handle;
|
HandleType handle;
|
||||||
|
|
||||||
s32 currentCommit = 0;
|
s32 currentCommit = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Process {
|
struct Process {
|
||||||
// Resource limits for this process
|
// Resource limits for this process
|
||||||
ResourceLimits limits;
|
ResourceLimits limits;
|
||||||
// Process ID
|
// Process ID
|
||||||
u32 id;
|
u32 id;
|
||||||
|
|
||||||
Process(u32 id) : id(id) {}
|
Process(u32 id) : id(id) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Event {
|
struct Event {
|
||||||
// Some events (for now, only the DSP semaphore events) need to execute a callback when signalled
|
// Some events (for now, only the DSP semaphore events) need to execute a callback when signalled
|
||||||
// This enum stores what kind of callback they should execute
|
// This enum stores what kind of callback they should execute
|
||||||
enum class CallbackType : u32 {
|
enum class CallbackType : u32 {
|
||||||
None, DSPSemaphore,
|
None,
|
||||||
};
|
DSPSemaphore,
|
||||||
|
};
|
||||||
|
|
||||||
u64 waitlist; // A bitfield where each bit symbolizes if the thread with thread with the corresponding index is waiting on the event
|
u64 waitlist; // A bitfield where each bit symbolizes if the thread with thread with the corresponding index is waiting on the event
|
||||||
ResetType resetType = ResetType::OneShot;
|
ResetType resetType = ResetType::OneShot;
|
||||||
CallbackType callback = CallbackType::None;
|
CallbackType callback = CallbackType::None;
|
||||||
bool fired = false;
|
bool fired = false;
|
||||||
|
|
||||||
Event(ResetType resetType) : resetType(resetType), waitlist(0) {}
|
Event(ResetType resetType) : resetType(resetType), waitlist(0) {}
|
||||||
Event(ResetType resetType, CallbackType cb) : resetType(resetType), waitlist(0), callback(cb) {}
|
Event(ResetType resetType, CallbackType cb) : resetType(resetType), waitlist(0), callback(cb) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Port {
|
struct Port {
|
||||||
static constexpr u32 maxNameLen = 11;
|
static constexpr u32 maxNameLen = 11;
|
||||||
|
|
||||||
char name[maxNameLen + 1] = {};
|
char name[maxNameLen + 1] = {};
|
||||||
bool isPublic = false; // Setting name=NULL creates a private port not accessible from svcConnectToPort.
|
bool isPublic = false; // Setting name=NULL creates a private port not accessible from svcConnectToPort.
|
||||||
|
|
||||||
Port(const char* name) {
|
Port(const char* name) {
|
||||||
// If the name is empty (ie the first char is the null terminator) then the port is private
|
// If the name is empty (ie the first char is the null terminator) then the port is private
|
||||||
isPublic = name[0] != '\0';
|
isPublic = name[0] != '\0';
|
||||||
std::strncpy(this->name, name, maxNameLen);
|
std::strncpy(this->name, name, maxNameLen);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Session {
|
struct Session {
|
||||||
Handle portHandle; // The port this session is subscribed to
|
HandleType portHandle; // The port this session is subscribed to
|
||||||
Session(Handle portHandle) : portHandle(portHandle) {}
|
Session(HandleType portHandle) : portHandle(portHandle) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ThreadStatus {
|
enum class ThreadStatus {
|
||||||
|
@ -115,14 +119,14 @@ struct Thread {
|
||||||
u32 arg;
|
u32 arg;
|
||||||
ProcessorID processorID;
|
ProcessorID processorID;
|
||||||
ThreadStatus status;
|
ThreadStatus status;
|
||||||
Handle handle; // OS handle for this thread
|
HandleType handle; // OS handle for this thread
|
||||||
int index; // Index of the thread. 0 for the first thread, 1 for the second, and so on
|
int index; // Index of the thread. 0 for the first thread, 1 for the second, and so on
|
||||||
|
|
||||||
// The waiting address for threads that are waiting on an AddressArbiter
|
// The waiting address for threads that are waiting on an AddressArbiter
|
||||||
u32 waitingAddress;
|
u32 waitingAddress;
|
||||||
|
|
||||||
// For WaitSynchronization(N): A vector of objects this thread is waiting for
|
// For WaitSynchronization(N): A vector of objects this thread is waiting for
|
||||||
std::vector<Handle> waitList;
|
std::vector<HandleType> waitList;
|
||||||
// For WaitSynchronizationN: Shows whether the object should wait for all objects in the wait list or just one
|
// For WaitSynchronizationN: Shows whether the object should wait for all objects in the wait list or just one
|
||||||
bool waitAll;
|
bool waitAll;
|
||||||
// For WaitSynchronizationN: The "out" pointer
|
// For WaitSynchronizationN: The "out" pointer
|
||||||
|
@ -141,88 +145,86 @@ struct Thread {
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char* kernelObjectTypeToString(KernelObjectType t) {
|
static const char* kernelObjectTypeToString(KernelObjectType t) {
|
||||||
switch (t) {
|
switch (t) {
|
||||||
case KernelObjectType::AddressArbiter: return "address arbiter";
|
case KernelObjectType::AddressArbiter: return "address arbiter";
|
||||||
case KernelObjectType::Archive: return "archive";
|
case KernelObjectType::Archive: return "archive";
|
||||||
case KernelObjectType::Directory: return "directory";
|
case KernelObjectType::Directory: return "directory";
|
||||||
case KernelObjectType::Event: return "event";
|
case KernelObjectType::Event: return "event";
|
||||||
case KernelObjectType::File: return "file";
|
case KernelObjectType::File: return "file";
|
||||||
case KernelObjectType::MemoryBlock: return "memory block";
|
case KernelObjectType::MemoryBlock: return "memory block";
|
||||||
case KernelObjectType::Port: return "port";
|
case KernelObjectType::Port: return "port";
|
||||||
case KernelObjectType::Process: return "process";
|
case KernelObjectType::Process: return "process";
|
||||||
case KernelObjectType::ResourceLimit: return "resource limit";
|
case KernelObjectType::ResourceLimit: return "resource limit";
|
||||||
case KernelObjectType::Session: return "session";
|
case KernelObjectType::Session: return "session";
|
||||||
case KernelObjectType::Mutex: return "mutex";
|
case KernelObjectType::Mutex: return "mutex";
|
||||||
case KernelObjectType::Semaphore: return "semaphore";
|
case KernelObjectType::Semaphore: return "semaphore";
|
||||||
case KernelObjectType::Thread: return "thread";
|
case KernelObjectType::Thread: return "thread";
|
||||||
case KernelObjectType::Dummy: return "dummy";
|
case KernelObjectType::Dummy: return "dummy";
|
||||||
default: return "unknown";
|
default: return "unknown";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Mutex {
|
struct Mutex {
|
||||||
u64 waitlist; // Refer to the getWaitlist function below for documentation
|
u64 waitlist; // Refer to the getWaitlist function below for documentation
|
||||||
Handle ownerThread = 0; // Index of the thread that holds the mutex if it's locked
|
HandleType ownerThread = 0; // Index of the thread that holds the mutex if it's locked
|
||||||
Handle handle; // Handle of the mutex itself
|
HandleType handle; // HandleType of the mutex itself
|
||||||
u32 lockCount; // Number of times this mutex has been locked by its daddy. 0 = not locked
|
u32 lockCount; // Number of times this mutex has been locked by its daddy. 0 = not locked
|
||||||
bool locked;
|
bool locked;
|
||||||
|
|
||||||
Mutex(bool lock, Handle handle) : locked(lock), waitlist(0), lockCount(lock ? 1 : 0), handle(handle) {}
|
Mutex(bool lock, HandleType handle) : locked(lock), waitlist(0), lockCount(lock ? 1 : 0), handle(handle) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Semaphore {
|
struct Semaphore {
|
||||||
u64 waitlist; // Refer to the getWaitlist function below for documentation
|
u64 waitlist; // Refer to the getWaitlist function below for documentation
|
||||||
s32 availableCount;
|
s32 availableCount;
|
||||||
s32 maximumCount;
|
s32 maximumCount;
|
||||||
|
|
||||||
Semaphore(s32 initialCount, s32 maximumCount) : availableCount(initialCount), maximumCount(maximumCount), waitlist(0) {}
|
Semaphore(s32 initialCount, s32 maximumCount) : availableCount(initialCount), maximumCount(maximumCount), waitlist(0) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Timer {
|
struct Timer {
|
||||||
u64 waitlist; // Refer to the getWaitlist function below for documentation
|
u64 waitlist; // Refer to the getWaitlist function below for documentation
|
||||||
ResetType resetType = ResetType::OneShot;
|
ResetType resetType = ResetType::OneShot;
|
||||||
|
|
||||||
u64 fireTick; // CPU tick the timer will be fired
|
u64 fireTick; // CPU tick the timer will be fired
|
||||||
u64 interval; // Number of ns until the timer fires for the second and future times
|
u64 interval; // Number of ns until the timer fires for the second and future times
|
||||||
bool fired; // Has this timer been signalled?
|
bool fired; // Has this timer been signalled?
|
||||||
bool running; // Is this timer running or stopped?
|
bool running; // Is this timer running or stopped?
|
||||||
|
|
||||||
Timer(ResetType type) : resetType(type), fireTick(0), interval(0), waitlist(0), fired(false), running(false) {}
|
Timer(ResetType type) : resetType(type), fireTick(0), interval(0), waitlist(0), fired(false), running(false) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MemoryBlock {
|
struct MemoryBlock {
|
||||||
u32 addr = 0;
|
u32 addr = 0;
|
||||||
u32 size = 0;
|
u32 size = 0;
|
||||||
u32 myPermission = 0;
|
u32 myPermission = 0;
|
||||||
u32 otherPermission = 0;
|
u32 otherPermission = 0;
|
||||||
bool mapped = false;
|
bool mapped = false;
|
||||||
|
|
||||||
MemoryBlock(u32 addr, u32 size, u32 myPerm, u32 otherPerm) : addr(addr), size(size), myPermission(myPerm), otherPermission(otherPerm),
|
MemoryBlock(u32 addr, u32 size, u32 myPerm, u32 otherPerm)
|
||||||
mapped(false) {}
|
: addr(addr), size(size), myPermission(myPerm), otherPermission(otherPerm), mapped(false) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Generic kernel object class
|
// Generic kernel object class
|
||||||
struct KernelObject {
|
struct KernelObject {
|
||||||
Handle handle = 0; // A u32 the OS will use to identify objects
|
HandleType handle = 0; // A u32 the OS will use to identify objects
|
||||||
void* data = nullptr;
|
void* data = nullptr;
|
||||||
KernelObjectType type;
|
KernelObjectType type;
|
||||||
|
|
||||||
KernelObject(Handle handle, KernelObjectType type) : handle(handle), type(type) {}
|
KernelObject(HandleType handle, KernelObjectType type) : handle(handle), type(type) {}
|
||||||
|
|
||||||
// Our destructor does not free the data in order to avoid it being freed when our std::vector is expanded
|
// Our destructor does not free the data in order to avoid it being freed when our std::vector is expanded
|
||||||
// Thus, the kernel needs to delete it when appropriate
|
// Thus, the kernel needs to delete it when appropriate
|
||||||
~KernelObject() {}
|
~KernelObject() {}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T* getData() {
|
T* getData() {
|
||||||
return static_cast<T*>(data);
|
return static_cast<T*>(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* getTypeName() const {
|
const char* getTypeName() const { return kernelObjectTypeToString(type); }
|
||||||
return kernelObjectTypeToString(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieves a reference to the waitlist for a specified object
|
// Retrieves a reference to the waitlist for a specified object
|
||||||
// We return a reference because this function is only called in the kernel threading internals
|
// We return a reference because this function is only called in the kernel threading internals
|
||||||
// We want the kernel to be able to easily manage waitlists, by reading/parsing them or setting/clearing bits.
|
// We want the kernel to be able to easily manage waitlists, by reading/parsing them or setting/clearing bits.
|
||||||
// As we mention in the definition of the "Event" struct, the format for wailists is very simple and made to be efficient.
|
// As we mention in the definition of the "Event" struct, the format for wailists is very simple and made to be efficient.
|
||||||
|
@ -238,8 +240,7 @@ struct KernelObject {
|
||||||
case KernelObjectType::Timer: return getData<Timer>()->waitlist;
|
case KernelObjectType::Timer: return getData<Timer>()->waitlist;
|
||||||
|
|
||||||
// This should be unreachable once we fully implement sync objects
|
// This should be unreachable once we fully implement sync objects
|
||||||
default: [[unlikely]]
|
default: [[unlikely]] Helpers::panic("Called GetWaitList on kernel object without a waitlist (Type: %s)", getTypeName());
|
||||||
Helpers::panic("Called GetWaitList on kernel object without a waitlist (Type: %s)", getTypeName());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
#include "crypto/aes_engine.hpp"
|
#include "crypto/aes_engine.hpp"
|
||||||
#include "handles.hpp"
|
#include "handles.hpp"
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
#include "loader/ncsd.hpp"
|
|
||||||
#include "loader/3dsx.hpp"
|
#include "loader/3dsx.hpp"
|
||||||
|
#include "loader/ncsd.hpp"
|
||||||
#include "services/region_codes.hpp"
|
#include "services/region_codes.hpp"
|
||||||
|
|
||||||
namespace PhysicalAddrs {
|
namespace PhysicalAddrs {
|
||||||
|
@ -38,7 +38,7 @@ namespace VirtualAddrs {
|
||||||
DefaultStackSize = 0x4000,
|
DefaultStackSize = 0x4000,
|
||||||
|
|
||||||
NormalHeapStart = 0x08000000,
|
NormalHeapStart = 0x08000000,
|
||||||
LinearHeapStartOld = 0x14000000, // If kernel version < 0x22C
|
LinearHeapStartOld = 0x14000000, // If kernel version < 0x22C
|
||||||
LinearHeapEndOld = 0x1C000000,
|
LinearHeapEndOld = 0x1C000000,
|
||||||
|
|
||||||
LinearHeapStartNew = 0x30000000,
|
LinearHeapStartNew = 0x30000000,
|
||||||
|
@ -76,37 +76,36 @@ namespace KernelMemoryTypes {
|
||||||
PERMISSION_W = 1 << 1,
|
PERMISSION_W = 1 << 1,
|
||||||
PERMISSION_X = 1 << 2
|
PERMISSION_X = 1 << 2
|
||||||
};
|
};
|
||||||
|
|
||||||
// I assume this is referring to a single piece of allocated memory? If it's for pages, it makes no sense.
|
// I assume this is referring to a single piece of allocated memory? If it's for pages, it makes no sense.
|
||||||
// If it's for multiple allocations, it also makes no sense
|
// If it's for multiple allocations, it also makes no sense
|
||||||
struct MemoryInfo {
|
struct MemoryInfo {
|
||||||
u32 baseAddr; // Base process virtual address. Used as a paddr in lockedMemoryInfo instead
|
u32 baseAddr; // Base process virtual address. Used as a paddr in lockedMemoryInfo instead
|
||||||
u32 size; // Of what?
|
u32 size; // Of what?
|
||||||
u32 perms; // Is this referring to a single page or?
|
u32 perms; // Is this referring to a single page or?
|
||||||
u32 state;
|
u32 state;
|
||||||
|
|
||||||
u32 end() { return baseAddr + size; }
|
u32 end() { return baseAddr + size; }
|
||||||
MemoryInfo(u32 baseAddr, u32 size, u32 perms, u32 state) : baseAddr(baseAddr), size(size)
|
MemoryInfo(u32 baseAddr, u32 size, u32 perms, u32 state) : baseAddr(baseAddr), size(size), perms(perms), state(state) {}
|
||||||
, perms(perms), state(state) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Shared memory block for HID, GSP:GPU etc
|
// Shared memory block for HID, GSP:GPU etc
|
||||||
struct SharedMemoryBlock {
|
struct SharedMemoryBlock {
|
||||||
u32 paddr; // Physical address of this block's memory
|
u32 paddr; // Physical address of this block's memory
|
||||||
u32 size; // Size of block
|
u32 size; // Size of block
|
||||||
u32 handle; // The handle of the shared memory block
|
u32 handle; // The handle of the shared memory block
|
||||||
bool mapped; // Has this block been mapped at least once?
|
bool mapped; // Has this block been mapped at least once?
|
||||||
|
|
||||||
SharedMemoryBlock(u32 paddr, u32 size, u32 handle) : paddr(paddr), size(size), handle(handle), mapped(false) {}
|
SharedMemoryBlock(u32 paddr, u32 size, u32 handle) : paddr(paddr), size(size), handle(handle), mapped(false) {}
|
||||||
};
|
};
|
||||||
}
|
} // namespace KernelMemoryTypes
|
||||||
|
|
||||||
class Memory {
|
class Memory {
|
||||||
u8* fcram;
|
u8* fcram;
|
||||||
u8* dspRam; // Provided to us by Audio
|
u8* dspRam; // Provided to us by Audio
|
||||||
u8* vram; // Provided to the memory class by the GPU class
|
u8* vram; // Provided to the memory class by the GPU class
|
||||||
|
|
||||||
u64& cpuTicks; // Reference to the CPU tick counter
|
u64& cpuTicks; // Reference to the CPU tick counter
|
||||||
using SharedMemoryBlock = KernelMemoryTypes::SharedMemoryBlock;
|
using SharedMemoryBlock = KernelMemoryTypes::SharedMemoryBlock;
|
||||||
|
|
||||||
// Our dynarmic core uses page tables for reads and writes with 4096 byte pages
|
// Our dynarmic core uses page tables for reads and writes with 4096 byte pages
|
||||||
|
@ -116,19 +115,21 @@ class Memory {
|
||||||
std::vector<KernelMemoryTypes::MemoryInfo> memoryInfo;
|
std::vector<KernelMemoryTypes::MemoryInfo> memoryInfo;
|
||||||
|
|
||||||
std::array<SharedMemoryBlock, 5> sharedMemBlocks = {
|
std::array<SharedMemoryBlock, 5> sharedMemBlocks = {
|
||||||
SharedMemoryBlock(0, 0, KernelHandles::FontSharedMemHandle), // Shared memory for the system font (size is 0 because we read the size from the cmrc filesystem
|
SharedMemoryBlock(
|
||||||
SharedMemoryBlock(0, 0x1000, KernelHandles::GSPSharedMemHandle), // GSP shared memory
|
0, 0, KernelHandles::FontSharedMemHandle
|
||||||
SharedMemoryBlock(0, 0x1000, KernelHandles::HIDSharedMemHandle), // HID shared memory
|
), // Shared memory for the system font (size is 0 because we read the size from the cmrc filesystem
|
||||||
SharedMemoryBlock(0, 0x3000, KernelHandles::CSNDSharedMemHandle), // CSND shared memory
|
SharedMemoryBlock(0, 0x1000, KernelHandles::GSPSharedMemHandle), // GSP shared memory
|
||||||
|
SharedMemoryBlock(0, 0x1000, KernelHandles::HIDSharedMemHandle), // HID shared memory
|
||||||
|
SharedMemoryBlock(0, 0x3000, KernelHandles::CSNDSharedMemHandle), // CSND shared memory
|
||||||
SharedMemoryBlock(0, 0xE7000, KernelHandles::APTCaptureSharedMemHandle), // APT Capture Buffer memory
|
SharedMemoryBlock(0, 0xE7000, KernelHandles::APTCaptureSharedMemHandle), // APT Capture Buffer memory
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static constexpr u32 pageShift = 12;
|
static constexpr u32 pageShift = 12;
|
||||||
static constexpr u32 pageSize = 1 << pageShift;
|
static constexpr u32 pageSize = 1 << pageShift;
|
||||||
static constexpr u32 pageMask = pageSize - 1;
|
static constexpr u32 pageMask = pageSize - 1;
|
||||||
static constexpr u32 totalPageCount = 1 << (32 - pageShift);
|
static constexpr u32 totalPageCount = 1 << (32 - pageShift);
|
||||||
|
|
||||||
static constexpr u32 FCRAM_SIZE = u32(128_MB);
|
static constexpr u32 FCRAM_SIZE = u32(128_MB);
|
||||||
static constexpr u32 FCRAM_APPLICATION_SIZE = u32(64_MB);
|
static constexpr u32 FCRAM_APPLICATION_SIZE = u32(64_MB);
|
||||||
static constexpr u32 FCRAM_PAGE_COUNT = FCRAM_SIZE / pageSize;
|
static constexpr u32 FCRAM_PAGE_COUNT = FCRAM_SIZE / pageSize;
|
||||||
|
@ -138,7 +139,7 @@ public:
|
||||||
static constexpr u32 DSP_CODE_MEMORY_OFFSET = u32(0_KB);
|
static constexpr u32 DSP_CODE_MEMORY_OFFSET = u32(0_KB);
|
||||||
static constexpr u32 DSP_DATA_MEMORY_OFFSET = u32(256_KB);
|
static constexpr u32 DSP_DATA_MEMORY_OFFSET = u32(256_KB);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::bitset<FCRAM_PAGE_COUNT> usedFCRAMPages;
|
std::bitset<FCRAM_PAGE_COUNT> usedFCRAMPages;
|
||||||
std::optional<u32> findPaddr(u32 size);
|
std::optional<u32> findPaddr(u32 size);
|
||||||
u64 timeSince3DSEpoch();
|
u64 timeSince3DSEpoch();
|
||||||
|
@ -147,9 +148,9 @@ private:
|
||||||
// Report a retail unit without JTAG
|
// Report a retail unit without JTAG
|
||||||
static constexpr u32 envInfo = 1;
|
static constexpr u32 envInfo = 1;
|
||||||
|
|
||||||
// Stored in Configuration Memory starting @ 0x1FF80060
|
// Stored in Configuration Memory starting @ 0x1FF80060
|
||||||
struct FirmwareInfo {
|
struct FirmwareInfo {
|
||||||
u8 unk; // Usually 0 according to 3DBrew
|
u8 unk; // Usually 0 according to 3DBrew
|
||||||
u8 revision;
|
u8 revision;
|
||||||
u8 minor;
|
u8 minor;
|
||||||
u8 major;
|
u8 major;
|
||||||
|
@ -167,8 +168,8 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
u16 kernelVersion = 0;
|
u16 kernelVersion = 0;
|
||||||
u32 usedUserMemory = u32(0_MB); // How much of the APPLICATION FCRAM range is used (allocated to the appcore)
|
u32 usedUserMemory = u32(0_MB); // How much of the APPLICATION FCRAM range is used (allocated to the appcore)
|
||||||
u32 usedSystemMemory = u32(0_MB); // Similar for the SYSTEM range (reserved for the syscore)
|
u32 usedSystemMemory = u32(0_MB); // Similar for the SYSTEM range (reserved for the syscore)
|
||||||
|
|
||||||
Memory(u64& cpuTicks, const EmulatorConfig& config);
|
Memory(u64& cpuTicks, const EmulatorConfig& config);
|
||||||
void reset();
|
void reset();
|
||||||
|
@ -197,28 +198,20 @@ private:
|
||||||
u8* getFCRAM() { return fcram; }
|
u8* getFCRAM() { return fcram; }
|
||||||
|
|
||||||
// Total amount of OS-only FCRAM available (Can vary depending on how much FCRAM the app requests via the cart exheader)
|
// Total amount of OS-only FCRAM available (Can vary depending on how much FCRAM the app requests via the cart exheader)
|
||||||
u32 totalSysFCRAM() {
|
u32 totalSysFCRAM() { return FCRAM_SIZE - FCRAM_APPLICATION_SIZE; }
|
||||||
return FCRAM_SIZE - FCRAM_APPLICATION_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Amount of OS-only FCRAM currently available
|
// Amount of OS-only FCRAM currently available
|
||||||
u32 remainingSysFCRAM() {
|
u32 remainingSysFCRAM() { return totalSysFCRAM() - usedSystemMemory; }
|
||||||
return totalSysFCRAM() - usedSystemMemory;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Physical FCRAM index to the start of OS FCRAM
|
// Physical FCRAM index to the start of OS FCRAM
|
||||||
// We allocate the first part of physical FCRAM for the application, and the rest to the OS. So the index for the OS = application ram size
|
// We allocate the first part of physical FCRAM for the application, and the rest to the OS. So the index for the OS = application ram size
|
||||||
u32 sysFCRAMIndex() {
|
u32 sysFCRAMIndex() { return FCRAM_APPLICATION_SIZE; }
|
||||||
return FCRAM_APPLICATION_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class BatteryLevel {
|
enum class BatteryLevel { Empty = 0, AlmostEmpty, OneBar, TwoBars, ThreeBars, FourBars };
|
||||||
Empty = 0, AlmostEmpty, OneBar, TwoBars, ThreeBars, FourBars
|
|
||||||
};
|
|
||||||
u8 getBatteryState(bool adapterConnected, bool charging, BatteryLevel batteryLevel) {
|
u8 getBatteryState(bool adapterConnected, bool charging, BatteryLevel batteryLevel) {
|
||||||
u8 value = static_cast<u8>(batteryLevel) << 2; // Bits 2:4 are the battery level from 0 to 5
|
u8 value = static_cast<u8>(batteryLevel) << 2; // Bits 2:4 are the battery level from 0 to 5
|
||||||
if (adapterConnected) value |= 1 << 0; // Bit 0 shows if the charger is connected
|
if (adapterConnected) value |= 1 << 0; // Bit 0 shows if the charger is connected
|
||||||
if (charging) value |= 1 << 1; // Bit 1 shows if we're charging
|
if (charging) value |= 1 << 1; // Bit 1 shows if we're charging
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
@ -240,9 +233,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns whether "addr" is aligned to a page (4096 byte) boundary
|
// Returns whether "addr" is aligned to a page (4096 byte) boundary
|
||||||
static constexpr bool isAligned(u32 addr) {
|
static constexpr bool isAligned(u32 addr) { return (addr & pageMask) == 0; }
|
||||||
return (addr & pageMask) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate "size" bytes of RAM starting from FCRAM index "paddr" (We pick it ourself if paddr == 0)
|
// Allocate "size" bytes of RAM starting from FCRAM index "paddr" (We pick it ourself if paddr == 0)
|
||||||
// And map them to virtual address "vaddr" (We also pick it ourself if vaddr == 0).
|
// And map them to virtual address "vaddr" (We also pick it ourself if vaddr == 0).
|
||||||
|
@ -253,8 +244,9 @@ private:
|
||||||
// isMap: Shows whether this is a reserve operation, that allocates memory and maps it to the addr space, or if it's a map operation,
|
// isMap: Shows whether this is a reserve operation, that allocates memory and maps it to the addr space, or if it's a map operation,
|
||||||
// which just maps memory from paddr to vaddr without hassle. The latter is useful for shared memory mapping, the "map" ControlMemory, op, etc
|
// which just maps memory from paddr to vaddr without hassle. The latter is useful for shared memory mapping, the "map" ControlMemory, op, etc
|
||||||
// Returns the vaddr the FCRAM was mapped to or nullopt if allocation failed
|
// Returns the vaddr the FCRAM was mapped to or nullopt if allocation failed
|
||||||
std::optional<u32> allocateMemory(u32 vaddr, u32 paddr, u32 size, bool linear, bool r = true, bool w = true, bool x = true,
|
std::optional<u32> allocateMemory(
|
||||||
bool adjustsAddrs = false, bool isMap = false);
|
u32 vaddr, u32 paddr, u32 size, bool linear, bool r = true, bool w = true, bool x = true, bool adjustsAddrs = false, bool isMap = false
|
||||||
|
);
|
||||||
KernelMemoryTypes::MemoryInfo queryMemory(u32 vaddr);
|
KernelMemoryTypes::MemoryInfo queryMemory(u32 vaddr);
|
||||||
|
|
||||||
// For internal use
|
// For internal use
|
||||||
|
@ -266,7 +258,7 @@ private:
|
||||||
// The kernel has a second permission parameter in MapMemoryBlock but not sure what's used for
|
// The kernel has a second permission parameter in MapMemoryBlock but not sure what's used for
|
||||||
// TODO: Find out
|
// TODO: Find out
|
||||||
// Returns a pointer to the FCRAM block used for the memory if allocation succeeded
|
// Returns a pointer to the FCRAM block used for the memory if allocation succeeded
|
||||||
u8* mapSharedMemory(Handle handle, u32 vaddr, u32 myPerms, u32 otherPerms);
|
u8* mapSharedMemory(HandleType handle, u32 vaddr, u32 myPerms, u32 otherPerms);
|
||||||
|
|
||||||
// Mirrors the page mapping for "size" bytes starting from sourceAddress, to "size" bytes in destAddress
|
// Mirrors the page mapping for "size" bytes starting from sourceAddress, to "size" bytes in destAddress
|
||||||
// All of the above must be page-aligned.
|
// All of the above must be page-aligned.
|
||||||
|
|
|
@ -119,9 +119,10 @@ class MainWindow : public QMainWindow {
|
||||||
void sendMessage(const EmulatorMessage& message);
|
void sendMessage(const EmulatorMessage& message);
|
||||||
void dispatchMessage(const EmulatorMessage& message);
|
void dispatchMessage(const EmulatorMessage& message);
|
||||||
|
|
||||||
// Tracks whether we are using an OpenGL-backed renderer or a Vulkan-backed renderer
|
// Tracks whether we are using an OpenGL-backed renderer, a Vulkan-backed renderer or a Metal-backed renderer
|
||||||
bool usingGL = false;
|
bool usingGL = false;
|
||||||
bool usingVk = false;
|
bool usingVk = false;
|
||||||
|
bool usingMtl = false;
|
||||||
|
|
||||||
// Variables to keep track of whether the user is controlling the 3DS analog stick with their keyboard
|
// Variables to keep track of whether the user is controlling the 3DS analog stick with their keyboard
|
||||||
// This is done so when a gamepad is connected, we won't automatically override the 3DS analog stick settings with the gamepad's state
|
// This is done so when a gamepad is connected, we won't automatically override the 3DS analog stick settings with the gamepad's state
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <span>
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
#include "PICA/pica_vertex.hpp"
|
#include "PICA/pica_vertex.hpp"
|
||||||
#include "PICA/regs.hpp"
|
#include "PICA/regs.hpp"
|
||||||
|
@ -17,6 +17,7 @@ enum class RendererType : s8 {
|
||||||
OpenGL = 1,
|
OpenGL = 1,
|
||||||
Vulkan = 2,
|
Vulkan = 2,
|
||||||
Software = 3,
|
Software = 3,
|
||||||
|
Metal = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
class GPU;
|
class GPU;
|
||||||
|
|
32
include/renderer_mtl/renderer_mtl.hpp
Normal file
32
include/renderer_mtl/renderer_mtl.hpp
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#include <Metal/Metal.hpp>
|
||||||
|
#include <QuartzCore/QuartzCore.hpp>
|
||||||
|
|
||||||
|
#include "renderer.hpp"
|
||||||
|
|
||||||
|
class GPU;
|
||||||
|
|
||||||
|
class RendererMTL final : public Renderer {
|
||||||
|
public:
|
||||||
|
RendererMTL(GPU& gpu, const std::array<u32, regNum>& internalRegs, const std::array<u32, extRegNum>& externalRegs);
|
||||||
|
~RendererMTL() override;
|
||||||
|
|
||||||
|
void reset() override;
|
||||||
|
void display() override;
|
||||||
|
void initGraphicsContext(SDL_Window* window) override;
|
||||||
|
void clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control) override;
|
||||||
|
void displayTransfer(u32 inputAddr, u32 outputAddr, u32 inputSize, u32 outputSize, u32 flags) override;
|
||||||
|
void textureCopy(u32 inputAddr, u32 outputAddr, u32 totalBytes, u32 inputSize, u32 outputSize, u32 flags) override;
|
||||||
|
void drawVertices(PICA::PrimType primType, std::span<const PICA::Vertex> vertices) override;
|
||||||
|
void screenshot(const std::string& name) override;
|
||||||
|
void deinitGraphicsContext() override;
|
||||||
|
|
||||||
|
#ifdef PANDA3DS_FRONTEND_QT
|
||||||
|
virtual void initGraphicsContext([[maybe_unused]] GL::Context* context) override {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
CA::MetalLayer* metalLayer;
|
||||||
|
|
||||||
|
MTL::Device* device;
|
||||||
|
MTL::CommandQueue* commandQueue;
|
||||||
|
};
|
|
@ -8,7 +8,7 @@
|
||||||
#include "result/result.hpp"
|
#include "result/result.hpp"
|
||||||
|
|
||||||
class ACService {
|
class ACService {
|
||||||
Handle handle = KernelHandles::AC;
|
HandleType handle = KernelHandles::AC;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
MAKE_LOG_FUNCTION(log, acLogger)
|
MAKE_LOG_FUNCTION(log, acLogger)
|
||||||
|
|
||||||
|
@ -25,10 +25,10 @@ class ACService {
|
||||||
void setClientVersion(u32 messagePointer);
|
void setClientVersion(u32 messagePointer);
|
||||||
|
|
||||||
bool connected = false;
|
bool connected = false;
|
||||||
std::optional<Handle> disconnectEvent = std::nullopt;
|
std::optional<HandleType> disconnectEvent = std::nullopt;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ACService(Memory& mem) : mem(mem) {}
|
ACService(Memory& mem) : mem(mem) {}
|
||||||
void reset();
|
void reset();
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include "result/result.hpp"
|
#include "result/result.hpp"
|
||||||
|
|
||||||
class ACTService {
|
class ACTService {
|
||||||
Handle handle = KernelHandles::ACT;
|
HandleType handle = KernelHandles::ACT;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
MAKE_LOG_FUNCTION(log, actLogger)
|
MAKE_LOG_FUNCTION(log, actLogger)
|
||||||
|
|
||||||
|
@ -15,8 +15,8 @@ class ACTService {
|
||||||
void generateUUID(u32 messagePointer);
|
void generateUUID(u32 messagePointer);
|
||||||
void getAccountDataBlock(u32 messagePointer);
|
void getAccountDataBlock(u32 messagePointer);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ACTService(Memory& mem) : mem(mem) {}
|
ACTService(Memory& mem) : mem(mem) {}
|
||||||
void reset();
|
void reset();
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include "result/result.hpp"
|
#include "result/result.hpp"
|
||||||
|
|
||||||
class AMService {
|
class AMService {
|
||||||
Handle handle = KernelHandles::AM;
|
HandleType handle = KernelHandles::AM;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
MAKE_LOG_FUNCTION(log, amLogger)
|
MAKE_LOG_FUNCTION(log, amLogger)
|
||||||
|
|
||||||
|
@ -15,8 +15,8 @@ class AMService {
|
||||||
void getPatchTitleInfo(u32 messagePointer);
|
void getPatchTitleInfo(u32 messagePointer);
|
||||||
void listTitleInfo(u32 messagePointer);
|
void listTitleInfo(u32 messagePointer);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AMService(Memory& mem) : mem(mem) {}
|
AMService(Memory& mem) : mem(mem) {}
|
||||||
void reset();
|
void reset();
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,19 +1,17 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
|
#include "applets/applet_manager.hpp"
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
#include "kernel_types.hpp"
|
#include "kernel_types.hpp"
|
||||||
#include "logger.hpp"
|
#include "logger.hpp"
|
||||||
#include "memory.hpp"
|
#include "memory.hpp"
|
||||||
#include "result/result.hpp"
|
#include "result/result.hpp"
|
||||||
|
|
||||||
#include "applets/applet_manager.hpp"
|
|
||||||
|
|
||||||
// Yay, more circular dependencies
|
// Yay, more circular dependencies
|
||||||
class Kernel;
|
class Kernel;
|
||||||
|
|
||||||
enum class ConsoleModel : u32 {
|
enum class ConsoleModel : u32 { Old3DS, New3DS };
|
||||||
Old3DS, New3DS
|
|
||||||
};
|
|
||||||
|
|
||||||
// https://www.3dbrew.org/wiki/NS_and_APT_Services#Command
|
// https://www.3dbrew.org/wiki/NS_and_APT_Services#Command
|
||||||
namespace APT::Transitions {
|
namespace APT::Transitions {
|
||||||
|
@ -41,13 +39,13 @@ namespace APT::Transitions {
|
||||||
}
|
}
|
||||||
|
|
||||||
class APTService {
|
class APTService {
|
||||||
Handle handle = KernelHandles::APT;
|
HandleType handle = KernelHandles::APT;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
Kernel& kernel;
|
Kernel& kernel;
|
||||||
|
|
||||||
std::optional<Handle> lockHandle = std::nullopt;
|
std::optional<HandleType> lockHandle = std::nullopt;
|
||||||
std::optional<Handle> notificationEvent = std::nullopt;
|
std::optional<HandleType> notificationEvent = std::nullopt;
|
||||||
std::optional<Handle> resumeEvent = std::nullopt;
|
std::optional<HandleType> resumeEvent = std::nullopt;
|
||||||
|
|
||||||
ConsoleModel model = ConsoleModel::Old3DS;
|
ConsoleModel model = ConsoleModel::Old3DS;
|
||||||
Applets::AppletManager appletManager;
|
Applets::AppletManager appletManager;
|
||||||
|
@ -99,8 +97,8 @@ class APTService {
|
||||||
|
|
||||||
u32 screencapPostPermission;
|
u32 screencapPostPermission;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
APTService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel), appletManager(mem) {}
|
APTService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel), appletManager(mem) {}
|
||||||
void reset();
|
void reset();
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include "result/result.hpp"
|
#include "result/result.hpp"
|
||||||
|
|
||||||
class BOSSService {
|
class BOSSService {
|
||||||
Handle handle = KernelHandles::BOSS;
|
HandleType handle = KernelHandles::BOSS;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
MAKE_LOG_FUNCTION(log, bossLogger)
|
MAKE_LOG_FUNCTION(log, bossLogger)
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ class BOSSService {
|
||||||
void getNewArrivalFlag(u32 messagePointer);
|
void getNewArrivalFlag(u32 messagePointer);
|
||||||
void getNsDataIdList(u32 messagePointer, u32 commandWord);
|
void getNsDataIdList(u32 messagePointer, u32 commandWord);
|
||||||
void getOptoutFlag(u32 messagePointer);
|
void getOptoutFlag(u32 messagePointer);
|
||||||
void getStorageEntryInfo(u32 messagePointer); // Unknown what this is, name taken from Citra
|
void getStorageEntryInfo(u32 messagePointer); // Unknown what this is, name taken from Citra
|
||||||
void getTaskIdList(u32 messagePointer);
|
void getTaskIdList(u32 messagePointer);
|
||||||
void getTaskInfo(u32 messagePointer);
|
void getTaskInfo(u32 messagePointer);
|
||||||
void getTaskServiceStatus(u32 messagePointer);
|
void getTaskServiceStatus(u32 messagePointer);
|
||||||
|
@ -35,8 +35,9 @@ class BOSSService {
|
||||||
void unregisterTask(u32 messagePointer);
|
void unregisterTask(u32 messagePointer);
|
||||||
|
|
||||||
s8 optoutFlag;
|
s8 optoutFlag;
|
||||||
public:
|
|
||||||
|
public:
|
||||||
BOSSService(Memory& mem) : mem(mem) {}
|
BOSSService(Memory& mem) : mem(mem) {}
|
||||||
void reset();
|
void reset();
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
class Kernel;
|
class Kernel;
|
||||||
|
|
||||||
class CAMService {
|
class CAMService {
|
||||||
using Event = std::optional<Handle>;
|
using Event = std::optional<HandleType>;
|
||||||
|
|
||||||
struct Port {
|
struct Port {
|
||||||
Event bufferErrorInterruptEvent = std::nullopt;
|
Event bufferErrorInterruptEvent = std::nullopt;
|
||||||
|
@ -26,7 +26,7 @@ class CAMService {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Handle handle = KernelHandles::CAM;
|
HandleType handle = KernelHandles::CAM;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
Kernel& kernel;
|
Kernel& kernel;
|
||||||
MAKE_LOG_FUNCTION(log, camLogger)
|
MAKE_LOG_FUNCTION(log, camLogger)
|
||||||
|
@ -56,4 +56,4 @@ class CAMService {
|
||||||
CAMService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
|
CAMService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
|
||||||
void reset();
|
void reset();
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
#include "kernel_types.hpp"
|
#include "kernel_types.hpp"
|
||||||
#include "logger.hpp"
|
#include "logger.hpp"
|
||||||
|
@ -9,19 +10,19 @@
|
||||||
class Kernel;
|
class Kernel;
|
||||||
|
|
||||||
class CECDService {
|
class CECDService {
|
||||||
Handle handle = KernelHandles::CECD;
|
HandleType handle = KernelHandles::CECD;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
Kernel& kernel;
|
Kernel& kernel;
|
||||||
MAKE_LOG_FUNCTION(log, cecdLogger)
|
MAKE_LOG_FUNCTION(log, cecdLogger)
|
||||||
|
|
||||||
std::optional<Handle> infoEvent;
|
std::optional<HandleType> infoEvent;
|
||||||
|
|
||||||
// Service commands
|
// Service commands
|
||||||
void getInfoEventHandle(u32 messagePointer);
|
void getInfoEventHandle(u32 messagePointer);
|
||||||
void openAndRead(u32 messagePointer);
|
void openAndRead(u32 messagePointer);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CECDService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
|
CECDService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
|
||||||
void reset();
|
void reset();
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,13 +10,13 @@
|
||||||
class Kernel;
|
class Kernel;
|
||||||
|
|
||||||
class CSNDService {
|
class CSNDService {
|
||||||
Handle handle = KernelHandles::CSND;
|
HandleType handle = KernelHandles::CSND;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
Kernel& kernel;
|
Kernel& kernel;
|
||||||
MAKE_LOG_FUNCTION(log, csndLogger)
|
MAKE_LOG_FUNCTION(log, csndLogger)
|
||||||
|
|
||||||
u8* sharedMemory = nullptr;
|
u8* sharedMemory = nullptr;
|
||||||
std::optional<Handle> csndMutex = std::nullopt;
|
std::optional<HandleType> csndMutex = std::nullopt;
|
||||||
size_t sharedMemSize = 0;
|
size_t sharedMemSize = 0;
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
|
|
||||||
|
@ -30,7 +30,5 @@ class CSNDService {
|
||||||
void reset();
|
void reset();
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
|
|
||||||
void setSharedMemory(u8* ptr) {
|
void setSharedMemory(u8* ptr) { sharedMemory = ptr; }
|
||||||
sharedMemory = ptr;
|
};
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
|
@ -8,15 +8,15 @@
|
||||||
// Please forgive me for how everything in this file is named
|
// Please forgive me for how everything in this file is named
|
||||||
// "dlp:SRVR" is not a nice name to work with
|
// "dlp:SRVR" is not a nice name to work with
|
||||||
class DlpSrvrService {
|
class DlpSrvrService {
|
||||||
Handle handle = KernelHandles::DLP_SRVR;
|
HandleType handle = KernelHandles::DLP_SRVR;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
MAKE_LOG_FUNCTION(log, dlpSrvrLogger)
|
MAKE_LOG_FUNCTION(log, dlpSrvrLogger)
|
||||||
|
|
||||||
// Service commands
|
// Service commands
|
||||||
void isChild(u32 messagePointer);
|
void isChild(u32 messagePointer);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DlpSrvrService(Memory& mem) : mem(mem) {}
|
DlpSrvrService(Memory& mem) : mem(mem) {}
|
||||||
void reset();
|
void reset();
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
class Kernel;
|
class Kernel;
|
||||||
|
|
||||||
class DSPService {
|
class DSPService {
|
||||||
Handle handle = KernelHandles::DSP;
|
HandleType handle = KernelHandles::DSP;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
Kernel& kernel;
|
Kernel& kernel;
|
||||||
Audio::DSPCore* dsp = nullptr;
|
Audio::DSPCore* dsp = nullptr;
|
||||||
|
@ -24,7 +24,7 @@ class DSPService {
|
||||||
static constexpr size_t pipeCount = 8;
|
static constexpr size_t pipeCount = 8;
|
||||||
|
|
||||||
// DSP service event handles
|
// DSP service event handles
|
||||||
using DSPEvent = std::optional<Handle>;
|
using DSPEvent = std::optional<HandleType>;
|
||||||
|
|
||||||
DSPEvent semaphoreEvent;
|
DSPEvent semaphoreEvent;
|
||||||
DSPEvent interrupt0;
|
DSPEvent interrupt0;
|
||||||
|
@ -82,4 +82,4 @@ class DSPService {
|
||||||
void triggerInterrupt1();
|
void triggerInterrupt1();
|
||||||
|
|
||||||
ComponentDumpResult dumpComponent(const std::filesystem::path& path);
|
ComponentDumpResult dumpComponent(const std::filesystem::path& path);
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
class Kernel;
|
class Kernel;
|
||||||
|
|
||||||
class FSService {
|
class FSService {
|
||||||
Handle handle = KernelHandles::FS;
|
HandleType handle = KernelHandles::FS;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
Kernel& kernel;
|
Kernel& kernel;
|
||||||
|
|
||||||
|
@ -38,9 +38,9 @@ class FSService {
|
||||||
SystemSaveDataArchive systemSaveData;
|
SystemSaveDataArchive systemSaveData;
|
||||||
|
|
||||||
ArchiveBase* getArchiveFromID(u32 id, const FSPath& archivePath);
|
ArchiveBase* getArchiveFromID(u32 id, const FSPath& archivePath);
|
||||||
Rust::Result<Handle, HorizonResult> openArchiveHandle(u32 archiveID, const FSPath& path);
|
Rust::Result<HandleType, HorizonResult> openArchiveHandle(u32 archiveID, const FSPath& path);
|
||||||
Rust::Result<Handle, HorizonResult> openDirectoryHandle(ArchiveBase* archive, const FSPath& path);
|
Rust::Result<HandleType, HorizonResult> openDirectoryHandle(ArchiveBase* archive, const FSPath& path);
|
||||||
std::optional<Handle> openFileHandle(ArchiveBase* archive, const FSPath& path, const FSPath& archivePath, const FilePerms& perms);
|
std::optional<HandleType> openFileHandle(ArchiveBase* archive, const FSPath& path, const FSPath& archivePath, const FilePerms& perms);
|
||||||
FSPath readPath(u32 type, u32 pointer, u32 size);
|
FSPath readPath(u32 type, u32 pointer, u32 size);
|
||||||
|
|
||||||
const EmulatorConfig& config;
|
const EmulatorConfig& config;
|
||||||
|
@ -81,7 +81,7 @@ class FSService {
|
||||||
// Used for set/get priority: Not sure what sort of priority this is referring to
|
// Used for set/get priority: Not sure what sort of priority this is referring to
|
||||||
u32 priority;
|
u32 priority;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FSService(Memory& mem, Kernel& kernel, const EmulatorConfig& config)
|
FSService(Memory& mem, Kernel& kernel, const EmulatorConfig& config)
|
||||||
: mem(mem), saveData(mem), sharedExtSaveData_nand(mem, "../SharedFiles/NAND", true), extSaveData_sdmc(mem, "SDMC"), sdmc(mem),
|
: mem(mem), saveData(mem), sharedExtSaveData_nand(mem, "../SharedFiles/NAND", true), extSaveData_sdmc(mem, "SDMC"), sdmc(mem),
|
||||||
sdmcWriteOnly(mem, true), selfNcch(mem), ncch(mem), userSaveData1(mem, ArchiveID::UserSaveData1),
|
sdmcWriteOnly(mem, true), selfNcch(mem), ncch(mem), userSaveData1(mem, ArchiveID::UserSaveData1),
|
||||||
|
@ -91,4 +91,4 @@ public:
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
// Creates directories for NAND, ExtSaveData, etc if they don't already exist. Should be executed after loading a new ROM.
|
// Creates directories for NAND, ExtSaveData, etc if they don't already exist. Should be executed after loading a new ROM.
|
||||||
void initializeFilesystem();
|
void initializeFilesystem();
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#include "PICA/gpu.hpp"
|
#include "PICA/gpu.hpp"
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
#include "kernel_types.hpp"
|
#include "kernel_types.hpp"
|
||||||
|
@ -9,12 +10,12 @@
|
||||||
#include "result/result.hpp"
|
#include "result/result.hpp"
|
||||||
|
|
||||||
enum class GPUInterrupt : u8 {
|
enum class GPUInterrupt : u8 {
|
||||||
PSC0 = 0, // Memory fill completed
|
PSC0 = 0, // Memory fill completed
|
||||||
PSC1 = 1, // ?
|
PSC1 = 1, // ?
|
||||||
VBlank0 = 2, // ?
|
VBlank0 = 2, // ?
|
||||||
VBlank1 = 3, // ?
|
VBlank1 = 3, // ?
|
||||||
PPF = 4, // Display transfer finished
|
PPF = 4, // Display transfer finished
|
||||||
P3D = 5, // Command list processing finished
|
P3D = 5, // Command list processing finished
|
||||||
DMA = 6
|
DMA = 6
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,17 +23,17 @@ enum class GPUInterrupt : u8 {
|
||||||
class Kernel;
|
class Kernel;
|
||||||
|
|
||||||
class GPUService {
|
class GPUService {
|
||||||
Handle handle = KernelHandles::GPU;
|
HandleType handle = KernelHandles::GPU;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
GPU& gpu;
|
GPU& gpu;
|
||||||
Kernel& kernel;
|
Kernel& kernel;
|
||||||
u32& currentPID; // Process ID of the current process
|
u32& currentPID; // Process ID of the current process
|
||||||
u8* sharedMem; // Pointer to GSP shared memory
|
u8* sharedMem; // Pointer to GSP shared memory
|
||||||
|
|
||||||
// At any point in time only 1 process has privileges to use rendering functions
|
// At any point in time only 1 process has privileges to use rendering functions
|
||||||
// This is the PID of that process
|
// This is the PID of that process
|
||||||
u32 privilegedProcess;
|
u32 privilegedProcess;
|
||||||
std::optional<Handle> interruptEvent;
|
std::optional<HandleType> interruptEvent;
|
||||||
|
|
||||||
// Number of threads registered via RegisterInterruptRelayQueue
|
// Number of threads registered via RegisterInterruptRelayQueue
|
||||||
u32 gspThreadCount = 0;
|
u32 gspThreadCount = 0;
|
||||||
|
@ -62,8 +63,8 @@ class GPUService {
|
||||||
|
|
||||||
// Used for saving and restoring GPU state via ImportDisplayCaptureInfo
|
// Used for saving and restoring GPU state via ImportDisplayCaptureInfo
|
||||||
struct CaptureInfo {
|
struct CaptureInfo {
|
||||||
u32 leftFramebuffer; // Left framebuffer VA
|
u32 leftFramebuffer; // Left framebuffer VA
|
||||||
u32 rightFramebuffer; // Right framebuffer VA (Top screen only)
|
u32 rightFramebuffer; // Right framebuffer VA (Top screen only)
|
||||||
u32 format;
|
u32 format;
|
||||||
u32 stride;
|
u32 stride;
|
||||||
};
|
};
|
||||||
|
@ -106,15 +107,14 @@ class GPUService {
|
||||||
FramebufferUpdate* getTopFramebufferInfo() { return getFramebufferInfo(0); }
|
FramebufferUpdate* getTopFramebufferInfo() { return getFramebufferInfo(0); }
|
||||||
FramebufferUpdate* getBottomFramebufferInfo() { return getFramebufferInfo(1); }
|
FramebufferUpdate* getBottomFramebufferInfo() { return getFramebufferInfo(1); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GPUService(Memory& mem, GPU& gpu, Kernel& kernel, u32& currentPID) : mem(mem), gpu(gpu),
|
GPUService(Memory& mem, GPU& gpu, Kernel& kernel, u32& currentPID) : mem(mem), gpu(gpu), kernel(kernel), currentPID(currentPID) {}
|
||||||
kernel(kernel), currentPID(currentPID) {}
|
|
||||||
void reset();
|
void reset();
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
void requestInterrupt(GPUInterrupt type);
|
void requestInterrupt(GPUInterrupt type);
|
||||||
void setSharedMem(u8* ptr) {
|
void setSharedMem(u8* ptr) {
|
||||||
sharedMem = ptr;
|
sharedMem = ptr;
|
||||||
if (ptr != nullptr) { // Zero-fill shared memory in case the process tries to read stale service data or vice versa
|
if (ptr != nullptr) { // Zero-fill shared memory in case the process tries to read stale service data or vice versa
|
||||||
std::memset(ptr, 0, 0x1000);
|
std::memset(ptr, 0, 0x1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,14 +6,14 @@
|
||||||
#include "result/result.hpp"
|
#include "result/result.hpp"
|
||||||
|
|
||||||
class LCDService {
|
class LCDService {
|
||||||
Handle handle = KernelHandles::LCD;
|
HandleType handle = KernelHandles::LCD;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
MAKE_LOG_FUNCTION(log, gspLCDLogger)
|
MAKE_LOG_FUNCTION(log, gspLCDLogger)
|
||||||
|
|
||||||
// Service commands
|
// Service commands
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LCDService(Memory& mem) : mem(mem) {}
|
LCDService(Memory& mem) : mem(mem) {}
|
||||||
void reset();
|
void reset();
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
};
|
};
|
||||||
|
|
|
@ -38,7 +38,7 @@ namespace HID::Keys {
|
||||||
class Kernel;
|
class Kernel;
|
||||||
|
|
||||||
class HIDService {
|
class HIDService {
|
||||||
Handle handle = KernelHandles::HID;
|
HandleType handle = KernelHandles::HID;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
Kernel& kernel;
|
Kernel& kernel;
|
||||||
u8* sharedMem = nullptr; // Pointer to HID shared memory
|
u8* sharedMem = nullptr; // Pointer to HID shared memory
|
||||||
|
@ -60,7 +60,7 @@ class HIDService {
|
||||||
bool gyroEnabled;
|
bool gyroEnabled;
|
||||||
bool touchScreenPressed;
|
bool touchScreenPressed;
|
||||||
|
|
||||||
std::array<std::optional<Handle>, 5> events;
|
std::array<std::optional<HandleType>, 5> events;
|
||||||
|
|
||||||
MAKE_LOG_FUNCTION(log, hidLogger)
|
MAKE_LOG_FUNCTION(log, hidLogger)
|
||||||
|
|
||||||
|
@ -141,9 +141,7 @@ class HIDService {
|
||||||
touchScreenPressed = true;
|
touchScreenPressed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void releaseTouchScreen() {
|
void releaseTouchScreen() { touchScreenPressed = false; }
|
||||||
touchScreenPressed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isTouchScreenPressed() { return touchScreenPressed; }
|
bool isTouchScreenPressed() { return touchScreenPressed; }
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include "memory.hpp"
|
#include "memory.hpp"
|
||||||
|
|
||||||
class HTTPService {
|
class HTTPService {
|
||||||
Handle handle = KernelHandles::HTTP;
|
HandleType handle = KernelHandles::HTTP;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
MAKE_LOG_FUNCTION(log, httpLogger)
|
MAKE_LOG_FUNCTION(log, httpLogger)
|
||||||
|
|
||||||
|
@ -20,4 +20,4 @@ class HTTPService {
|
||||||
HTTPService(Memory& mem) : mem(mem) {}
|
HTTPService(Memory& mem) : mem(mem) {}
|
||||||
void reset();
|
void reset();
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,7 +15,7 @@ class IRUserService {
|
||||||
CirclePadPro = 1,
|
CirclePadPro = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
Handle handle = KernelHandles::IR_USER;
|
HandleType handle = KernelHandles::IR_USER;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
Kernel& kernel;
|
Kernel& kernel;
|
||||||
MAKE_LOG_FUNCTION(log, irUserLogger)
|
MAKE_LOG_FUNCTION(log, irUserLogger)
|
||||||
|
@ -29,7 +29,7 @@ class IRUserService {
|
||||||
void requireConnection(u32 messagePointer);
|
void requireConnection(u32 messagePointer);
|
||||||
void sendIrnop(u32 messagePointer);
|
void sendIrnop(u32 messagePointer);
|
||||||
|
|
||||||
using IREvent = std::optional<Handle>;
|
using IREvent = std::optional<HandleType>;
|
||||||
|
|
||||||
IREvent connectionStatusEvent = std::nullopt;
|
IREvent connectionStatusEvent = std::nullopt;
|
||||||
IREvent receiveEvent = std::nullopt;
|
IREvent receiveEvent = std::nullopt;
|
||||||
|
@ -58,4 +58,4 @@ class IRUserService {
|
||||||
IRUserService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
|
IRUserService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
|
||||||
void reset();
|
void reset();
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
class Kernel;
|
class Kernel;
|
||||||
|
|
||||||
class LDRService {
|
class LDRService {
|
||||||
Handle handle = KernelHandles::LDR_RO;
|
HandleType handle = KernelHandles::LDR_RO;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
Kernel& kernel;
|
Kernel& kernel;
|
||||||
MAKE_LOG_FUNCTION(log, ldrLogger)
|
MAKE_LOG_FUNCTION(log, ldrLogger)
|
||||||
|
@ -22,8 +22,8 @@ class LDRService {
|
||||||
void loadCRR(u32 messagePointer);
|
void loadCRR(u32 messagePointer);
|
||||||
void unloadCRO(u32 messagePointer);
|
void unloadCRO(u32 messagePointer);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LDRService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
|
LDRService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
|
||||||
void reset();
|
void reset();
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
namespace MCU {
|
namespace MCU {
|
||||||
class HWCService {
|
class HWCService {
|
||||||
Handle handle = KernelHandles::MCU_HWC;
|
HandleType handle = KernelHandles::MCU_HWC;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
MAKE_LOG_FUNCTION(log, mcuLogger)
|
MAKE_LOG_FUNCTION(log, mcuLogger)
|
||||||
|
|
||||||
|
@ -21,4 +21,4 @@ namespace MCU {
|
||||||
void reset();
|
void reset();
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
};
|
};
|
||||||
} // namespace MCU
|
} // namespace MCU
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
class Kernel;
|
class Kernel;
|
||||||
|
|
||||||
class MICService {
|
class MICService {
|
||||||
Handle handle = KernelHandles::MIC;
|
HandleType handle = KernelHandles::MIC;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
Kernel& kernel;
|
Kernel& kernel;
|
||||||
MAKE_LOG_FUNCTION(log, micLogger)
|
MAKE_LOG_FUNCTION(log, micLogger)
|
||||||
|
@ -29,15 +29,15 @@ class MICService {
|
||||||
void unmapSharedMem(u32 messagePointer);
|
void unmapSharedMem(u32 messagePointer);
|
||||||
void theCaptainToadFunction(u32 messagePointer);
|
void theCaptainToadFunction(u32 messagePointer);
|
||||||
|
|
||||||
u8 gain = 0; // How loud our microphone input signal is
|
u8 gain = 0; // How loud our microphone input signal is
|
||||||
bool micEnabled = false;
|
bool micEnabled = false;
|
||||||
bool shouldClamp = false;
|
bool shouldClamp = false;
|
||||||
bool currentlySampling = false;
|
bool currentlySampling = false;
|
||||||
|
|
||||||
std::optional<Handle> eventHandle;
|
std::optional<HandleType> eventHandle;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MICService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
|
MICService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
|
||||||
void reset();
|
void reset();
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
class NDMService {
|
class NDMService {
|
||||||
enum class ExclusiveState : u32 { None = 0, Infrastructure = 1, LocalComms = 2, StreetPass = 3, StreetPassData = 4 };
|
enum class ExclusiveState : u32 { None = 0, Infrastructure = 1, LocalComms = 2, StreetPass = 3, StreetPassData = 4 };
|
||||||
|
|
||||||
Handle handle = KernelHandles::NDM;
|
HandleType handle = KernelHandles::NDM;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
MAKE_LOG_FUNCTION(log, ndmLogger)
|
MAKE_LOG_FUNCTION(log, ndmLogger)
|
||||||
|
|
||||||
|
@ -25,8 +25,8 @@ class NDMService {
|
||||||
|
|
||||||
ExclusiveState exclusiveState = ExclusiveState::None;
|
ExclusiveState exclusiveState = ExclusiveState::None;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NDMService(Memory& mem) : mem(mem) {}
|
NDMService(Memory& mem) : mem(mem) {}
|
||||||
void reset();
|
void reset();
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include "memory.hpp"
|
#include "memory.hpp"
|
||||||
|
|
||||||
class NewsUService {
|
class NewsUService {
|
||||||
Handle handle = KernelHandles::NEWS_U;
|
HandleType handle = KernelHandles::NEWS_U;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
MAKE_LOG_FUNCTION(log, newsLogger)
|
MAKE_LOG_FUNCTION(log, newsLogger)
|
||||||
|
|
||||||
|
@ -15,4 +15,4 @@ class NewsUService {
|
||||||
NewsUService(Memory& mem) : mem(mem) {}
|
NewsUService(Memory& mem) : mem(mem) {}
|
||||||
void reset();
|
void reset();
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
class Kernel;
|
class Kernel;
|
||||||
|
|
||||||
class NFCService {
|
class NFCService {
|
||||||
Handle handle = KernelHandles::NFC;
|
HandleType handle = KernelHandles::NFC;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
Kernel& kernel;
|
Kernel& kernel;
|
||||||
MAKE_LOG_FUNCTION(log, nfcLogger)
|
MAKE_LOG_FUNCTION(log, nfcLogger)
|
||||||
|
@ -34,7 +34,7 @@ class NFCService {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Kernel events signaled when an NFC tag goes in and out of range respectively
|
// Kernel events signaled when an NFC tag goes in and out of range respectively
|
||||||
std::optional<Handle> tagInRangeEvent, tagOutOfRangeEvent;
|
std::optional<HandleType> tagInRangeEvent, tagOutOfRangeEvent;
|
||||||
|
|
||||||
AmiiboDevice device;
|
AmiiboDevice device;
|
||||||
Old3DSAdapterStatus adapterStatus;
|
Old3DSAdapterStatus adapterStatus;
|
||||||
|
@ -63,4 +63,4 @@ class NFCService {
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
|
|
||||||
bool loadAmiibo(const std::filesystem::path& path);
|
bool loadAmiibo(const std::filesystem::path& path);
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,15 +6,15 @@
|
||||||
#include "result/result.hpp"
|
#include "result/result.hpp"
|
||||||
|
|
||||||
class NIMService {
|
class NIMService {
|
||||||
Handle handle = KernelHandles::NIM;
|
HandleType handle = KernelHandles::NIM;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
MAKE_LOG_FUNCTION(log, nimLogger)
|
MAKE_LOG_FUNCTION(log, nimLogger)
|
||||||
|
|
||||||
// Service commands
|
// Service commands
|
||||||
void initialize(u32 messagePointer);
|
void initialize(u32 messagePointer);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NIMService(Memory& mem) : mem(mem) {}
|
NIMService(Memory& mem) : mem(mem) {}
|
||||||
void reset();
|
void reset();
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,13 +10,13 @@
|
||||||
class Kernel;
|
class Kernel;
|
||||||
|
|
||||||
class NwmUdsService {
|
class NwmUdsService {
|
||||||
Handle handle = KernelHandles::NWM_UDS;
|
HandleType handle = KernelHandles::NWM_UDS;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
Kernel& kernel;
|
Kernel& kernel;
|
||||||
MAKE_LOG_FUNCTION(log, nwmUdsLogger)
|
MAKE_LOG_FUNCTION(log, nwmUdsLogger)
|
||||||
|
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
std::optional<Handle> eventHandle = std::nullopt;
|
std::optional<HandleType> eventHandle = std::nullopt;
|
||||||
|
|
||||||
// Service commands
|
// Service commands
|
||||||
void initializeWithVersion(u32 messagePointer);
|
void initializeWithVersion(u32 messagePointer);
|
||||||
|
@ -25,4 +25,4 @@ class NwmUdsService {
|
||||||
NwmUdsService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
|
NwmUdsService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
|
||||||
void reset();
|
void reset();
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
};
|
};
|
||||||
|
|
|
@ -28,10 +28,10 @@
|
||||||
#include "services/mcu/mcu_hwc.hpp"
|
#include "services/mcu/mcu_hwc.hpp"
|
||||||
#include "services/mic.hpp"
|
#include "services/mic.hpp"
|
||||||
#include "services/ndm.hpp"
|
#include "services/ndm.hpp"
|
||||||
#include "services/nwm_uds.hpp"
|
|
||||||
#include "services/news_u.hpp"
|
#include "services/news_u.hpp"
|
||||||
#include "services/nfc.hpp"
|
#include "services/nfc.hpp"
|
||||||
#include "services/nim.hpp"
|
#include "services/nim.hpp"
|
||||||
|
#include "services/nwm_uds.hpp"
|
||||||
#include "services/ptm.hpp"
|
#include "services/ptm.hpp"
|
||||||
#include "services/soc.hpp"
|
#include "services/soc.hpp"
|
||||||
#include "services/ssl.hpp"
|
#include "services/ssl.hpp"
|
||||||
|
@ -46,15 +46,15 @@ class ServiceManager {
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
Kernel& kernel;
|
Kernel& kernel;
|
||||||
|
|
||||||
std::optional<Handle> notificationSemaphore;
|
std::optional<HandleType> notificationSemaphore;
|
||||||
|
|
||||||
MAKE_LOG_FUNCTION(log, srvLogger)
|
MAKE_LOG_FUNCTION(log, srvLogger)
|
||||||
|
|
||||||
ACService ac;
|
ACService ac;
|
||||||
ACTService act;
|
ACTService act;
|
||||||
AMService am;
|
AMService am;
|
||||||
APTService apt;
|
APTService apt;
|
||||||
BOSSService boss;
|
BOSSService boss;
|
||||||
CAMService cam;
|
CAMService cam;
|
||||||
CECDService cecd;
|
CECDService cecd;
|
||||||
CFGService cfg;
|
CFGService cfg;
|
||||||
|
@ -74,7 +74,7 @@ class ServiceManager {
|
||||||
NewsUService news_u;
|
NewsUService news_u;
|
||||||
NFCService nfc;
|
NFCService nfc;
|
||||||
NwmUdsService nwm_uds;
|
NwmUdsService nwm_uds;
|
||||||
NIMService nim;
|
NIMService nim;
|
||||||
PTMService ptm;
|
PTMService ptm;
|
||||||
SOCService soc;
|
SOCService soc;
|
||||||
SSLService ssl;
|
SSLService ssl;
|
||||||
|
@ -97,7 +97,7 @@ class ServiceManager {
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
|
|
||||||
// Forward a SendSyncRequest IPC message to the service with the respective handle
|
// Forward a SendSyncRequest IPC message to the service with the respective handle
|
||||||
void sendCommandToService(u32 messagePointer, Handle handle);
|
void sendCommandToService(u32 messagePointer, HandleType handle);
|
||||||
|
|
||||||
// Wrappers for communicating with certain services
|
// Wrappers for communicating with certain services
|
||||||
void sendGPUInterrupt(GPUInterrupt type) { gsp_gpu.requestInterrupt(type); }
|
void sendGPUInterrupt(GPUInterrupt type) { gsp_gpu.requestInterrupt(type); }
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include "memory.hpp"
|
#include "memory.hpp"
|
||||||
|
|
||||||
class SOCService {
|
class SOCService {
|
||||||
Handle handle = KernelHandles::SOC;
|
HandleType handle = KernelHandles::SOC;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
MAKE_LOG_FUNCTION(log, socLogger)
|
MAKE_LOG_FUNCTION(log, socLogger)
|
||||||
|
|
||||||
|
@ -14,8 +14,8 @@ class SOCService {
|
||||||
// Service commands
|
// Service commands
|
||||||
void initializeSockets(u32 messagePointer);
|
void initializeSockets(u32 messagePointer);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SOCService(Memory& mem) : mem(mem) {}
|
SOCService(Memory& mem) : mem(mem) {}
|
||||||
void reset();
|
void reset();
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <random>
|
||||||
|
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
#include "kernel_types.hpp"
|
#include "kernel_types.hpp"
|
||||||
#include "logger.hpp"
|
#include "logger.hpp"
|
||||||
#include "memory.hpp"
|
#include "memory.hpp"
|
||||||
|
|
||||||
#include <random>
|
|
||||||
|
|
||||||
class SSLService {
|
class SSLService {
|
||||||
Handle handle = KernelHandles::SSL;
|
HandleType handle = KernelHandles::SSL;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
MAKE_LOG_FUNCTION(log, sslLogger)
|
MAKE_LOG_FUNCTION(log, sslLogger)
|
||||||
|
|
||||||
std::mt19937 rng; // Use a Mersenne Twister for RNG since this service is supposed to have better rng than just rand()
|
std::mt19937 rng; // Use a Mersenne Twister for RNG since this service is supposed to have better rng than just rand()
|
||||||
bool initialized;
|
bool initialized;
|
||||||
|
|
||||||
// Service commands
|
// Service commands
|
||||||
|
@ -22,4 +22,4 @@ class SSLService {
|
||||||
SSLService(Memory& mem) : mem(mem) {}
|
SSLService(Memory& mem) : mem(mem) {}
|
||||||
void reset();
|
void reset();
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
#include "kernel_types.hpp"
|
#include "kernel_types.hpp"
|
||||||
#include "logger.hpp"
|
#include "logger.hpp"
|
||||||
|
@ -10,18 +11,15 @@
|
||||||
class Kernel;
|
class Kernel;
|
||||||
|
|
||||||
class Y2RService {
|
class Y2RService {
|
||||||
Handle handle = KernelHandles::Y2R;
|
HandleType handle = KernelHandles::Y2R;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
Kernel& kernel;
|
Kernel& kernel;
|
||||||
MAKE_LOG_FUNCTION(log, y2rLogger)
|
MAKE_LOG_FUNCTION(log, y2rLogger)
|
||||||
|
|
||||||
std::optional<Handle> transferEndEvent;
|
std::optional<HandleType> transferEndEvent;
|
||||||
bool transferEndInterruptEnabled;
|
bool transferEndInterruptEnabled;
|
||||||
|
|
||||||
enum class BusyStatus : u32 {
|
enum class BusyStatus : u32 { NotBusy = 0, Busy = 1 };
|
||||||
NotBusy = 0,
|
|
||||||
Busy = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class InputFormat : u32 {
|
enum class InputFormat : u32 {
|
||||||
YUV422_Individual8 = 0,
|
YUV422_Individual8 = 0,
|
||||||
|
@ -31,24 +29,14 @@ class Y2RService {
|
||||||
YUV422_Batch = 4,
|
YUV422_Batch = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class OutputFormat : u32 {
|
enum class OutputFormat : u32 { RGB32 = 0, RGB24 = 1, RGB15 = 2, RGB565 = 3 };
|
||||||
RGB32 = 0,
|
|
||||||
RGB24 = 1,
|
|
||||||
RGB15 = 2,
|
|
||||||
RGB565 = 3
|
|
||||||
};
|
|
||||||
|
|
||||||
// Clockwise rotation
|
// Clockwise rotation
|
||||||
enum class Rotation : u32 {
|
enum class Rotation : u32 { None = 0, Rotate90 = 1, Rotate180 = 2, Rotate270 = 3 };
|
||||||
None = 0,
|
|
||||||
Rotate90 = 1,
|
|
||||||
Rotate180 = 2,
|
|
||||||
Rotate270 = 3
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class BlockAlignment : u32 {
|
enum class BlockAlignment : u32 {
|
||||||
Line = 0, // Output buffer's pixels are arranged linearly. Used when outputting to the framebuffer.
|
Line = 0, // Output buffer's pixels are arranged linearly. Used when outputting to the framebuffer.
|
||||||
Block8x8 = 1, // Output buffer's pixels are morton swizzled. Used when outputting to a GPU texture.
|
Block8x8 = 1, // Output buffer's pixels are morton swizzled. Used when outputting to a GPU texture.
|
||||||
};
|
};
|
||||||
|
|
||||||
// https://github.com/citra-emu/citra/blob/ac9d72a95ca9a60de8d39484a14aecf489d6d016/src/core/hle/service/cam/y2r_u.cpp#L33
|
// https://github.com/citra-emu/citra/blob/ac9d72a95ca9a60de8d39484a14aecf489d6d016/src/core/hle/service/cam/y2r_u.cpp#L33
|
||||||
|
@ -60,7 +48,7 @@ class Y2RService {
|
||||||
{{0x12A, 0x1CA, 0x88, 0x36, 0x21C, -0x1F04, 0x99C, -0x2421}}, // ITU_Rec709_Scaling
|
{{0x12A, 0x1CA, 0x88, 0x36, 0x21C, -0x1F04, 0x99C, -0x2421}}, // ITU_Rec709_Scaling
|
||||||
}};
|
}};
|
||||||
|
|
||||||
CoefficientSet conversionCoefficients; // Current conversion coefficients
|
CoefficientSet conversionCoefficients; // Current conversion coefficients
|
||||||
|
|
||||||
InputFormat inputFmt;
|
InputFormat inputFmt;
|
||||||
OutputFormat outputFmt;
|
OutputFormat outputFmt;
|
||||||
|
@ -113,8 +101,8 @@ class Y2RService {
|
||||||
void startConversion(u32 messagePointer);
|
void startConversion(u32 messagePointer);
|
||||||
void stopConversion(u32 messagePointer);
|
void stopConversion(u32 messagePointer);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Y2RService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
|
Y2RService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
|
||||||
void reset();
|
void reset();
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
};
|
};
|
||||||
|
|
|
@ -40,7 +40,7 @@ void CPU::runFrame() {
|
||||||
execute:
|
execute:
|
||||||
const auto exitReason = jit->Run();
|
const auto exitReason = jit->Run();
|
||||||
|
|
||||||
// Handle any scheduler events that need handling.
|
// HandleType any scheduler events that need handling.
|
||||||
emu.pollScheduler();
|
emu.pollScheduler();
|
||||||
|
|
||||||
if (static_cast<u32>(exitReason) != 0) [[unlikely]] {
|
if (static_cast<u32>(exitReason) != 0) [[unlikely]] {
|
||||||
|
@ -55,4 +55,4 @@ void CPU::runFrame() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CPU_DYNARMIC
|
#endif // CPU_DYNARMIC
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
#if defined(PANDA3DS_DYNAPICA_SUPPORTED) && defined(PANDA3DS_X64_HOST)
|
#if defined(PANDA3DS_DYNAPICA_SUPPORTED) && defined(PANDA3DS_X64_HOST)
|
||||||
#include "PICA/dynapica/shader_rec_emitter_x64.hpp"
|
#include "PICA/dynapica/shader_rec_emitter_x64.hpp"
|
||||||
|
|
||||||
|
#include <immintrin.h>
|
||||||
|
#include <smmintrin.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <bit>
|
#include <bit>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <immintrin.h>
|
|
||||||
#include <smmintrin.h>
|
|
||||||
|
|
||||||
using namespace Xbyak;
|
using namespace Xbyak;
|
||||||
using namespace Xbyak::util;
|
using namespace Xbyak::util;
|
||||||
|
@ -41,9 +42,15 @@ void ShaderEmitter::compile(const PICAShader& shaderUnit) {
|
||||||
// Constants
|
// Constants
|
||||||
align(16);
|
align(16);
|
||||||
L(negateVector);
|
L(negateVector);
|
||||||
dd(0x80000000); dd(0x80000000); dd(0x80000000); dd(0x80000000); // -0.0 4 times
|
dd(0x80000000);
|
||||||
|
dd(0x80000000);
|
||||||
|
dd(0x80000000);
|
||||||
|
dd(0x80000000); // -0.0 4 times
|
||||||
L(onesVector);
|
L(onesVector);
|
||||||
dd(0x3f800000); dd(0x3f800000); dd(0x3f800000); dd(0x3f800000); // 1.0 4 times
|
dd(0x3f800000);
|
||||||
|
dd(0x3f800000);
|
||||||
|
dd(0x3f800000);
|
||||||
|
dd(0x3f800000); // 1.0 4 times
|
||||||
|
|
||||||
// Emit prologue first
|
// Emit prologue first
|
||||||
align(16);
|
align(16);
|
||||||
|
@ -86,7 +93,7 @@ void ShaderEmitter::scanCode(const PICAShader& shaderUnit) {
|
||||||
if (isCall(instruction)) {
|
if (isCall(instruction)) {
|
||||||
const u32 num = instruction & 0xff;
|
const u32 num = instruction & 0xff;
|
||||||
const u32 dest = getBits<10, 12>(instruction);
|
const u32 dest = getBits<10, 12>(instruction);
|
||||||
const u32 returnPC = num + dest; // Add them to get the return PC
|
const u32 returnPC = num + dest; // Add them to get the return PC
|
||||||
|
|
||||||
returnPCs.push_back(returnPC);
|
returnPCs.push_back(returnPC);
|
||||||
} else if (opcode == ShaderOpcodes::EX2) {
|
} else if (opcode == ShaderOpcodes::EX2) {
|
||||||
|
@ -129,23 +136,15 @@ void ShaderEmitter::compileInstruction(const PICAShader& shaderUnit) {
|
||||||
|
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case ShaderOpcodes::ADD: recADD(shaderUnit, instruction); break;
|
case ShaderOpcodes::ADD: recADD(shaderUnit, instruction); break;
|
||||||
case ShaderOpcodes::CALL:
|
case ShaderOpcodes::CALL: recCALL(shaderUnit, instruction); break;
|
||||||
recCALL(shaderUnit, instruction);
|
case ShaderOpcodes::CALLC: recCALLC(shaderUnit, instruction); break;
|
||||||
break;
|
case ShaderOpcodes::CALLU: recCALLU(shaderUnit, instruction); break;
|
||||||
case ShaderOpcodes::CALLC:
|
case ShaderOpcodes::CMP1:
|
||||||
recCALLC(shaderUnit, instruction);
|
case ShaderOpcodes::CMP2: recCMP(shaderUnit, instruction); break;
|
||||||
break;
|
|
||||||
case ShaderOpcodes::CALLU:
|
|
||||||
recCALLU(shaderUnit, instruction);
|
|
||||||
break;
|
|
||||||
case ShaderOpcodes::CMP1: case ShaderOpcodes::CMP2:
|
|
||||||
recCMP(shaderUnit, instruction);
|
|
||||||
break;
|
|
||||||
case ShaderOpcodes::DP3: recDP3(shaderUnit, instruction); break;
|
case ShaderOpcodes::DP3: recDP3(shaderUnit, instruction); break;
|
||||||
case ShaderOpcodes::DP4: recDP4(shaderUnit, instruction); break;
|
case ShaderOpcodes::DP4: recDP4(shaderUnit, instruction); break;
|
||||||
case ShaderOpcodes::DPH:
|
case ShaderOpcodes::DPH:
|
||||||
case ShaderOpcodes::DPHI:
|
case ShaderOpcodes::DPHI: recDPH(shaderUnit, instruction); break;
|
||||||
recDPH(shaderUnit, instruction); break;
|
|
||||||
case ShaderOpcodes::END: recEND(shaderUnit, instruction); break;
|
case ShaderOpcodes::END: recEND(shaderUnit, instruction); break;
|
||||||
case ShaderOpcodes::EX2: recEX2(shaderUnit, instruction); break;
|
case ShaderOpcodes::EX2: recEX2(shaderUnit, instruction); break;
|
||||||
case ShaderOpcodes::FLR: recFLR(shaderUnit, instruction); break;
|
case ShaderOpcodes::FLR: recFLR(shaderUnit, instruction); break;
|
||||||
|
@ -176,21 +175,30 @@ void ShaderEmitter::compileInstruction(const PICAShader& shaderUnit) {
|
||||||
case ShaderOpcodes::BREAKC: Helpers::warn("[Shader JIT] Unimplemented BREAK(C) instruction!"); break;
|
case ShaderOpcodes::BREAKC: Helpers::warn("[Shader JIT] Unimplemented BREAK(C) instruction!"); break;
|
||||||
|
|
||||||
// We consider both MAD and MADI to be the same instruction and decode which one we actually have in recMAD
|
// We consider both MAD and MADI to be the same instruction and decode which one we actually have in recMAD
|
||||||
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
|
case 0x30:
|
||||||
case 0x38: case 0x39: case 0x3A: case 0x3B: case 0x3C: case 0x3D: case 0x3E: case 0x3F:
|
case 0x31:
|
||||||
recMAD(shaderUnit, instruction);
|
case 0x32:
|
||||||
break;
|
case 0x33:
|
||||||
|
case 0x34:
|
||||||
|
case 0x35:
|
||||||
|
case 0x36:
|
||||||
|
case 0x37:
|
||||||
|
case 0x38:
|
||||||
|
case 0x39:
|
||||||
|
case 0x3A:
|
||||||
|
case 0x3B:
|
||||||
|
case 0x3C:
|
||||||
|
case 0x3D:
|
||||||
|
case 0x3E:
|
||||||
|
case 0x3F: recMAD(shaderUnit, instruction); break;
|
||||||
|
|
||||||
case ShaderOpcodes::SLT:
|
case ShaderOpcodes::SLT:
|
||||||
case ShaderOpcodes::SLTI:
|
case ShaderOpcodes::SLTI: recSLT(shaderUnit, instruction); break;
|
||||||
recSLT(shaderUnit, instruction); break;
|
|
||||||
|
|
||||||
case ShaderOpcodes::SGE:
|
case ShaderOpcodes::SGE:
|
||||||
case ShaderOpcodes::SGEI:
|
case ShaderOpcodes::SGEI: recSGE(shaderUnit, instruction); break;
|
||||||
recSGE(shaderUnit, instruction); break;
|
|
||||||
|
|
||||||
default:
|
default: Helpers::panic("Shader JIT: Unimplemented PICA opcode %X", opcode);
|
||||||
Helpers::panic("Shader JIT: Unimplemented PICA opcode %X", opcode);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,64 +227,64 @@ const ShaderEmitter::vec4f& ShaderEmitter::getDestRef(const PICAShader& shader,
|
||||||
// See shader.hpp header for docs on how the swizzle and negate works
|
// See shader.hpp header for docs on how the swizzle and negate works
|
||||||
template <int sourceIndex>
|
template <int sourceIndex>
|
||||||
void ShaderEmitter::loadRegister(Xmm dest, const PICAShader& shader, u32 src, u32 index, u32 operandDescriptor) {
|
void ShaderEmitter::loadRegister(Xmm dest, const PICAShader& shader, u32 src, u32 index, u32 operandDescriptor) {
|
||||||
u32 compSwizzle; // Component swizzle pattern for the register
|
u32 compSwizzle; // Component swizzle pattern for the register
|
||||||
bool negate; // If true, negate all lanes of the register
|
bool negate; // If true, negate all lanes of the register
|
||||||
|
|
||||||
if constexpr (sourceIndex == 1) { // SRC1
|
if constexpr (sourceIndex == 1) { // SRC1
|
||||||
negate = (getBit<4>(operandDescriptor)) != 0;
|
negate = (getBit<4>(operandDescriptor)) != 0;
|
||||||
compSwizzle = getBits<5, 8>(operandDescriptor);
|
compSwizzle = getBits<5, 8>(operandDescriptor);
|
||||||
}
|
} else if constexpr (sourceIndex == 2) { // SRC2
|
||||||
else if constexpr (sourceIndex == 2) { // SRC2
|
|
||||||
negate = (getBit<13>(operandDescriptor)) != 0;
|
negate = (getBit<13>(operandDescriptor)) != 0;
|
||||||
compSwizzle = getBits<14, 8>(operandDescriptor);
|
compSwizzle = getBits<14, 8>(operandDescriptor);
|
||||||
}
|
} else if constexpr (sourceIndex == 3) { // SRC3
|
||||||
else if constexpr (sourceIndex == 3) { // SRC3
|
|
||||||
negate = (getBit<22>(operandDescriptor)) != 0;
|
negate = (getBit<22>(operandDescriptor)) != 0;
|
||||||
compSwizzle = getBits<23, 8>(operandDescriptor);
|
compSwizzle = getBits<23, 8>(operandDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Do indexes get applied if src < 0x20?
|
// TODO: Do indexes get applied if src < 0x20?
|
||||||
|
|
||||||
// PICA has the swizzle descriptor inverted in comparison to x86. For the PICA, the descriptor is (lowest to highest bits) wzyx while it's xyzw for x86
|
// PICA has the swizzle descriptor inverted in comparison to x86. For the PICA, the descriptor is (lowest to highest bits) wzyx while it's xyzw
|
||||||
u32 convertedSwizzle = ((compSwizzle >> 6) & 0b11) | (((compSwizzle >> 4) & 0b11) << 2) | (((compSwizzle >> 2) & 0b11) << 4) | ((compSwizzle & 0b11) << 6);
|
// for x86
|
||||||
|
u32 convertedSwizzle =
|
||||||
|
((compSwizzle >> 6) & 0b11) | (((compSwizzle >> 4) & 0b11) << 2) | (((compSwizzle >> 2) & 0b11) << 4) | ((compSwizzle & 0b11) << 6);
|
||||||
|
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0: [[likely]] { // Keep src as is, no need to offset it
|
case 0:
|
||||||
const vec4f& srcRef = getSourceRef(shader, src);
|
[[likely]] { // Keep src as is, no need to offset it
|
||||||
const uintptr_t offset = uintptr_t(&srcRef) - uintptr_t(&shader); // Calculate offset of register from start of the state struct
|
const vec4f& srcRef = getSourceRef(shader, src);
|
||||||
|
const uintptr_t offset = uintptr_t(&srcRef) - uintptr_t(&shader); // Calculate offset of register from start of the state struct
|
||||||
|
|
||||||
if (compSwizzle == noSwizzle) // Avoid emitting swizzle if not necessary
|
if (compSwizzle == noSwizzle) // Avoid emitting swizzle if not necessary
|
||||||
movaps(dest, xword[statePointer + offset]);
|
movaps(dest, xword[statePointer + offset]);
|
||||||
else // Swizzle is not trivial so we need to emit a shuffle instruction
|
else // Swizzle is not trivial so we need to emit a shuffle instruction
|
||||||
pshufd(dest, xword[statePointer + offset], convertedSwizzle);
|
pshufd(dest, xword[statePointer + offset], convertedSwizzle);
|
||||||
|
|
||||||
// Negate the register if necessary
|
// Negate the register if necessary
|
||||||
if (negate) {
|
if (negate) {
|
||||||
pxor(dest, xword[rip + negateVector]);
|
pxor(dest, xword[rip + negateVector]);
|
||||||
|
}
|
||||||
|
return; // Return. Rest of the function handles indexing which is not used if index == 0
|
||||||
}
|
}
|
||||||
return; // Return. Rest of the function handles indexing which is not used if index == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
case 1: {
|
case 1: {
|
||||||
const uintptr_t addrXOffset = uintptr_t(&shader.addrRegister[0]) - uintptr_t(&shader);
|
const uintptr_t addrXOffset = uintptr_t(&shader.addrRegister[0]) - uintptr_t(&shader);
|
||||||
movsxd(rax, dword[statePointer + addrXOffset]); // rax = address register x
|
movsxd(rax, dword[statePointer + addrXOffset]); // rax = address register x
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 2: {
|
case 2: {
|
||||||
const uintptr_t addrYOffset = uintptr_t(&shader.addrRegister[1]) - uintptr_t(&shader);
|
const uintptr_t addrYOffset = uintptr_t(&shader.addrRegister[1]) - uintptr_t(&shader);
|
||||||
movsxd(rax, dword[statePointer + addrYOffset]); // rax = address register y
|
movsxd(rax, dword[statePointer + addrYOffset]); // rax = address register y
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 3: {
|
case 3: {
|
||||||
const uintptr_t loopCounterOffset = uintptr_t(&shader.loopCounter) - uintptr_t(&shader);
|
const uintptr_t loopCounterOffset = uintptr_t(&shader.loopCounter) - uintptr_t(&shader);
|
||||||
mov(eax, dword[statePointer + loopCounterOffset]); // rax = loop counter
|
mov(eax, dword[statePointer + loopCounterOffset]); // rax = loop counter
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default: Helpers::panic("[ShaderJIT]: Unimplemented source index type %d", index);
|
||||||
Helpers::panic("[ShaderJIT]: Unimplemented source index type %d", index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Swizzle and load register into dest, from [state pointer + rcx + offset] and apply the relevant swizzle
|
// Swizzle and load register into dest, from [state pointer + rcx + offset] and apply the relevant swizzle
|
||||||
|
@ -304,7 +312,7 @@ void ShaderEmitter::loadRegister(Xmm dest, const PICAShader& shader, u32 src, u3
|
||||||
shl(rcx, 4); // rcx = rax * sizeof(vec4 of floats) = rax * 16
|
shl(rcx, 4); // rcx = rax * sizeof(vec4 of floats) = rax * 16
|
||||||
swizzleAndLoadReg(inputOffset);
|
swizzleAndLoadReg(inputOffset);
|
||||||
jmp(end);
|
jmp(end);
|
||||||
|
|
||||||
// If (reg < 0x1F) return tempRegisters[reg - 0x10]
|
// If (reg < 0x1F) return tempRegisters[reg - 0x10]
|
||||||
L(maybeTemp);
|
L(maybeTemp);
|
||||||
cmp(rax, 0x20);
|
cmp(rax, 0x20);
|
||||||
|
@ -324,7 +332,7 @@ void ShaderEmitter::loadRegister(Xmm dest, const PICAShader& shader, u32 src, u3
|
||||||
jmp(end);
|
jmp(end);
|
||||||
|
|
||||||
L(unknownReg);
|
L(unknownReg);
|
||||||
pxor(dest, dest); // Set dest to 0 if we're reading from a garbage register
|
pxor(dest, dest); // Set dest to 0 if we're reading from a garbage register
|
||||||
|
|
||||||
L(end);
|
L(end);
|
||||||
// Negate the register if necessary
|
// Negate the register if necessary
|
||||||
|
@ -335,20 +343,20 @@ void ShaderEmitter::loadRegister(Xmm dest, const PICAShader& shader, u32 src, u3
|
||||||
|
|
||||||
void ShaderEmitter::storeRegister(Xmm source, const PICAShader& shader, u32 dest, u32 operandDescriptor) {
|
void ShaderEmitter::storeRegister(Xmm source, const PICAShader& shader, u32 dest, u32 operandDescriptor) {
|
||||||
const vec4f& destRef = getDestRef(shader, dest);
|
const vec4f& destRef = getDestRef(shader, dest);
|
||||||
const uintptr_t offset = uintptr_t(&destRef) - uintptr_t(&shader); // Calculate offset of register from start of the state struct
|
const uintptr_t offset = uintptr_t(&destRef) - uintptr_t(&shader); // Calculate offset of register from start of the state struct
|
||||||
|
|
||||||
// Mask of which lanes to write
|
// Mask of which lanes to write
|
||||||
u32 writeMask = operandDescriptor & 0xf;
|
u32 writeMask = operandDescriptor & 0xf;
|
||||||
if (writeMask == 0xf) { // No lanes are masked, just movaps
|
if (writeMask == 0xf) { // No lanes are masked, just movaps
|
||||||
movaps(xword[statePointer + offset], source);
|
movaps(xword[statePointer + offset], source);
|
||||||
} else if (std::popcount(writeMask) == 1) { // Only 1 register needs to be written back. This can be done with a simple shift right + movss
|
} else if (std::popcount(writeMask) == 1) { // Only 1 register needs to be written back. This can be done with a simple shift right + movss
|
||||||
int bit = std::countr_zero(writeMask); // Get which PICA register needs to be written to (0 = w, 1 = z, etc)
|
int bit = std::countr_zero(writeMask); // Get which PICA register needs to be written to (0 = w, 1 = z, etc)
|
||||||
size_t index = 3 - bit;
|
size_t index = 3 - bit;
|
||||||
const uintptr_t laneOffset = offset + index * sizeof(float);
|
const uintptr_t laneOffset = offset + index * sizeof(float);
|
||||||
|
|
||||||
if (index == 0) { // Bottom lane, no need to shift
|
if (index == 0) { // Bottom lane, no need to shift
|
||||||
movss(dword[statePointer + laneOffset], source);
|
movss(dword[statePointer + laneOffset], source);
|
||||||
} else { // Shift right by 32 * index, then write bottom lane
|
} else { // Shift right by 32 * index, then write bottom lane
|
||||||
if (haveAVX) {
|
if (haveAVX) {
|
||||||
vpsrldq(scratch1, source, index * sizeof(float));
|
vpsrldq(scratch1, source, index * sizeof(float));
|
||||||
} else {
|
} else {
|
||||||
|
@ -363,18 +371,17 @@ void ShaderEmitter::storeRegister(Xmm source, const PICAShader& shader, u32 dest
|
||||||
// Don't accidentally overwrite scratch1 if that is what we're writing derp
|
// Don't accidentally overwrite scratch1 if that is what we're writing derp
|
||||||
Xmm temp = (source == scratch1) ? scratch2 : scratch1;
|
Xmm temp = (source == scratch1) ? scratch2 : scratch1;
|
||||||
|
|
||||||
movaps(temp, xword[statePointer + offset]); // Read current value of dest
|
movaps(temp, xword[statePointer + offset]); // Read current value of dest
|
||||||
blendps(temp, source, adjustedMask); // Blend with source
|
blendps(temp, source, adjustedMask); // Blend with source
|
||||||
movaps(xword[statePointer + offset], temp); // Write back
|
movaps(xword[statePointer + offset], temp); // Write back
|
||||||
} else {
|
} else {
|
||||||
// Blend algo referenced from Citra
|
// Blend algo referenced from Citra
|
||||||
const u8 selector = (((writeMask & 0b1000) ? 1 : 0) << 0) |
|
const u8 selector = (((writeMask & 0b1000) ? 1 : 0) << 0) | (((writeMask & 0b0100) ? 3 : 2) << 2) | (((writeMask & 0b0010) ? 0 : 1) << 4) |
|
||||||
(((writeMask & 0b0100) ? 3 : 2) << 2) |
|
(((writeMask & 0b0001) ? 2 : 3) << 6);
|
||||||
(((writeMask & 0b0010) ? 0 : 1) << 4) |
|
|
||||||
(((writeMask & 0b0001) ? 2 : 3) << 6);
|
|
||||||
|
|
||||||
// Reorder instructions based on whether the source == scratch1. This is to avoid overwriting scratch1 if it's the source,
|
// Reorder instructions based on whether the source == scratch1. This is to avoid overwriting scratch1 if it's the source,
|
||||||
// While also having the memory load come first to mitigate execution hazards and give the load more time to complete before reading if possible
|
// While also having the memory load come first to mitigate execution hazards and give the load more time to complete before reading if
|
||||||
|
// possible
|
||||||
if (source != scratch1) {
|
if (source != scratch1) {
|
||||||
movaps(scratch1, xword[statePointer + offset]);
|
movaps(scratch1, xword[statePointer + offset]);
|
||||||
movaps(scratch2, source);
|
movaps(scratch2, source);
|
||||||
|
@ -382,16 +389,16 @@ void ShaderEmitter::storeRegister(Xmm source, const PICAShader& shader, u32 dest
|
||||||
movaps(scratch2, source);
|
movaps(scratch2, source);
|
||||||
movaps(scratch1, xword[statePointer + offset]);
|
movaps(scratch1, xword[statePointer + offset]);
|
||||||
}
|
}
|
||||||
|
|
||||||
unpckhps(scratch2, scratch1); // Unpack X/Y components of source and destination
|
unpckhps(scratch2, scratch1); // Unpack X/Y components of source and destination
|
||||||
unpcklps(scratch1, source); // Unpack Z/W components of source and destination
|
unpcklps(scratch1, source); // Unpack Z/W components of source and destination
|
||||||
shufps(scratch1, scratch2, selector); // "merge-shuffle" dest and source using selecto
|
shufps(scratch1, scratch2, selector); // "merge-shuffle" dest and source using selecto
|
||||||
movaps(xword[statePointer + offset], scratch1); // Write back
|
movaps(xword[statePointer + offset], scratch1); // Write back
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderEmitter::checkCmpRegister(const PICAShader& shader, u32 instruction) {
|
void ShaderEmitter::checkCmpRegister(const PICAShader& shader, u32 instruction) {
|
||||||
static_assert(sizeof(bool) == 1 && sizeof(shader.cmpRegister) == 2); // The code below relies on bool being 1 byte exactly
|
static_assert(sizeof(bool) == 1 && sizeof(shader.cmpRegister) == 2); // The code below relies on bool being 1 byte exactly
|
||||||
const size_t cmpRegXOffset = uintptr_t(&shader.cmpRegister[0]) - uintptr_t(&shader);
|
const size_t cmpRegXOffset = uintptr_t(&shader.cmpRegister[0]) - uintptr_t(&shader);
|
||||||
const size_t cmpRegYOffset = cmpRegXOffset + sizeof(bool);
|
const size_t cmpRegYOffset = cmpRegXOffset + sizeof(bool);
|
||||||
|
|
||||||
|
@ -399,11 +406,12 @@ void ShaderEmitter::checkCmpRegister(const PICAShader& shader, u32 instruction)
|
||||||
const uint refY = getBit<24>(instruction);
|
const uint refY = getBit<24>(instruction);
|
||||||
const uint refX = getBit<25>(instruction);
|
const uint refX = getBit<25>(instruction);
|
||||||
|
|
||||||
// refX in the bottom byte, refY in the top byte. This is done for condition codes 0 and 1 which check both x and y, so we can emit a single instruction that checks both
|
// refX in the bottom byte, refY in the top byte. This is done for condition codes 0 and 1 which check both x and y, so we can emit a single
|
||||||
|
// instruction that checks both
|
||||||
const u16 refX_refY_merged = refX | (refY << 8);
|
const u16 refX_refY_merged = refX | (refY << 8);
|
||||||
|
|
||||||
switch (condition) {
|
switch (condition) {
|
||||||
case 0: // Either cmp register matches
|
case 0: // Either cmp register matches
|
||||||
// Z flag is 0 if at least 1 of them is set
|
// Z flag is 0 if at least 1 of them is set
|
||||||
|
|
||||||
// Check if X matches
|
// Check if X matches
|
||||||
|
@ -418,20 +426,20 @@ void ShaderEmitter::checkCmpRegister(const PICAShader& shader, u32 instruction)
|
||||||
// If either of them matches, set Z to 1, else set it to 0
|
// If either of them matches, set Z to 1, else set it to 0
|
||||||
xor_(al, 1);
|
xor_(al, 1);
|
||||||
break;
|
break;
|
||||||
case 1: // Both cmp registers match
|
case 1: // Both cmp registers match
|
||||||
cmp(word[statePointer + cmpRegXOffset], refX_refY_merged);
|
cmp(word[statePointer + cmpRegXOffset], refX_refY_merged);
|
||||||
break;
|
break;
|
||||||
case 2: // At least cmp.x matches
|
case 2: // At least cmp.x matches
|
||||||
cmp(byte[statePointer + cmpRegXOffset], refX);
|
cmp(byte[statePointer + cmpRegXOffset], refX);
|
||||||
break;
|
break;
|
||||||
default: // At least cmp.y matches
|
default: // At least cmp.y matches
|
||||||
cmp(byte[statePointer + cmpRegYOffset], refY);
|
cmp(byte[statePointer + cmpRegYOffset], refY);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderEmitter::checkBoolUniform(const PICAShader& shader, u32 instruction) {
|
void ShaderEmitter::checkBoolUniform(const PICAShader& shader, u32 instruction) {
|
||||||
const u32 bit = getBits<22, 4>(instruction); // Bit of the bool uniform to check
|
const u32 bit = getBits<22, 4>(instruction); // Bit of the bool uniform to check
|
||||||
const uintptr_t boolUniformOffset = uintptr_t(&shader.boolUniform) - uintptr_t(&shader);
|
const uintptr_t boolUniformOffset = uintptr_t(&shader.boolUniform) - uintptr_t(&shader);
|
||||||
|
|
||||||
test(word[statePointer + boolUniformOffset], 1 << bit);
|
test(word[statePointer + boolUniformOffset], 1 << bit);
|
||||||
|
@ -450,7 +458,7 @@ void ShaderEmitter::recMOV(const PICAShader& shader, u32 instruction) {
|
||||||
const u32 idx = getBits<19, 2>(instruction);
|
const u32 idx = getBits<19, 2>(instruction);
|
||||||
const u32 dest = getBits<21, 5>(instruction);
|
const u32 dest = getBits<21, 5>(instruction);
|
||||||
|
|
||||||
loadRegister<1>(src1_xmm, shader, src, idx, operandDescriptor); // Load source 1 into scratch1
|
loadRegister<1>(src1_xmm, shader, src, idx, operandDescriptor); // Load source 1 into scratch1
|
||||||
storeRegister(src1_xmm, shader, dest, operandDescriptor);
|
storeRegister(src1_xmm, shader, dest, operandDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -460,12 +468,12 @@ void ShaderEmitter::recFLR(const PICAShader& shader, u32 instruction) {
|
||||||
const u32 idx = getBits<19, 2>(instruction);
|
const u32 idx = getBits<19, 2>(instruction);
|
||||||
const u32 dest = getBits<21, 5>(instruction);
|
const u32 dest = getBits<21, 5>(instruction);
|
||||||
|
|
||||||
loadRegister<1>(src1_xmm, shader, src, idx, operandDescriptor); // Load source 1 into scratch1
|
loadRegister<1>(src1_xmm, shader, src, idx, operandDescriptor); // Load source 1 into scratch1
|
||||||
if (haveSSE4_1) {
|
if (haveSSE4_1) {
|
||||||
roundps(src1_xmm, src1_xmm, _MM_FROUND_FLOOR);
|
roundps(src1_xmm, src1_xmm, _MM_FROUND_FLOOR);
|
||||||
} else {
|
} else {
|
||||||
cvttps2dq(src1_xmm, src1_xmm); // Truncate and convert to integer
|
cvttps2dq(src1_xmm, src1_xmm); // Truncate and convert to integer
|
||||||
cvtdq2ps(src1_xmm, src1_xmm); // Convert from integer back to float
|
cvtdq2ps(src1_xmm, src1_xmm); // Convert from integer back to float
|
||||||
}
|
}
|
||||||
|
|
||||||
storeRegister(src1_xmm, shader, dest, operandDescriptor);
|
storeRegister(src1_xmm, shader, dest, operandDescriptor);
|
||||||
|
@ -476,71 +484,69 @@ void ShaderEmitter::recMOVA(const PICAShader& shader, u32 instruction) {
|
||||||
const u32 src = getBits<12, 7>(instruction);
|
const u32 src = getBits<12, 7>(instruction);
|
||||||
const u32 idx = getBits<19, 2>(instruction);
|
const u32 idx = getBits<19, 2>(instruction);
|
||||||
|
|
||||||
const bool writeX = getBit<3>(operandDescriptor); // Should we write the x component of the address register?
|
const bool writeX = getBit<3>(operandDescriptor); // Should we write the x component of the address register?
|
||||||
const bool writeY = getBit<2>(operandDescriptor);
|
const bool writeY = getBit<2>(operandDescriptor);
|
||||||
|
|
||||||
static_assert(sizeof(shader.addrRegister) == 2 * sizeof(s32)); // Assert that the address register is 2 s32s
|
static_assert(sizeof(shader.addrRegister) == 2 * sizeof(s32)); // Assert that the address register is 2 s32s
|
||||||
const uintptr_t addrRegisterOffset = uintptr_t(&shader.addrRegister[0]) - uintptr_t(&shader);
|
const uintptr_t addrRegisterOffset = uintptr_t(&shader.addrRegister[0]) - uintptr_t(&shader);
|
||||||
const uintptr_t addrRegisterYOffset = addrRegisterOffset + sizeof(shader.addrRegister[0]);
|
const uintptr_t addrRegisterYOffset = addrRegisterOffset + sizeof(shader.addrRegister[0]);
|
||||||
|
|
||||||
// If no register is being written to then it is a nop. Probably not common but whatever
|
// If no register is being written to then it is a nop. Probably not common but whatever
|
||||||
if (!writeX && !writeY) return;
|
if (!writeX && !writeY) return;
|
||||||
loadRegister<1>(src1_xmm, shader, src, idx, operandDescriptor); // Load source 1 into scratch1
|
loadRegister<1>(src1_xmm, shader, src, idx, operandDescriptor); // Load source 1 into scratch1
|
||||||
|
|
||||||
// Write both
|
// Write both
|
||||||
if (writeX && writeY) {
|
if (writeX && writeY) {
|
||||||
cvttps2dq(scratch1, src1_xmm); // Convert all lanes of src1 with truncation
|
cvttps2dq(scratch1, src1_xmm); // Convert all lanes of src1 with truncation
|
||||||
movsd(qword[statePointer + addrRegisterOffset], scratch1); // Write back bottom 2 to addr register x and ys
|
movsd(qword[statePointer + addrRegisterOffset], scratch1); // Write back bottom 2 to addr register x and ys
|
||||||
}
|
} else if (writeX) {
|
||||||
else if (writeX) {
|
cvttss2si(eax, src1_xmm); // Convert bottom lane
|
||||||
cvttss2si(eax, src1_xmm); // Convert bottom lane
|
mov(dword[statePointer + addrRegisterOffset], eax); // Write it back
|
||||||
mov(dword[statePointer + addrRegisterOffset], eax); // Write it back
|
} else if (writeY) {
|
||||||
}
|
psrldq(src1_xmm, sizeof(float)); // Shift y component to bottom lane
|
||||||
else if (writeY) {
|
cvttss2si(eax, src1_xmm); // Convert bottom lane
|
||||||
psrldq(src1_xmm, sizeof(float)); // Shift y component to bottom lane
|
mov(dword[statePointer + addrRegisterYOffset], eax); // Write it back to y component
|
||||||
cvttss2si(eax, src1_xmm); // Convert bottom lane
|
|
||||||
mov(dword[statePointer + addrRegisterYOffset], eax); // Write it back to y component
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderEmitter::recADD(const PICAShader& shader, u32 instruction) {
|
void ShaderEmitter::recADD(const PICAShader& shader, u32 instruction) {
|
||||||
const u32 operandDescriptor = shader.operandDescriptors[instruction & 0x7f];
|
const u32 operandDescriptor = shader.operandDescriptors[instruction & 0x7f];
|
||||||
const u32 src1 = getBits<12, 7>(instruction);
|
const u32 src1 = getBits<12, 7>(instruction);
|
||||||
const u32 src2 = getBits<7, 5>(instruction); // src2 coming first because PICA moment
|
const u32 src2 = getBits<7, 5>(instruction); // src2 coming first because PICA moment
|
||||||
const u32 idx = getBits<19, 2>(instruction);
|
const u32 idx = getBits<19, 2>(instruction);
|
||||||
const u32 dest = getBits<21, 5>(instruction);
|
const u32 dest = getBits<21, 5>(instruction);
|
||||||
|
|
||||||
loadRegister<1>(src1_xmm, shader, src1, idx, operandDescriptor);
|
loadRegister<1>(src1_xmm, shader, src1, idx, operandDescriptor);
|
||||||
loadRegister<2>(src2_xmm, shader, src2, 0, operandDescriptor);
|
loadRegister<2>(src2_xmm, shader, src2, 0, operandDescriptor);
|
||||||
addps(src1_xmm, src2_xmm); // Dot product between the 2 register
|
addps(src1_xmm, src2_xmm); // Dot product between the 2 register
|
||||||
storeRegister(src1_xmm, shader, dest, operandDescriptor);
|
storeRegister(src1_xmm, shader, dest, operandDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderEmitter::recDP3(const PICAShader& shader, u32 instruction) {
|
void ShaderEmitter::recDP3(const PICAShader& shader, u32 instruction) {
|
||||||
const u32 operandDescriptor = shader.operandDescriptors[instruction & 0x7f];
|
const u32 operandDescriptor = shader.operandDescriptors[instruction & 0x7f];
|
||||||
const u32 src1 = getBits<12, 7>(instruction);
|
const u32 src1 = getBits<12, 7>(instruction);
|
||||||
const u32 src2 = getBits<7, 5>(instruction); // src2 coming first because PICA moment
|
const u32 src2 = getBits<7, 5>(instruction); // src2 coming first because PICA moment
|
||||||
const u32 idx = getBits<19, 2>(instruction);
|
const u32 idx = getBits<19, 2>(instruction);
|
||||||
const u32 dest = getBits<21, 5>(instruction);
|
const u32 dest = getBits<21, 5>(instruction);
|
||||||
|
|
||||||
// TODO: Safe multiplication equivalent (Multiplication is not IEEE compliant on the PICA)
|
// TODO: Safe multiplication equivalent (Multiplication is not IEEE compliant on the PICA)
|
||||||
loadRegister<1>(src1_xmm, shader, src1, idx, operandDescriptor);
|
loadRegister<1>(src1_xmm, shader, src1, idx, operandDescriptor);
|
||||||
loadRegister<2>(src2_xmm, shader, src2, 0, operandDescriptor);
|
loadRegister<2>(src2_xmm, shader, src2, 0, operandDescriptor);
|
||||||
dpps(src1_xmm, src2_xmm, 0b01111111); // 3-lane dot product between the 2 registers, store the result in all lanes of scratch1 similarly to PICA
|
dpps(src1_xmm, src2_xmm, 0b01111111); // 3-lane dot product between the 2 registers, store the result in all lanes of scratch1 similarly to PICA
|
||||||
storeRegister(src1_xmm, shader, dest, operandDescriptor);
|
storeRegister(src1_xmm, shader, dest, operandDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderEmitter::recDP4(const PICAShader& shader, u32 instruction) {
|
void ShaderEmitter::recDP4(const PICAShader& shader, u32 instruction) {
|
||||||
const u32 operandDescriptor = shader.operandDescriptors[instruction & 0x7f];
|
const u32 operandDescriptor = shader.operandDescriptors[instruction & 0x7f];
|
||||||
const u32 src1 = getBits<12, 7>(instruction);
|
const u32 src1 = getBits<12, 7>(instruction);
|
||||||
const u32 src2 = getBits<7, 5>(instruction); // src2 coming first because PICA moment
|
const u32 src2 = getBits<7, 5>(instruction); // src2 coming first because PICA moment
|
||||||
const u32 idx = getBits<19, 2>(instruction);
|
const u32 idx = getBits<19, 2>(instruction);
|
||||||
const u32 dest = getBits<21, 5>(instruction);
|
const u32 dest = getBits<21, 5>(instruction);
|
||||||
|
|
||||||
// TODO: Safe multiplication equivalent (Multiplication is not IEEE compliant on the PICA)
|
// TODO: Safe multiplication equivalent (Multiplication is not IEEE compliant on the PICA)
|
||||||
loadRegister<1>(src1_xmm, shader, src1, idx, operandDescriptor);
|
loadRegister<1>(src1_xmm, shader, src1, idx, operandDescriptor);
|
||||||
loadRegister<2>(src2_xmm, shader, src2, 0, operandDescriptor);
|
loadRegister<2>(src2_xmm, shader, src2, 0, operandDescriptor);
|
||||||
dpps(src1_xmm, src2_xmm, 0b11111111); // 4-lane dot product between the 2 registers, store the result in all lanes of scratch1 similarly to PICA
|
dpps(src1_xmm, src2_xmm, 0b11111111); // 4-lane dot product between the 2 registers, store the result in all lanes of scratch1 similarly to PICA
|
||||||
storeRegister(src1_xmm, shader, dest, operandDescriptor);
|
storeRegister(src1_xmm, shader, dest, operandDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -573,7 +579,7 @@ void ShaderEmitter::recDPH(const PICAShader& shader, u32 instruction) {
|
||||||
void ShaderEmitter::recMAX(const PICAShader& shader, u32 instruction) {
|
void ShaderEmitter::recMAX(const PICAShader& shader, u32 instruction) {
|
||||||
const u32 operandDescriptor = shader.operandDescriptors[instruction & 0x7f];
|
const u32 operandDescriptor = shader.operandDescriptors[instruction & 0x7f];
|
||||||
const u32 src1 = getBits<12, 7>(instruction);
|
const u32 src1 = getBits<12, 7>(instruction);
|
||||||
const u32 src2 = getBits<7, 5>(instruction); // src2 coming first because PICA moment
|
const u32 src2 = getBits<7, 5>(instruction); // src2 coming first because PICA moment
|
||||||
const u32 idx = getBits<19, 2>(instruction);
|
const u32 idx = getBits<19, 2>(instruction);
|
||||||
const u32 dest = getBits<21, 5>(instruction);
|
const u32 dest = getBits<21, 5>(instruction);
|
||||||
|
|
||||||
|
@ -586,7 +592,7 @@ void ShaderEmitter::recMAX(const PICAShader& shader, u32 instruction) {
|
||||||
void ShaderEmitter::recMIN(const PICAShader& shader, u32 instruction) {
|
void ShaderEmitter::recMIN(const PICAShader& shader, u32 instruction) {
|
||||||
const u32 operandDescriptor = shader.operandDescriptors[instruction & 0x7f];
|
const u32 operandDescriptor = shader.operandDescriptors[instruction & 0x7f];
|
||||||
const u32 src1 = getBits<12, 7>(instruction);
|
const u32 src1 = getBits<12, 7>(instruction);
|
||||||
const u32 src2 = getBits<7, 5>(instruction); // src2 coming first because PICA moment
|
const u32 src2 = getBits<7, 5>(instruction); // src2 coming first because PICA moment
|
||||||
const u32 idx = getBits<19, 2>(instruction);
|
const u32 idx = getBits<19, 2>(instruction);
|
||||||
const u32 dest = getBits<21, 5>(instruction);
|
const u32 dest = getBits<21, 5>(instruction);
|
||||||
|
|
||||||
|
@ -599,7 +605,7 @@ void ShaderEmitter::recMIN(const PICAShader& shader, u32 instruction) {
|
||||||
void ShaderEmitter::recMUL(const PICAShader& shader, u32 instruction) {
|
void ShaderEmitter::recMUL(const PICAShader& shader, u32 instruction) {
|
||||||
const u32 operandDescriptor = shader.operandDescriptors[instruction & 0x7f];
|
const u32 operandDescriptor = shader.operandDescriptors[instruction & 0x7f];
|
||||||
const u32 src1 = getBits<12, 7>(instruction);
|
const u32 src1 = getBits<12, 7>(instruction);
|
||||||
const u32 src2 = getBits<7, 5>(instruction); // src2 coming first because PICA moment
|
const u32 src2 = getBits<7, 5>(instruction); // src2 coming first because PICA moment
|
||||||
const u32 idx = getBits<19, 2>(instruction);
|
const u32 idx = getBits<19, 2>(instruction);
|
||||||
const u32 dest = getBits<21, 5>(instruction);
|
const u32 dest = getBits<21, 5>(instruction);
|
||||||
|
|
||||||
|
@ -617,13 +623,13 @@ void ShaderEmitter::recRCP(const PICAShader& shader, u32 instruction) {
|
||||||
const u32 dest = getBits<21, 5>(instruction);
|
const u32 dest = getBits<21, 5>(instruction);
|
||||||
const u32 writeMask = operandDescriptor & 0xf;
|
const u32 writeMask = operandDescriptor & 0xf;
|
||||||
|
|
||||||
loadRegister<1>(src1_xmm, shader, src, idx, operandDescriptor); // Load source 1 into scratch1
|
loadRegister<1>(src1_xmm, shader, src, idx, operandDescriptor); // Load source 1 into scratch1
|
||||||
rcpss(src1_xmm, src1_xmm); // Compute rcp approximation
|
rcpss(src1_xmm, src1_xmm); // Compute rcp approximation
|
||||||
|
|
||||||
// If we only write back the x component to the result, we needn't perform a shuffle to do res = res.xxxx
|
// If we only write back the x component to the result, we needn't perform a shuffle to do res = res.xxxx
|
||||||
// Otherwise we do
|
// Otherwise we do
|
||||||
if (writeMask != 0x8) {// Copy bottom lane to all lanes if we're not simply writing back x
|
if (writeMask != 0x8) { // Copy bottom lane to all lanes if we're not simply writing back x
|
||||||
shufps(src1_xmm, src1_xmm, 0); // src1_xmm = src1_xmm.xxxx
|
shufps(src1_xmm, src1_xmm, 0); // src1_xmm = src1_xmm.xxxx
|
||||||
}
|
}
|
||||||
|
|
||||||
storeRegister(src1_xmm, shader, dest, operandDescriptor);
|
storeRegister(src1_xmm, shader, dest, operandDescriptor);
|
||||||
|
@ -636,13 +642,13 @@ void ShaderEmitter::recRSQ(const PICAShader& shader, u32 instruction) {
|
||||||
const u32 dest = getBits<21, 5>(instruction);
|
const u32 dest = getBits<21, 5>(instruction);
|
||||||
const u32 writeMask = operandDescriptor & 0xf;
|
const u32 writeMask = operandDescriptor & 0xf;
|
||||||
|
|
||||||
loadRegister<1>(src1_xmm, shader, src, idx, operandDescriptor); // Load source 1 into scratch1
|
loadRegister<1>(src1_xmm, shader, src, idx, operandDescriptor); // Load source 1 into scratch1
|
||||||
rsqrtss(src1_xmm, src1_xmm); // Compute rsqrt approximation
|
rsqrtss(src1_xmm, src1_xmm); // Compute rsqrt approximation
|
||||||
|
|
||||||
// If we only write back the x component to the result, we needn't perform a shuffle to do res = res.xxxx
|
// If we only write back the x component to the result, we needn't perform a shuffle to do res = res.xxxx
|
||||||
// Otherwise we do
|
// Otherwise we do
|
||||||
if (writeMask != 0x8) {// Copy bottom lane to all lanes if we're not simply writing back x
|
if (writeMask != 0x8) { // Copy bottom lane to all lanes if we're not simply writing back x
|
||||||
shufps(src1_xmm, src1_xmm, 0); // src1_xmm = src1_xmm.xxxx
|
shufps(src1_xmm, src1_xmm, 0); // src1_xmm = src1_xmm.xxxx
|
||||||
}
|
}
|
||||||
|
|
||||||
storeRegister(src1_xmm, shader, dest, operandDescriptor);
|
storeRegister(src1_xmm, shader, dest, operandDescriptor);
|
||||||
|
@ -668,7 +674,7 @@ void ShaderEmitter::recMAD(const PICAShader& shader, u32 instruction) {
|
||||||
vfmadd213ps(src1_xmm, src2_xmm, src3_xmm);
|
vfmadd213ps(src1_xmm, src2_xmm, src3_xmm);
|
||||||
storeRegister(src1_xmm, shader, dest, operandDescriptor);
|
storeRegister(src1_xmm, shader, dest, operandDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we don't have FMA3, do a multiplication and addition
|
// If we don't have FMA3, do a multiplication and addition
|
||||||
else {
|
else {
|
||||||
// Multiply src1 * src2
|
// Multiply src1 * src2
|
||||||
|
@ -712,7 +718,7 @@ void ShaderEmitter::recSGE(const PICAShader& shader, u32 instruction) {
|
||||||
|
|
||||||
loadRegister<1>(src1_xmm, shader, src1, isSGEI ? 0 : idx, operandDescriptor);
|
loadRegister<1>(src1_xmm, shader, src1, isSGEI ? 0 : idx, operandDescriptor);
|
||||||
loadRegister<2>(src2_xmm, shader, src2, isSGEI ? idx : 0, operandDescriptor);
|
loadRegister<2>(src2_xmm, shader, src2, isSGEI ? idx : 0, operandDescriptor);
|
||||||
|
|
||||||
// SSE does not have a cmpgeps instruction so we turn src1 >= src2 to src2 <= src1, result in src2
|
// SSE does not have a cmpgeps instruction so we turn src1 >= src2 to src2 <= src1, result in src2
|
||||||
cmpleps(src2_xmm, src1_xmm);
|
cmpleps(src2_xmm, src1_xmm);
|
||||||
andps(src2_xmm, xword[rip + onesVector]);
|
andps(src2_xmm, xword[rip + onesVector]);
|
||||||
|
@ -722,7 +728,7 @@ void ShaderEmitter::recSGE(const PICAShader& shader, u32 instruction) {
|
||||||
void ShaderEmitter::recCMP(const PICAShader& shader, u32 instruction) {
|
void ShaderEmitter::recCMP(const PICAShader& shader, u32 instruction) {
|
||||||
const u32 operandDescriptor = shader.operandDescriptors[instruction & 0x7f];
|
const u32 operandDescriptor = shader.operandDescriptors[instruction & 0x7f];
|
||||||
const u32 src1 = getBits<12, 7>(instruction);
|
const u32 src1 = getBits<12, 7>(instruction);
|
||||||
const u32 src2 = getBits<7, 5>(instruction); // src2 coming first because PICA moment
|
const u32 src2 = getBits<7, 5>(instruction); // src2 coming first because PICA moment
|
||||||
const u32 idx = getBits<19, 2>(instruction);
|
const u32 idx = getBits<19, 2>(instruction);
|
||||||
const u32 cmpY = getBits<21, 3>(instruction);
|
const u32 cmpY = getBits<21, 3>(instruction);
|
||||||
const u32 cmpX = getBits<24, 3>(instruction);
|
const u32 cmpX = getBits<24, 3>(instruction);
|
||||||
|
@ -731,20 +737,10 @@ void ShaderEmitter::recCMP(const PICAShader& shader, u32 instruction) {
|
||||||
loadRegister<2>(src2_xmm, shader, src2, 0, operandDescriptor);
|
loadRegister<2>(src2_xmm, shader, src2, 0, operandDescriptor);
|
||||||
|
|
||||||
// Condition codes for cmpps
|
// Condition codes for cmpps
|
||||||
enum : u8 {
|
enum : u8 { CMP_EQ = 0, CMP_LT = 1, CMP_LE = 2, CMP_UNORD = 3, CMP_NEQ = 4, CMP_NLT = 5, CMP_NLE = 6, CMP_ORD = 7, CMP_TRUE = 15 };
|
||||||
CMP_EQ = 0,
|
|
||||||
CMP_LT = 1,
|
|
||||||
CMP_LE = 2,
|
|
||||||
CMP_UNORD = 3,
|
|
||||||
CMP_NEQ = 4,
|
|
||||||
CMP_NLT = 5,
|
|
||||||
CMP_NLE = 6,
|
|
||||||
CMP_ORD = 7,
|
|
||||||
CMP_TRUE = 15
|
|
||||||
};
|
|
||||||
|
|
||||||
// Map from PICA condition codes (used as index) to x86 condition codes
|
// Map from PICA condition codes (used as index) to x86 condition codes
|
||||||
static constexpr std::array<u8, 8> conditionCodes = { CMP_EQ, CMP_NEQ, CMP_LT, CMP_LE, CMP_LT, CMP_LE, CMP_TRUE, CMP_TRUE };
|
static constexpr std::array<u8, 8> conditionCodes = {CMP_EQ, CMP_NEQ, CMP_LT, CMP_LE, CMP_LT, CMP_LE, CMP_TRUE, CMP_TRUE};
|
||||||
|
|
||||||
// SSE does not offer GT or GE comparisons in the cmpps instruction, so we need to flip the left and right operands in that case and use LT/LE
|
// SSE does not offer GT or GE comparisons in the cmpps instruction, so we need to flip the left and right operands in that case and use LT/LE
|
||||||
const bool invertX = (cmpX == 4 || cmpX == 5);
|
const bool invertX = (cmpX == 4 || cmpX == 5);
|
||||||
|
@ -757,37 +753,37 @@ void ShaderEmitter::recCMP(const PICAShader& shader, u32 instruction) {
|
||||||
const u8 compareFuncX = conditionCodes[cmpX];
|
const u8 compareFuncX = conditionCodes[cmpX];
|
||||||
const u8 compareFuncY = conditionCodes[cmpY];
|
const u8 compareFuncY = conditionCodes[cmpY];
|
||||||
|
|
||||||
static_assert(sizeof(shader.cmpRegister[0]) == 1 && sizeof(shader.cmpRegister) == 2); // The code below relies on bool being 1 byte exactly
|
static_assert(sizeof(shader.cmpRegister[0]) == 1 && sizeof(shader.cmpRegister) == 2); // The code below relies on bool being 1 byte exactly
|
||||||
const size_t cmpRegXOffset = uintptr_t(&shader.cmpRegister[0]) - uintptr_t(&shader);
|
const size_t cmpRegXOffset = uintptr_t(&shader.cmpRegister[0]) - uintptr_t(&shader);
|
||||||
const size_t cmpRegYOffset = cmpRegXOffset + sizeof(bool);
|
const size_t cmpRegYOffset = cmpRegXOffset + sizeof(bool);
|
||||||
|
|
||||||
// Cmp x and y are the same compare function, we can use a single cmp instruction
|
// Cmp x and y are the same compare function, we can use a single cmp instruction
|
||||||
if (cmpX == cmpY) {
|
if (cmpX == cmpY) {
|
||||||
cmpps(lhs_x, rhs_x, compareFuncX);
|
cmpps(lhs_x, rhs_x, compareFuncX);
|
||||||
movq(rax, lhs_x); // Move both comparison results to rax
|
movq(rax, lhs_x); // Move both comparison results to rax
|
||||||
test(eax, eax); // Check bottom 32 bits first
|
test(eax, eax); // Check bottom 32 bits first
|
||||||
setne(byte[statePointer + cmpRegXOffset]); // set cmp.x
|
setne(byte[statePointer + cmpRegXOffset]); // set cmp.x
|
||||||
|
|
||||||
shr(rax, 32); // Check top 32 bits (shr will set the zero flag properly)
|
shr(rax, 32); // Check top 32 bits (shr will set the zero flag properly)
|
||||||
setne(byte[statePointer + cmpRegYOffset]); // set cmp.y
|
setne(byte[statePointer + cmpRegYOffset]); // set cmp.y
|
||||||
} else {
|
} else {
|
||||||
if (haveAVX) {
|
if (haveAVX) {
|
||||||
vcmpps(scratch1, lhs_x, rhs_x, compareFuncX); // Perform comparison for X component and store result in scratch1
|
vcmpps(scratch1, lhs_x, rhs_x, compareFuncX); // Perform comparison for X component and store result in scratch1
|
||||||
vcmpps(scratch2, lhs_y, rhs_y, compareFuncY); // Perform comparison for Y component and store result in scratch2
|
vcmpps(scratch2, lhs_y, rhs_y, compareFuncY); // Perform comparison for Y component and store result in scratch2
|
||||||
} else {
|
} else {
|
||||||
movaps(scratch1, lhs_x); // Copy the left hand operands to temp registers
|
movaps(scratch1, lhs_x); // Copy the left hand operands to temp registers
|
||||||
movaps(scratch2, lhs_y);
|
movaps(scratch2, lhs_y);
|
||||||
|
|
||||||
cmpps(scratch1, rhs_x, compareFuncX); // Perform the compares
|
cmpps(scratch1, rhs_x, compareFuncX); // Perform the compares
|
||||||
cmpps(scratch2, rhs_y, compareFuncY);
|
cmpps(scratch2, rhs_y, compareFuncY);
|
||||||
}
|
}
|
||||||
|
|
||||||
movd(eax, scratch1); // Move results to eax for X and edx for Y
|
movd(eax, scratch1); // Move results to eax for X and edx for Y
|
||||||
movq(rdx, scratch2);
|
movq(rdx, scratch2);
|
||||||
|
|
||||||
test(eax, eax); // Write back results with setne
|
test(eax, eax); // Write back results with setne
|
||||||
setne(byte[statePointer + cmpRegXOffset]);
|
setne(byte[statePointer + cmpRegXOffset]);
|
||||||
shr(rdx, 32); // We want the y component for the second comparison. This shift will set zero flag to 0 if the comparison is true
|
shr(rdx, 32); // We want the y component for the second comparison. This shift will set zero flag to 0 if the comparison is true
|
||||||
setne(byte[statePointer + cmpRegYOffset]);
|
setne(byte[statePointer + cmpRegYOffset]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -807,10 +803,10 @@ void ShaderEmitter::recIFC(const PICAShader& shader, u32 instruction) {
|
||||||
jnz(elseBlock, T_NEAR);
|
jnz(elseBlock, T_NEAR);
|
||||||
compileUntil(shader, dest);
|
compileUntil(shader, dest);
|
||||||
|
|
||||||
if (num == 0) { // Else block is empty,
|
if (num == 0) { // Else block is empty,
|
||||||
L(elseBlock);
|
L(elseBlock);
|
||||||
} else { // Else block is NOT empty
|
} else { // Else block is NOT empty
|
||||||
jmp(endIf, T_NEAR); // Skip executing the else branch if the if branch was ran
|
jmp(endIf, T_NEAR); // Skip executing the else branch if the if branch was ran
|
||||||
L(elseBlock);
|
L(elseBlock);
|
||||||
compileUntil(shader, dest + num);
|
compileUntil(shader, dest + num);
|
||||||
L(endIf);
|
L(endIf);
|
||||||
|
@ -832,10 +828,10 @@ void ShaderEmitter::recIFU(const PICAShader& shader, u32 instruction) {
|
||||||
jz(elseBlock, T_NEAR);
|
jz(elseBlock, T_NEAR);
|
||||||
compileUntil(shader, dest);
|
compileUntil(shader, dest);
|
||||||
|
|
||||||
if (num == 0) { // Else block is empty,
|
if (num == 0) { // Else block is empty,
|
||||||
L(elseBlock);
|
L(elseBlock);
|
||||||
} else { // Else block is NOT empty
|
} else { // Else block is NOT empty
|
||||||
jmp(endIf, T_NEAR); // Skip executing the else branch if the if branch was ran
|
jmp(endIf, T_NEAR); // Skip executing the else branch if the if branch was ran
|
||||||
L(elseBlock);
|
L(elseBlock);
|
||||||
compileUntil(shader, dest + num);
|
compileUntil(shader, dest + num);
|
||||||
L(endIf);
|
L(endIf);
|
||||||
|
@ -888,7 +884,7 @@ void ShaderEmitter::recJMPC(const PICAShader& shader, u32 instruction) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderEmitter::recJMPU(const PICAShader& shader, u32 instruction) {
|
void ShaderEmitter::recJMPU(const PICAShader& shader, u32 instruction) {
|
||||||
bool jumpIfFalse = instruction & 1; // If the LSB is 0 we want to compare to true, otherwise compare to false
|
bool jumpIfFalse = instruction & 1; // If the LSB is 0 we want to compare to true, otherwise compare to false
|
||||||
const u32 dest = getBits<10, 12>(instruction);
|
const u32 dest = getBits<10, 12>(instruction);
|
||||||
|
|
||||||
Label& l = instructionLabels[dest];
|
Label& l = instructionLabels[dest];
|
||||||
|
@ -922,13 +918,13 @@ void ShaderEmitter::recLOOP(const PICAShader& shader, u32 instruction) {
|
||||||
// Offset of the loop register
|
// Offset of the loop register
|
||||||
const uintptr_t loopRegOffset = uintptr_t(&shader.loopCounter) - uintptr_t(&shader);
|
const uintptr_t loopRegOffset = uintptr_t(&shader.loopCounter) - uintptr_t(&shader);
|
||||||
|
|
||||||
movzx(eax, byte[statePointer + uniformOffset]); // eax = loop iteration count
|
movzx(eax, byte[statePointer + uniformOffset]); // eax = loop iteration count
|
||||||
movzx(ecx, byte[statePointer + uniformOffset + sizeof(u8)]); // ecx = initial loop counter value
|
movzx(ecx, byte[statePointer + uniformOffset + sizeof(u8)]); // ecx = initial loop counter value
|
||||||
movzx(edx, byte[statePointer + uniformOffset + 2 * sizeof(u8)]); // edx = loop increment
|
movzx(edx, byte[statePointer + uniformOffset + 2 * sizeof(u8)]); // edx = loop increment
|
||||||
|
|
||||||
|
add(eax, 1); // The iteration count is actually uniform.x + 1
|
||||||
|
mov(dword[statePointer + loopRegOffset], ecx); // Set loop counter
|
||||||
|
|
||||||
add(eax, 1); // The iteration count is actually uniform.x + 1
|
|
||||||
mov(dword[statePointer + loopRegOffset], ecx); // Set loop counter
|
|
||||||
|
|
||||||
// TODO: This might break if an instruction in a loop decides to yield...
|
// TODO: This might break if an instruction in a loop decides to yield...
|
||||||
push(rax); // Push loop iteration counter
|
push(rax); // Push loop iteration counter
|
||||||
push(rdx); // Push loop increment
|
push(rdx); // Push loop increment
|
||||||
|
@ -957,8 +953,8 @@ void ShaderEmitter::recLG2(const PICAShader& shader, u32 instruction) {
|
||||||
const u32 writeMask = getBits<0, 4>(operandDescriptor);
|
const u32 writeMask = getBits<0, 4>(operandDescriptor);
|
||||||
|
|
||||||
loadRegister<1>(src1_xmm, shader, src, idx, operandDescriptor);
|
loadRegister<1>(src1_xmm, shader, src, idx, operandDescriptor);
|
||||||
call(log2Func); // Result is output in src1_xmm
|
call(log2Func); // Result is output in src1_xmm
|
||||||
|
|
||||||
if (writeMask != 0x8) { // Copy bottom lane to all lanes if we're not simply writing back x
|
if (writeMask != 0x8) { // Copy bottom lane to all lanes if we're not simply writing back x
|
||||||
shufps(src1_xmm, src1_xmm, 0); // src1_xmm = src1_xmm.xxxx
|
shufps(src1_xmm, src1_xmm, 0); // src1_xmm = src1_xmm.xxxx
|
||||||
}
|
}
|
||||||
|
@ -1147,7 +1143,7 @@ Xbyak::Label ShaderEmitter::emitExp2Func() {
|
||||||
align(16);
|
align(16);
|
||||||
L(subroutine);
|
L(subroutine);
|
||||||
|
|
||||||
// Handle edge cases
|
// HandleType edge cases
|
||||||
ucomiss(src1_xmm, src1_xmm);
|
ucomiss(src1_xmm, src1_xmm);
|
||||||
jp(retLabel);
|
jp(retLabel);
|
||||||
|
|
||||||
|
@ -1277,4 +1273,4 @@ void ShaderEmitter::emitPrintLog(const PICAShader& shaderUnit) {
|
||||||
pop(rbp);
|
pop(rbp);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -15,6 +15,9 @@
|
||||||
#ifdef PANDA3DS_ENABLE_VULKAN
|
#ifdef PANDA3DS_ENABLE_VULKAN
|
||||||
#include "renderer_vk/renderer_vk.hpp"
|
#include "renderer_vk/renderer_vk.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef PANDA3DS_ENABLE_METAL
|
||||||
|
#include "renderer_mtl/renderer_mtl.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
constexpr u32 topScreenWidth = 240;
|
constexpr u32 topScreenWidth = 240;
|
||||||
constexpr u32 topScreenHeight = 400;
|
constexpr u32 topScreenHeight = 400;
|
||||||
|
@ -52,6 +55,12 @@ GPU::GPU(Memory& mem, EmulatorConfig& config) : mem(mem), config(config) {
|
||||||
renderer.reset(new RendererVK(*this, regs, externalRegs));
|
renderer.reset(new RendererVK(*this, regs, externalRegs));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef PANDA3DS_ENABLE_METAL
|
||||||
|
case RendererType::Metal: {
|
||||||
|
renderer.reset(new RendererMTL(*this, regs, externalRegs));
|
||||||
|
break;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
default: {
|
default: {
|
||||||
Helpers::panic("Rendering backend not supported: %s", Renderer::typeToString(config.rendererType));
|
Helpers::panic("Rendering backend not supported: %s", Renderer::typeToString(config.rendererType));
|
||||||
|
@ -355,7 +364,7 @@ PICA::Vertex GPU::getImmediateModeVertex() {
|
||||||
|
|
||||||
// Run VS and return vertex data. TODO: Don't hardcode offsets for each attribute
|
// Run VS and return vertex data. TODO: Don't hardcode offsets for each attribute
|
||||||
shaderUnit.vs.run();
|
shaderUnit.vs.run();
|
||||||
|
|
||||||
// Map shader outputs to fixed function properties
|
// Map shader outputs to fixed function properties
|
||||||
const u32 totalShaderOutputs = regs[PICA::InternalRegs::ShaderOutputCount] & 7;
|
const u32 totalShaderOutputs = regs[PICA::InternalRegs::ShaderOutputCount] & 7;
|
||||||
for (int i = 0; i < totalShaderOutputs; i++) {
|
for (int i = 0; i < totalShaderOutputs; i++) {
|
||||||
|
|
|
@ -232,7 +232,7 @@ void GPU::writeInternalReg(u32 index, u32 value, u32 mask) {
|
||||||
const u32 primType = getBits<8, 2>(primConfig);
|
const u32 primType = getBits<8, 2>(primConfig);
|
||||||
|
|
||||||
// If we've reached 3 verts, issue a draw call
|
// If we've reached 3 verts, issue a draw call
|
||||||
// Handle rendering depending on the primitive type
|
// HandleType rendering depending on the primitive type
|
||||||
if (immediateModeVertIndex == 3) {
|
if (immediateModeVertIndex == 3) {
|
||||||
renderer->drawVertices(PICA::PrimType::TriangleList, immediateModeVertices);
|
renderer->drawVertices(PICA::PrimType::TriangleList, immediateModeVertices);
|
||||||
|
|
||||||
|
|
|
@ -77,8 +77,8 @@ void PICAShader::run() {
|
||||||
default: Helpers::panic("Unimplemented PICA instruction %08X (Opcode = %02X)", instruction, opcode);
|
default: Helpers::panic("Unimplemented PICA instruction %08X (Opcode = %02X)", instruction, opcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle control flow statements. The ordering is important as the priority goes: LOOP > IF > CALL
|
// HandleType control flow statements. The ordering is important as the priority goes: LOOP > IF > CALL
|
||||||
// Handle loop
|
// HandleType loop
|
||||||
if (loopIndex != 0) {
|
if (loopIndex != 0) {
|
||||||
auto& loop = loopInfo[loopIndex - 1];
|
auto& loop = loopInfo[loopIndex - 1];
|
||||||
if (pc == loop.endingPC) { // Check if the loop needs to start over
|
if (pc == loop.endingPC) { // Check if the loop needs to start over
|
||||||
|
@ -91,7 +91,7 @@ void PICAShader::run() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle ifs
|
// HandleType ifs
|
||||||
if (ifIndex != 0) {
|
if (ifIndex != 0) {
|
||||||
auto& info = conditionalInfo[ifIndex - 1];
|
auto& info = conditionalInfo[ifIndex - 1];
|
||||||
if (pc == info.endingPC) { // Check if the IF block ended
|
if (pc == info.endingPC) { // Check if the IF block ended
|
||||||
|
@ -100,7 +100,7 @@ void PICAShader::run() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle calls
|
// HandleType calls
|
||||||
if (callIndex != 0) {
|
if (callIndex != 0) {
|
||||||
auto& info = callInfo[callIndex - 1];
|
auto& info = callInfo[callIndex - 1];
|
||||||
if (pc == info.endingPC) { // Check if the CALL block ended
|
if (pc == info.endingPC) { // Check if the CALL block ended
|
||||||
|
@ -753,4 +753,4 @@ void PICAShader::jmpu(u32 instruction) {
|
||||||
|
|
||||||
if (((boolUniform >> bit) & 1) == test) // Jump if the bool uniform is the value we want
|
if (((boolUniform >> bit) & 1) == test) // Jump if the bool uniform is the value we want
|
||||||
pc = dest;
|
pc = dest;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,34 +12,36 @@ static const char* arbitrationTypeToString(u32 type) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle Kernel::makeArbiter() {
|
HandleType Kernel::makeArbiter() {
|
||||||
if (arbiterCount >= appResourceLimits.maxAddressArbiters) {
|
if (arbiterCount >= appResourceLimits.maxAddressArbiters) {
|
||||||
Helpers::panic("Overflowed the number of address arbiters");
|
Helpers::panic("Overflowed the number of address arbiters");
|
||||||
}
|
}
|
||||||
arbiterCount++;
|
arbiterCount++;
|
||||||
|
|
||||||
Handle ret = makeObject(KernelObjectType::AddressArbiter);
|
HandleType ret = makeObject(KernelObjectType::AddressArbiter);
|
||||||
objects[ret].data = new AddressArbiter();
|
objects[ret].data = new AddressArbiter();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Result CreateAddressArbiter(Handle* arbiter)
|
// Result CreateAddressArbiter(HandleType* arbiter)
|
||||||
void Kernel::createAddressArbiter() {
|
void Kernel::createAddressArbiter() {
|
||||||
logSVC("CreateAddressArbiter\n");
|
logSVC("CreateAddressArbiter\n");
|
||||||
regs[0] = Result::Success;
|
regs[0] = Result::Success;
|
||||||
regs[1] = makeArbiter();
|
regs[1] = makeArbiter();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Result ArbitrateAddress(Handle arbiter, u32 addr, ArbitrationType type, s32 value, s64 nanoseconds)
|
// Result ArbitrateAddress(HandleType arbiter, u32 addr, ArbitrationType type, s32 value, s64 nanoseconds)
|
||||||
void Kernel::arbitrateAddress() {
|
void Kernel::arbitrateAddress() {
|
||||||
const Handle handle = regs[0];
|
const HandleType handle = regs[0];
|
||||||
const u32 address = regs[1];
|
const u32 address = regs[1];
|
||||||
const u32 type = regs[2];
|
const u32 type = regs[2];
|
||||||
const s32 value = s32(regs[3]);
|
const s32 value = s32(regs[3]);
|
||||||
const s64 ns = s64(u64(regs[4]) | (u64(regs[5]) << 32));
|
const s64 ns = s64(u64(regs[4]) | (u64(regs[5]) << 32));
|
||||||
|
|
||||||
logSVC("ArbitrateAddress(Handle = %X, address = %08X, type = %s, value = %d, ns = %lld)\n", handle, address,
|
logSVC(
|
||||||
arbitrationTypeToString(type), value, ns);
|
"ArbitrateAddress(HandleType = %X, address = %08X, type = %s, value = %d, ns = %lld)\n", handle, address, arbitrationTypeToString(type),
|
||||||
|
value, ns
|
||||||
|
);
|
||||||
|
|
||||||
const auto arbiter = getObject(handle, KernelObjectType::AddressArbiter);
|
const auto arbiter = getObject(handle, KernelObjectType::AddressArbiter);
|
||||||
if (arbiter == nullptr) [[unlikely]] {
|
if (arbiter == nullptr) [[unlikely]] {
|
||||||
|
@ -61,7 +63,7 @@ void Kernel::arbitrateAddress() {
|
||||||
switch (static_cast<ArbitrationType>(type)) {
|
switch (static_cast<ArbitrationType>(type)) {
|
||||||
// Puts this thread to sleep if word < value until another thread arbitrates the address using SIGNAL
|
// Puts this thread to sleep if word < value until another thread arbitrates the address using SIGNAL
|
||||||
case ArbitrationType::WaitIfLess: {
|
case ArbitrationType::WaitIfLess: {
|
||||||
s32 word = static_cast<s32>(mem.read32(address)); // Yes this is meant to be signed
|
s32 word = static_cast<s32>(mem.read32(address)); // Yes this is meant to be signed
|
||||||
if (word < value) {
|
if (word < value) {
|
||||||
sleepThreadOnArbiter(address);
|
sleepThreadOnArbiter(address);
|
||||||
}
|
}
|
||||||
|
@ -71,7 +73,7 @@ void Kernel::arbitrateAddress() {
|
||||||
// Puts this thread to sleep if word < value until another thread arbitrates the address using SIGNAL
|
// Puts this thread to sleep if word < value until another thread arbitrates the address using SIGNAL
|
||||||
// If the thread is put to sleep, the arbiter address is decremented
|
// If the thread is put to sleep, the arbiter address is decremented
|
||||||
case ArbitrationType::DecrementAndWaitIfLess: {
|
case ArbitrationType::DecrementAndWaitIfLess: {
|
||||||
s32 word = static_cast<s32>(mem.read32(address)); // Yes this is meant to be signed
|
s32 word = static_cast<s32>(mem.read32(address)); // Yes this is meant to be signed
|
||||||
if (word < value) {
|
if (word < value) {
|
||||||
mem.write32(address, word - 1);
|
mem.write32(address, word - 1);
|
||||||
sleepThreadOnArbiter(address);
|
sleepThreadOnArbiter(address);
|
||||||
|
@ -79,12 +81,9 @@ void Kernel::arbitrateAddress() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ArbitrationType::Signal:
|
case ArbitrationType::Signal: signalArbiter(address, value); break;
|
||||||
signalArbiter(address, value);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default: Helpers::panic("ArbitrateAddress: Unimplemented type %s", arbitrationTypeToString(type));
|
||||||
Helpers::panic("ArbitrateAddress: Unimplemented type %s", arbitrationTypeToString(type));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
requireReschedule();
|
requireReschedule();
|
||||||
|
@ -92,8 +91,9 @@ void Kernel::arbitrateAddress() {
|
||||||
|
|
||||||
// Signal up to "threadCount" threads waiting on the arbiter indicated by "waitingAddress"
|
// Signal up to "threadCount" threads waiting on the arbiter indicated by "waitingAddress"
|
||||||
void Kernel::signalArbiter(u32 waitingAddress, s32 threadCount) {
|
void Kernel::signalArbiter(u32 waitingAddress, s32 threadCount) {
|
||||||
if (threadCount == 0) [[unlikely]] return;
|
if (threadCount == 0) [[unlikely]]
|
||||||
s32 count = 0; // Number of threads we've woken up
|
return;
|
||||||
|
s32 count = 0; // Number of threads we've woken up
|
||||||
|
|
||||||
// Wake threads with the highest priority threads being woken up first
|
// Wake threads with the highest priority threads being woken up first
|
||||||
for (auto index : threadIndices) {
|
for (auto index : threadIndices) {
|
||||||
|
@ -106,4 +106,4 @@ void Kernel::signalArbiter(u32 waitingAddress, s32 threadCount) {
|
||||||
if (count == threadCount && threadCount > 0) break;
|
if (count == threadCount && threadCount > 0) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,10 +8,7 @@
|
||||||
#include "kernel.hpp"
|
#include "kernel.hpp"
|
||||||
|
|
||||||
namespace DirectoryOps {
|
namespace DirectoryOps {
|
||||||
enum : u32 {
|
enum : u32 { Read = 0x08010042, Close = 0x08020000 };
|
||||||
Read = 0x08010042,
|
|
||||||
Close = 0x08020000
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper to convert std::string to an 8.3 filename to mimic how Directory::Read works
|
// Helper to convert std::string to an 8.3 filename to mimic how Directory::Read works
|
||||||
|
@ -28,7 +25,7 @@ Filename83 convertTo83(const std::string& path) {
|
||||||
// Convert a character to add it to the 8.3 name
|
// Convert a character to add it to the 8.3 name
|
||||||
// "Characters such as + are changed to the underscore _, and letters are put in uppercase"
|
// "Characters such as + are changed to the underscore _, and letters are put in uppercase"
|
||||||
// For now we put letters in uppercase until we find out what is supposed to be converted to _ and so on
|
// For now we put letters in uppercase until we find out what is supposed to be converted to _ and so on
|
||||||
auto convertCharacter = [](char c) { return (char) std::toupper(c); };
|
auto convertCharacter = [](char c) { return (char)std::toupper(c); };
|
||||||
|
|
||||||
// List of forbidden character for 8.3 filenames, from Citra
|
// List of forbidden character for 8.3 filenames, from Citra
|
||||||
// TODO: Use constexpr when C++20 support is solid
|
// TODO: Use constexpr when C++20 support is solid
|
||||||
|
@ -66,7 +63,7 @@ Filename83 convertTo83(const std::string& path) {
|
||||||
filenameTooBig = true;
|
filenameTooBig = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
filename[validCharacterCount++] = convertCharacter(c); // Append character to filename
|
filename[validCharacterCount++] = convertCharacter(c); // Append character to filename
|
||||||
}
|
}
|
||||||
|
|
||||||
// Truncate name to 6 characters and denote that it is too big
|
// Truncate name to 6 characters and denote that it is too big
|
||||||
|
@ -87,7 +84,7 @@ Filename83 convertTo83(const std::string& path) {
|
||||||
return {filename, extension};
|
return {filename, extension};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::handleDirectoryOperation(u32 messagePointer, Handle directory) {
|
void Kernel::handleDirectoryOperation(u32 messagePointer, HandleType directory) {
|
||||||
const u32 cmd = mem.read32(messagePointer);
|
const u32 cmd = mem.read32(messagePointer);
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case DirectoryOps::Close: closeDirectory(messagePointer, directory); break;
|
case DirectoryOps::Close: closeDirectory(messagePointer, directory); break;
|
||||||
|
@ -96,7 +93,7 @@ void Kernel::handleDirectoryOperation(u32 messagePointer, Handle directory) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::closeDirectory(u32 messagePointer, Handle directory) {
|
void Kernel::closeDirectory(u32 messagePointer, HandleType directory) {
|
||||||
logFileIO("Closed directory %X\n", directory);
|
logFileIO("Closed directory %X\n", directory);
|
||||||
|
|
||||||
const auto p = getObject(directory, KernelObjectType::Directory);
|
const auto p = getObject(directory, KernelObjectType::Directory);
|
||||||
|
@ -109,11 +106,11 @@ void Kernel::closeDirectory(u32 messagePointer, Handle directory) {
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::readDirectory(u32 messagePointer, Handle directory) {
|
void Kernel::readDirectory(u32 messagePointer, HandleType directory) {
|
||||||
const u32 entryCount = mem.read32(messagePointer + 4);
|
const u32 entryCount = mem.read32(messagePointer + 4);
|
||||||
const u32 outPointer = mem.read32(messagePointer + 12);
|
const u32 outPointer = mem.read32(messagePointer + 12);
|
||||||
logFileIO("Directory::Read (handle = %X, entry count = %d, out pointer = %08X)\n", directory, entryCount, outPointer);
|
logFileIO("Directory::Read (handle = %X, entry count = %d, out pointer = %08X)\n", directory, entryCount, outPointer);
|
||||||
|
|
||||||
const auto p = getObject(directory, KernelObjectType::Directory);
|
const auto p = getObject(directory, KernelObjectType::Directory);
|
||||||
if (p == nullptr) [[unlikely]] {
|
if (p == nullptr) [[unlikely]] {
|
||||||
Helpers::panic("Called ReadDirectory on non-existent directory");
|
Helpers::panic("Called ReadDirectory on non-existent directory");
|
||||||
|
@ -136,9 +133,9 @@ void Kernel::readDirectory(u32 messagePointer, Handle directory) {
|
||||||
bool isDirectory = std::filesystem::is_directory(relative);
|
bool isDirectory = std::filesystem::is_directory(relative);
|
||||||
|
|
||||||
std::u16string nameU16 = relative.u16string();
|
std::u16string nameU16 = relative.u16string();
|
||||||
bool isHidden = nameU16[0] == u'.'; // If the first character is a dot then this is a hidden file/folder
|
bool isHidden = nameU16[0] == u'.'; // If the first character is a dot then this is a hidden file/folder
|
||||||
|
|
||||||
const u32 entryPointer = outPointer + (count * 0x228); // 0x228 is the size of a single entry
|
const u32 entryPointer = outPointer + (count * 0x228); // 0x228 is the size of a single entry
|
||||||
u32 utfPointer = entryPointer;
|
u32 utfPointer = entryPointer;
|
||||||
u32 namePointer = entryPointer + 0x20C;
|
u32 namePointer = entryPointer + 0x20C;
|
||||||
u32 extensionPointer = entryPointer + 0x216;
|
u32 extensionPointer = entryPointer + 0x216;
|
||||||
|
@ -152,7 +149,7 @@ void Kernel::readDirectory(u32 messagePointer, Handle directory) {
|
||||||
mem.write16(utfPointer, u16(c));
|
mem.write16(utfPointer, u16(c));
|
||||||
utfPointer += sizeof(u16);
|
utfPointer += sizeof(u16);
|
||||||
}
|
}
|
||||||
mem.write16(utfPointer, 0); // Null terminate the UTF16 name
|
mem.write16(utfPointer, 0); // Null terminate the UTF16 name
|
||||||
|
|
||||||
// Write 8.3 filename-extension
|
// Write 8.3 filename-extension
|
||||||
for (auto c : shortFilename) {
|
for (auto c : shortFilename) {
|
||||||
|
|
|
@ -1,38 +1,25 @@
|
||||||
#include "kernel.hpp"
|
#include "kernel.hpp"
|
||||||
|
|
||||||
namespace Commands {
|
namespace Commands {
|
||||||
enum : u32 {
|
enum : u32 { Throw = 0x00010800 };
|
||||||
Throw = 0x00010800
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace FatalErrorType {
|
namespace FatalErrorType {
|
||||||
enum : u32 {
|
enum : u32 { Generic = 0, Corrupted = 1, CardRemoved = 2, Exception = 3, ResultFailure = 4, Logged = 5 };
|
||||||
Generic = 0,
|
|
||||||
Corrupted = 1,
|
|
||||||
CardRemoved = 2,
|
|
||||||
Exception = 3,
|
|
||||||
ResultFailure = 4,
|
|
||||||
Logged = 5
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle SendSyncRequest targetting the err:f port
|
// HandleType SendSyncRequest targetting the err:f port
|
||||||
void Kernel::handleErrorSyncRequest(u32 messagePointer) {
|
void Kernel::handleErrorSyncRequest(u32 messagePointer) {
|
||||||
u32 cmd = mem.read32(messagePointer);
|
u32 cmd = mem.read32(messagePointer);
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case Commands::Throw:
|
case Commands::Throw: throwError(messagePointer); break;
|
||||||
throwError(messagePointer);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default: Helpers::panic("Unimplemented err:f command %08X\n", cmd); break;
|
||||||
Helpers::panic("Unimplemented err:f command %08X\n", cmd);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::throwError(u32 messagePointer) {
|
void Kernel::throwError(u32 messagePointer) {
|
||||||
const auto type = mem.read8(messagePointer + 4); // Fatal error type
|
const auto type = mem.read8(messagePointer + 4); // Fatal error type
|
||||||
const u32 pc = mem.read32(messagePointer + 12);
|
const u32 pc = mem.read32(messagePointer + 12);
|
||||||
const u32 pid = mem.read32(messagePointer + 16);
|
const u32 pid = mem.read32(messagePointer + 16);
|
||||||
logError("Thrown fatal error @ %08X (pid = %X, type = %d)\n", pc, pid, type);
|
logError("Thrown fatal error @ %08X (pid = %X, type = %d)\n", pc, pid, type);
|
||||||
|
@ -44,4 +31,4 @@ void Kernel::throwError(u32 messagePointer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Helpers::panic("Thrown fatal error");
|
Helpers::panic("Thrown fatal error");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
#include "kernel.hpp"
|
|
||||||
#include "cpu.hpp"
|
|
||||||
#include <bit>
|
#include <bit>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include "cpu.hpp"
|
||||||
|
#include "kernel.hpp"
|
||||||
|
|
||||||
const char* Kernel::resetTypeToString(u32 type) {
|
const char* Kernel::resetTypeToString(u32 type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 0: return "One shot";
|
case 0: return "One shot";
|
||||||
|
@ -12,13 +13,13 @@ const char* Kernel::resetTypeToString(u32 type) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle Kernel::makeEvent(ResetType resetType, Event::CallbackType callback) {
|
HandleType Kernel::makeEvent(ResetType resetType, Event::CallbackType callback) {
|
||||||
Handle ret = makeObject(KernelObjectType::Event);
|
HandleType ret = makeObject(KernelObjectType::Event);
|
||||||
objects[ret].data = new Event(resetType, callback);
|
objects[ret].data = new Event(resetType, callback);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Kernel::signalEvent(Handle handle) {
|
bool Kernel::signalEvent(HandleType handle) {
|
||||||
KernelObject* object = getObject(handle, KernelObjectType::Event);
|
KernelObject* object = getObject(handle, KernelObjectType::Event);
|
||||||
if (object == nullptr) [[unlikely]] {
|
if (object == nullptr) [[unlikely]] {
|
||||||
Helpers::panic("Tried to signal non-existent event");
|
Helpers::panic("Tried to signal non-existent event");
|
||||||
|
@ -52,13 +53,12 @@ bool Kernel::signalEvent(Handle handle) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Result CreateEvent(Handle* event, ResetType resetType)
|
// Result CreateEvent(HandleType* event, ResetType resetType)
|
||||||
void Kernel::svcCreateEvent() {
|
void Kernel::svcCreateEvent() {
|
||||||
const u32 outPointer = regs[0];
|
const u32 outPointer = regs[0];
|
||||||
const u32 resetType = regs[1];
|
const u32 resetType = regs[1];
|
||||||
|
|
||||||
if (resetType > 2)
|
if (resetType > 2) Helpers::panic("Invalid reset type for event %d", resetType);
|
||||||
Helpers::panic("Invalid reset type for event %d", resetType);
|
|
||||||
|
|
||||||
logSVC("CreateEvent(handle pointer = %08X, resetType = %s)\n", outPointer, resetTypeToString(resetType));
|
logSVC("CreateEvent(handle pointer = %08X, resetType = %s)\n", outPointer, resetTypeToString(resetType));
|
||||||
|
|
||||||
|
@ -66,9 +66,9 @@ void Kernel::svcCreateEvent() {
|
||||||
regs[1] = makeEvent(static_cast<ResetType>(resetType));
|
regs[1] = makeEvent(static_cast<ResetType>(resetType));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Result ClearEvent(Handle event)
|
// Result ClearEvent(HandleType event)
|
||||||
void Kernel::svcClearEvent() {
|
void Kernel::svcClearEvent() {
|
||||||
const Handle handle = regs[0];
|
const HandleType handle = regs[0];
|
||||||
const auto event = getObject(handle, KernelObjectType::Event);
|
const auto event = getObject(handle, KernelObjectType::Event);
|
||||||
logSVC("ClearEvent(event handle = %X)\n", handle);
|
logSVC("ClearEvent(event handle = %X)\n", handle);
|
||||||
|
|
||||||
|
@ -82,9 +82,9 @@ void Kernel::svcClearEvent() {
|
||||||
regs[0] = Result::Success;
|
regs[0] = Result::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Result SignalEvent(Handle event)
|
// Result SignalEvent(HandleType event)
|
||||||
void Kernel::svcSignalEvent() {
|
void Kernel::svcSignalEvent() {
|
||||||
const Handle handle = regs[0];
|
const HandleType handle = regs[0];
|
||||||
logSVC("SignalEvent(event handle = %X)\n", handle);
|
logSVC("SignalEvent(event handle = %X)\n", handle);
|
||||||
KernelObject* object = getObject(handle, KernelObjectType::Event);
|
KernelObject* object = getObject(handle, KernelObjectType::Event);
|
||||||
|
|
||||||
|
@ -98,9 +98,9 @@ void Kernel::svcSignalEvent() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Result WaitSynchronization1(Handle handle, s64 timeout_nanoseconds)
|
// Result WaitSynchronization1(HandleType handle, s64 timeout_nanoseconds)
|
||||||
void Kernel::waitSynchronization1() {
|
void Kernel::waitSynchronization1() {
|
||||||
const Handle handle = regs[0];
|
const HandleType handle = regs[0];
|
||||||
const s64 ns = s64(u64(regs[2]) | (u64(regs[3]) << 32));
|
const s64 ns = s64(u64(regs[2]) | (u64(regs[3]) << 32));
|
||||||
logSVC("WaitSynchronization1(handle = %X, ns = %lld)\n", handle, ns);
|
logSVC("WaitSynchronization1(handle = %X, ns = %lld)\n", handle, ns);
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ void Kernel::waitSynchronization1() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!shouldWaitOnObject(object)) {
|
if (!shouldWaitOnObject(object)) {
|
||||||
acquireSyncObject(object, threads[currentThreadIndex]); // Acquire the object since it's ready
|
acquireSyncObject(object, threads[currentThreadIndex]); // Acquire the object since it's ready
|
||||||
regs[0] = Result::Success;
|
regs[0] = Result::Success;
|
||||||
} else {
|
} else {
|
||||||
// Timeout is 0, don't bother waiting, instantly timeout
|
// Timeout is 0, don't bother waiting, instantly timeout
|
||||||
|
@ -126,7 +126,7 @@ void Kernel::waitSynchronization1() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
regs[0] = Result::OS::Timeout; // This will be overwritten with success if we don't timeout
|
regs[0] = Result::OS::Timeout; // This will be overwritten with success if we don't timeout
|
||||||
|
|
||||||
auto& t = threads[currentThreadIndex];
|
auto& t = threads[currentThreadIndex];
|
||||||
t.waitList.resize(1);
|
t.waitList.resize(1);
|
||||||
|
@ -141,7 +141,7 @@ void Kernel::waitSynchronization1() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Result WaitSynchronizationN(s32* out, Handle* handles, s32 handlecount, bool waitAll, s64 timeout_nanoseconds)
|
// Result WaitSynchronizationN(s32* out, HandleType* handles, s32 handlecount, bool waitAll, s64 timeout_nanoseconds)
|
||||||
void Kernel::waitSynchronizationN() {
|
void Kernel::waitSynchronizationN() {
|
||||||
// TODO: Are these arguments even correct?
|
// TODO: Are these arguments even correct?
|
||||||
s32 ns1 = regs[0];
|
s32 ns1 = regs[0];
|
||||||
|
@ -149,13 +149,12 @@ void Kernel::waitSynchronizationN() {
|
||||||
s32 handleCount = regs[2];
|
s32 handleCount = regs[2];
|
||||||
bool waitAll = regs[3] != 0;
|
bool waitAll = regs[3] != 0;
|
||||||
u32 ns2 = regs[4];
|
u32 ns2 = regs[4];
|
||||||
s32 outPointer = regs[5]; // "out" pointer - shows which object got bonked if we're waiting on multiple objects
|
s32 outPointer = regs[5]; // "out" pointer - shows which object got bonked if we're waiting on multiple objects
|
||||||
s64 ns = s64(ns1) | (s64(ns2) << 32);
|
s64 ns = s64(ns1) | (s64(ns2) << 32);
|
||||||
|
|
||||||
logSVC("WaitSynchronizationN (handle pointer: %08X, count: %d, timeout = %lld)\n", handles, handleCount, ns);
|
logSVC("WaitSynchronizationN (handle pointer: %08X, count: %d, timeout = %lld)\n", handles, handleCount, ns);
|
||||||
|
|
||||||
if (handleCount <= 0)
|
if (handleCount <= 0) Helpers::panic("WaitSyncN: Invalid handle count");
|
||||||
Helpers::panic("WaitSyncN: Invalid handle count");
|
|
||||||
|
|
||||||
// Temporary hack: Until we implement service sessions properly, don't bother sleeping when WaitSyncN targets a service handle
|
// Temporary hack: Until we implement service sessions properly, don't bother sleeping when WaitSyncN targets a service handle
|
||||||
// This is necessary because a lot of games use WaitSyncN with eg the CECD service
|
// This is necessary because a lot of games use WaitSyncN with eg the CECD service
|
||||||
|
@ -165,11 +164,11 @@ void Kernel::waitSynchronizationN() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
using WaitObject = std::pair<Handle, KernelObject*>;
|
using WaitObject = std::pair<HandleType, KernelObject*>;
|
||||||
std::vector<WaitObject> waitObjects(handleCount);
|
std::vector<WaitObject> waitObjects(handleCount);
|
||||||
|
|
||||||
// We don't actually need to wait if waitAll == true unless one of the objects is not ready
|
// We don't actually need to wait if waitAll == true unless one of the objects is not ready
|
||||||
bool allReady = true; // Default initialize to true, set to fault if one of the objects is not ready
|
bool allReady = true; // Default initialize to true, set to fault if one of the objects is not ready
|
||||||
|
|
||||||
// Tracks whether at least one object is ready, + the index of the first ready object
|
// Tracks whether at least one object is ready, + the index of the first ready object
|
||||||
// This is used when waitAll == false, because if one object is already available then we can skip the sleeping
|
// This is used when waitAll == false, because if one object is already available then we can skip the sleeping
|
||||||
|
@ -177,8 +176,8 @@ void Kernel::waitSynchronizationN() {
|
||||||
s32 firstReadyObjectIndex = 0;
|
s32 firstReadyObjectIndex = 0;
|
||||||
|
|
||||||
for (s32 i = 0; i < handleCount; i++) {
|
for (s32 i = 0; i < handleCount; i++) {
|
||||||
Handle handle = mem.read32(handles);
|
HandleType handle = mem.read32(handles);
|
||||||
handles += sizeof(Handle);
|
handles += sizeof(HandleType);
|
||||||
|
|
||||||
auto object = getObject(handle);
|
auto object = getObject(handle);
|
||||||
// Panic if one of the objects is not even an object
|
// Panic if one of the objects is not even an object
|
||||||
|
@ -190,13 +189,12 @@ void Kernel::waitSynchronizationN() {
|
||||||
|
|
||||||
// Panic if one of the objects is not a valid sync object
|
// Panic if one of the objects is not a valid sync object
|
||||||
if (!isWaitable(object)) [[unlikely]] {
|
if (!isWaitable(object)) [[unlikely]] {
|
||||||
Helpers::panic("Tried to wait on a non waitable object in WaitSyncN. Type: %s, handle: %X\n",
|
Helpers::panic("Tried to wait on a non waitable object in WaitSyncN. Type: %s, handle: %X\n", object->getTypeName(), handle);
|
||||||
object->getTypeName(), handle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldWaitOnObject(object)) {
|
if (shouldWaitOnObject(object)) {
|
||||||
allReady = false; // Derp, not all objects are ready :(
|
allReady = false; // Derp, not all objects are ready :(
|
||||||
} else { /// At least one object is ready to be acquired ahead of time. If it's the first one, write it down
|
} else { /// At least one object is ready to be acquired ahead of time. If it's the first one, write it down
|
||||||
if (!oneObjectReady) {
|
if (!oneObjectReady) {
|
||||||
oneObjectReady = true;
|
oneObjectReady = true;
|
||||||
firstReadyObjectIndex = i;
|
firstReadyObjectIndex = i;
|
||||||
|
@ -213,12 +211,12 @@ void Kernel::waitSynchronizationN() {
|
||||||
// If there's ready objects, acquire the first one and return
|
// If there's ready objects, acquire the first one and return
|
||||||
if (oneObjectReady) {
|
if (oneObjectReady) {
|
||||||
regs[0] = Result::Success;
|
regs[0] = Result::Success;
|
||||||
regs[1] = firstReadyObjectIndex; // Return index of the acquired object
|
regs[1] = firstReadyObjectIndex; // Return index of the acquired object
|
||||||
acquireSyncObject(waitObjects[firstReadyObjectIndex].second, t); // Acquire object
|
acquireSyncObject(waitObjects[firstReadyObjectIndex].second, t); // Acquire object
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
regs[0] = Result::OS::Timeout; // This will be overwritten with success if we don't timeout
|
regs[0] = Result::OS::Timeout; // This will be overwritten with success if we don't timeout
|
||||||
// If the thread wakes up without timeout, this will be adjusted to the index of the handle that woke us up
|
// If the thread wakes up without timeout, this will be adjusted to the index of the handle that woke us up
|
||||||
regs[1] = 0xFFFFFFFF;
|
regs[1] = 0xFFFFFFFF;
|
||||||
t.waitList.resize(handleCount);
|
t.waitList.resize(handleCount);
|
||||||
|
@ -227,8 +225,8 @@ void Kernel::waitSynchronizationN() {
|
||||||
t.wakeupTick = getWakeupTick(ns);
|
t.wakeupTick = getWakeupTick(ns);
|
||||||
|
|
||||||
for (s32 i = 0; i < handleCount; i++) {
|
for (s32 i = 0; i < handleCount; i++) {
|
||||||
t.waitList[i] = waitObjects[i].first; // Add object to this thread's waitlist
|
t.waitList[i] = waitObjects[i].first; // Add object to this thread's waitlist
|
||||||
waitObjects[i].second->getWaitlist() |= (1ull << currentThreadIndex); // And add the thread to the object's waitlist
|
waitObjects[i].second->getWaitlist() |= (1ull << currentThreadIndex); // And add the thread to the object's waitlist
|
||||||
}
|
}
|
||||||
|
|
||||||
requireReschedule();
|
requireReschedule();
|
||||||
|
@ -243,4 +241,4 @@ void Kernel::runEventCallback(Event::CallbackType callback) {
|
||||||
case Event::CallbackType::DSPSemaphore: serviceManager.getDSP().onSemaphoreEventSignal(); break;
|
case Event::CallbackType::DSPSemaphore: serviceManager.getDSP().onSemaphoreEventSignal(); break;
|
||||||
default: Helpers::panic("Unimplemented special callback for kernel event!"); break;
|
default: Helpers::panic("Unimplemented special callback for kernel event!"); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,7 @@ namespace FileOps {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Kernel::handleFileOperation(u32 messagePointer, HandleType file) {
|
||||||
void Kernel::handleFileOperation(u32 messagePointer, Handle file) {
|
|
||||||
const u32 cmd = mem.read32(messagePointer);
|
const u32 cmd = mem.read32(messagePointer);
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case FileOps::Close: closeFile(messagePointer, file); break;
|
case FileOps::Close: closeFile(messagePointer, file); break;
|
||||||
|
@ -30,7 +29,7 @@ void Kernel::handleFileOperation(u32 messagePointer, Handle file) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::closeFile(u32 messagePointer, Handle fileHandle) {
|
void Kernel::closeFile(u32 messagePointer, HandleType fileHandle) {
|
||||||
logFileIO("Closed file %X\n", fileHandle);
|
logFileIO("Closed file %X\n", fileHandle);
|
||||||
|
|
||||||
const auto p = getObject(fileHandle, KernelObjectType::File);
|
const auto p = getObject(fileHandle, KernelObjectType::File);
|
||||||
|
@ -48,7 +47,7 @@ void Kernel::closeFile(u32 messagePointer, Handle fileHandle) {
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::flushFile(u32 messagePointer, Handle fileHandle) {
|
void Kernel::flushFile(u32 messagePointer, HandleType fileHandle) {
|
||||||
logFileIO("Flushed file %X\n", fileHandle);
|
logFileIO("Flushed file %X\n", fileHandle);
|
||||||
|
|
||||||
const auto p = getObject(fileHandle, KernelObjectType::File);
|
const auto p = getObject(fileHandle, KernelObjectType::File);
|
||||||
|
@ -65,13 +64,12 @@ void Kernel::flushFile(u32 messagePointer, Handle fileHandle) {
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::readFile(u32 messagePointer, Handle fileHandle) {
|
void Kernel::readFile(u32 messagePointer, HandleType fileHandle) {
|
||||||
u64 offset = mem.read64(messagePointer + 4);
|
u64 offset = mem.read64(messagePointer + 4);
|
||||||
u32 size = mem.read32(messagePointer + 12);
|
u32 size = mem.read32(messagePointer + 12);
|
||||||
u32 dataPointer = mem.read32(messagePointer + 20);
|
u32 dataPointer = mem.read32(messagePointer + 20);
|
||||||
|
|
||||||
logFileIO("Trying to read %X bytes from file %X, starting from offset %llX into memory address %08X\n",
|
logFileIO("Trying to read %X bytes from file %X, starting from offset %llX into memory address %08X\n", size, fileHandle, offset, dataPointer);
|
||||||
size, fileHandle, offset, dataPointer);
|
|
||||||
|
|
||||||
const auto p = getObject(fileHandle, KernelObjectType::File);
|
const auto p = getObject(fileHandle, KernelObjectType::File);
|
||||||
if (p == nullptr) [[unlikely]] {
|
if (p == nullptr) [[unlikely]] {
|
||||||
|
@ -85,7 +83,7 @@ void Kernel::readFile(u32 messagePointer, Handle fileHandle) {
|
||||||
Helpers::panic("Tried to read closed file");
|
Helpers::panic("Tried to read closed file");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle files with their own file descriptors by just fread'ing the data
|
// HandleType files with their own file descriptors by just fread'ing the data
|
||||||
if (file->fd) {
|
if (file->fd) {
|
||||||
std::unique_ptr<u8[]> data(new u8[size]);
|
std::unique_ptr<u8[]> data(new u8[size]);
|
||||||
IOFile f(file->fd);
|
IOFile f(file->fd);
|
||||||
|
@ -94,8 +92,7 @@ void Kernel::readFile(u32 messagePointer, Handle fileHandle) {
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
Helpers::panic("Kernel::ReadFile with file descriptor failed");
|
Helpers::panic("Kernel::ReadFile with file descriptor failed");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
for (size_t i = 0; i < bytesRead; i++) {
|
for (size_t i = 0; i < bytesRead; i++) {
|
||||||
mem.write8(u32(dataPointer + i), data[i]);
|
mem.write8(u32(dataPointer + i), data[i]);
|
||||||
}
|
}
|
||||||
|
@ -107,7 +104,7 @@ void Kernel::readFile(u32 messagePointer, Handle fileHandle) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle files without their own FD, such as SelfNCCH files
|
// HandleType files without their own FD, such as SelfNCCH files
|
||||||
auto archive = file->archive;
|
auto archive = file->archive;
|
||||||
std::optional<u32> bytesRead = archive->readFile(file, offset, size, dataPointer);
|
std::optional<u32> bytesRead = archive->readFile(file, offset, size, dataPointer);
|
||||||
if (!bytesRead.has_value()) {
|
if (!bytesRead.has_value()) {
|
||||||
|
@ -118,14 +115,13 @@ void Kernel::readFile(u32 messagePointer, Handle fileHandle) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::writeFile(u32 messagePointer, Handle fileHandle) {
|
void Kernel::writeFile(u32 messagePointer, HandleType fileHandle) {
|
||||||
u64 offset = mem.read64(messagePointer + 4);
|
u64 offset = mem.read64(messagePointer + 4);
|
||||||
u32 size = mem.read32(messagePointer + 12);
|
u32 size = mem.read32(messagePointer + 12);
|
||||||
u32 writeOption = mem.read32(messagePointer + 16);
|
u32 writeOption = mem.read32(messagePointer + 16);
|
||||||
u32 dataPointer = mem.read32(messagePointer + 24);
|
u32 dataPointer = mem.read32(messagePointer + 24);
|
||||||
|
|
||||||
logFileIO("Trying to write %X bytes to file %X, starting from file offset %llX and memory address %08X\n",
|
logFileIO("Trying to write %X bytes to file %X, starting from file offset %llX and memory address %08X\n", size, fileHandle, offset, dataPointer);
|
||||||
size, fileHandle, offset, dataPointer);
|
|
||||||
|
|
||||||
const auto p = getObject(fileHandle, KernelObjectType::File);
|
const auto p = getObject(fileHandle, KernelObjectType::File);
|
||||||
if (p == nullptr) [[unlikely]] {
|
if (p == nullptr) [[unlikely]] {
|
||||||
|
@ -137,8 +133,7 @@ void Kernel::writeFile(u32 messagePointer, Handle fileHandle) {
|
||||||
Helpers::panic("Tried to write closed file");
|
Helpers::panic("Tried to write closed file");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!file->fd)
|
if (!file->fd) Helpers::panic("[Kernel::File::WriteFile] Tried to write to file without a valid file descriptor");
|
||||||
Helpers::panic("[Kernel::File::WriteFile] Tried to write to file without a valid file descriptor");
|
|
||||||
|
|
||||||
std::unique_ptr<u8[]> data(new u8[size]);
|
std::unique_ptr<u8[]> data(new u8[size]);
|
||||||
for (size_t i = 0; i < size; i++) {
|
for (size_t i = 0; i < size; i++) {
|
||||||
|
@ -162,7 +157,7 @@ void Kernel::writeFile(u32 messagePointer, Handle fileHandle) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::setFileSize(u32 messagePointer, Handle fileHandle) {
|
void Kernel::setFileSize(u32 messagePointer, HandleType fileHandle) {
|
||||||
logFileIO("Setting size of file %X\n", fileHandle);
|
logFileIO("Setting size of file %X\n", fileHandle);
|
||||||
|
|
||||||
const auto p = getObject(fileHandle, KernelObjectType::File);
|
const auto p = getObject(fileHandle, KernelObjectType::File);
|
||||||
|
@ -191,7 +186,7 @@ void Kernel::setFileSize(u32 messagePointer, Handle fileHandle) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::getFileSize(u32 messagePointer, Handle fileHandle) {
|
void Kernel::getFileSize(u32 messagePointer, HandleType fileHandle) {
|
||||||
logFileIO("Getting size of file %X\n", fileHandle);
|
logFileIO("Getting size of file %X\n", fileHandle);
|
||||||
|
|
||||||
const auto p = getObject(fileHandle, KernelObjectType::File);
|
const auto p = getObject(fileHandle, KernelObjectType::File);
|
||||||
|
@ -220,7 +215,7 @@ void Kernel::getFileSize(u32 messagePointer, Handle fileHandle) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::openLinkFile(u32 messagePointer, Handle fileHandle) {
|
void Kernel::openLinkFile(u32 messagePointer, HandleType fileHandle) {
|
||||||
logFileIO("Open link file (clone) of file %X\n", fileHandle);
|
logFileIO("Open link file (clone) of file %X\n", fileHandle);
|
||||||
|
|
||||||
const auto p = getObject(fileHandle, KernelObjectType::File);
|
const auto p = getObject(fileHandle, KernelObjectType::File);
|
||||||
|
@ -247,7 +242,7 @@ void Kernel::openLinkFile(u32 messagePointer, Handle fileHandle) {
|
||||||
mem.write32(messagePointer + 12, handle);
|
mem.write32(messagePointer + 12, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::setFilePriority(u32 messagePointer, Handle fileHandle) {
|
void Kernel::setFilePriority(u32 messagePointer, HandleType fileHandle) {
|
||||||
const u32 priority = mem.read32(messagePointer + 4);
|
const u32 priority = mem.read32(messagePointer + 4);
|
||||||
logFileIO("Setting priority of file %X to %d\n", fileHandle, priority);
|
logFileIO("Setting priority of file %X to %d\n", fileHandle, priority);
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
#include <cassert>
|
|
||||||
#include "kernel.hpp"
|
#include "kernel.hpp"
|
||||||
#include "kernel_types.hpp"
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
#include "cpu.hpp"
|
#include "cpu.hpp"
|
||||||
|
#include "kernel_types.hpp"
|
||||||
|
|
||||||
Kernel::Kernel(CPU& cpu, Memory& mem, GPU& gpu, const EmulatorConfig& config)
|
Kernel::Kernel(CPU& cpu, Memory& mem, GPU& gpu, const EmulatorConfig& config)
|
||||||
: cpu(cpu), regs(cpu.regs()), mem(mem), handleCounter(0), serviceManager(regs, mem, gpu, currentProcess, *this, config) {
|
: cpu(cpu), regs(cpu.regs()), mem(mem), handleCounter(0), serviceManager(regs, mem, gpu, currentProcess, *this, config) {
|
||||||
objects.reserve(512); // Make room for a few objects to avoid further memory allocs later
|
objects.reserve(512); // Make room for a few objects to avoid further memory allocs later
|
||||||
mutexHandles.reserve(8);
|
mutexHandles.reserve(8);
|
||||||
portHandles.reserve(32);
|
portHandles.reserve(32);
|
||||||
threadIndices.reserve(appResourceLimits.maxThreads);
|
threadIndices.reserve(appResourceLimits.maxThreads);
|
||||||
|
@ -17,7 +19,7 @@ Kernel::Kernel(CPU& cpu, Memory& mem, GPU& gpu, const EmulatorConfig& config)
|
||||||
t.tlsBase = VirtualAddrs::TLSBase + i * VirtualAddrs::TLSSize;
|
t.tlsBase = VirtualAddrs::TLSBase + i * VirtualAddrs::TLSSize;
|
||||||
t.status = ThreadStatus::Dead;
|
t.status = ThreadStatus::Dead;
|
||||||
t.waitList.clear();
|
t.waitList.clear();
|
||||||
t.waitList.reserve(10); // Reserve some space for the wait list to avoid further memory allocs later
|
t.waitList.reserve(10); // Reserve some space for the wait list to avoid further memory allocs later
|
||||||
// The state below isn't necessary to initialize but we do it anyways out of caution
|
// The state below isn't necessary to initialize but we do it anyways out of caution
|
||||||
t.outPointer = 0;
|
t.outPointer = 0;
|
||||||
t.waitAll = false;
|
t.waitAll = false;
|
||||||
|
@ -79,12 +81,12 @@ void Kernel::setVersion(u8 major, u8 minor) {
|
||||||
u16 descriptor = (u16(major) << 8) | u16(minor);
|
u16 descriptor = (u16(major) << 8) | u16(minor);
|
||||||
|
|
||||||
kernelVersion = descriptor;
|
kernelVersion = descriptor;
|
||||||
mem.kernelVersion = descriptor; // The memory objects needs a copy because you can read the kernel ver from config mem
|
mem.kernelVersion = descriptor; // The memory objects needs a copy because you can read the kernel ver from config mem
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle Kernel::makeProcess(u32 id) {
|
HandleType Kernel::makeProcess(u32 id) {
|
||||||
const Handle processHandle = makeObject(KernelObjectType::Process);
|
const HandleType processHandle = makeObject(KernelObjectType::Process);
|
||||||
const Handle resourceLimitHandle = makeObject(KernelObjectType::ResourceLimit);
|
const HandleType resourceLimitHandle = makeObject(KernelObjectType::ResourceLimit);
|
||||||
|
|
||||||
// Allocate data
|
// Allocate data
|
||||||
objects[processHandle].data = new Process(id);
|
objects[processHandle].data = new Process(id);
|
||||||
|
@ -98,7 +100,7 @@ Handle Kernel::makeProcess(u32 id) {
|
||||||
|
|
||||||
// Get a pointer to the process indicated by handle, taking into account that 0xFFFF8001 always refers to the current process
|
// Get a pointer to the process indicated by handle, taking into account that 0xFFFF8001 always refers to the current process
|
||||||
// Returns nullptr if the handle does not correspond to a process
|
// Returns nullptr if the handle does not correspond to a process
|
||||||
KernelObject* Kernel::getProcessFromPID(Handle handle) {
|
KernelObject* Kernel::getProcessFromPID(HandleType handle) {
|
||||||
if (handle == KernelHandles::CurrentProcess) [[likely]] {
|
if (handle == KernelHandles::CurrentProcess) [[likely]] {
|
||||||
return getObject(currentProcess, KernelObjectType::Process);
|
return getObject(currentProcess, KernelObjectType::Process);
|
||||||
} else {
|
} else {
|
||||||
|
@ -142,7 +144,7 @@ void Kernel::reset() {
|
||||||
for (auto& t : threads) {
|
for (auto& t : threads) {
|
||||||
t.status = ThreadStatus::Dead;
|
t.status = ThreadStatus::Dead;
|
||||||
t.waitList.clear();
|
t.waitList.clear();
|
||||||
t.threadsWaitingForTermination = 0; // No threads are waiting for this thread to terminate cause it's dead
|
t.threadsWaitingForTermination = 0; // No threads are waiting for this thread to terminate cause it's dead
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& object : objects) {
|
for (auto& object : objects) {
|
||||||
|
@ -159,7 +161,7 @@ void Kernel::reset() {
|
||||||
|
|
||||||
// Allocate handle #0 to a dummy object and make a main process object
|
// Allocate handle #0 to a dummy object and make a main process object
|
||||||
makeObject(KernelObjectType::Dummy);
|
makeObject(KernelObjectType::Dummy);
|
||||||
currentProcess = makeProcess(1); // Use ID = 1 for main process
|
currentProcess = makeProcess(1); // Use ID = 1 for main process
|
||||||
|
|
||||||
// Make main thread object. We do not have to set the entrypoint and SP for it as the ROM loader does.
|
// Make main thread object. We do not have to set the entrypoint and SP for it as the ROM loader does.
|
||||||
// Main thread seems to have a priority of 0x30. TODO: This creates a dummy context for thread 0,
|
// Main thread seems to have a priority of 0x30. TODO: This creates a dummy context for thread 0,
|
||||||
|
@ -169,19 +171,17 @@ void Kernel::reset() {
|
||||||
setupIdleThread();
|
setupIdleThread();
|
||||||
|
|
||||||
// Create some of the OS ports
|
// Create some of the OS ports
|
||||||
srvHandle = makePort("srv:"); // Service manager port
|
srvHandle = makePort("srv:"); // Service manager port
|
||||||
errorPortHandle = makePort("err:f"); // Error display port
|
errorPortHandle = makePort("err:f"); // Error display port
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get pointer to thread-local storage
|
// Get pointer to thread-local storage
|
||||||
u32 Kernel::getTLSPointer() {
|
u32 Kernel::getTLSPointer() { return VirtualAddrs::TLSBase + currentThreadIndex * VirtualAddrs::TLSSize; }
|
||||||
return VirtualAddrs::TLSBase + currentThreadIndex * VirtualAddrs::TLSSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Result CloseHandle(Handle handle)
|
// Result CloseHandle(HandleType handle)
|
||||||
void Kernel::svcCloseHandle() {
|
void Kernel::svcCloseHandle() {
|
||||||
logSVC("CloseHandle(handle = %d) (Unimplemented)\n", regs[0]);
|
logSVC("CloseHandle(handle = %d) (Unimplemented)\n", regs[0]);
|
||||||
const Handle handle = regs[0];
|
const HandleType handle = regs[0];
|
||||||
|
|
||||||
KernelObject* object = getObject(handle);
|
KernelObject* object = getObject(handle);
|
||||||
if (object != nullptr) {
|
if (object != nullptr) {
|
||||||
|
@ -242,7 +242,7 @@ void Kernel::getProcessID() {
|
||||||
regs[1] = process->getData<Process>()->id;
|
regs[1] = process->getData<Process>()->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Result GetProcessInfo(s64* out, Handle process, ProcessInfoType type)
|
// Result GetProcessInfo(s64* out, HandleType process, ProcessInfoType type)
|
||||||
void Kernel::getProcessInfo() {
|
void Kernel::getProcessInfo() {
|
||||||
const auto pid = regs[1];
|
const auto pid = regs[1];
|
||||||
const auto type = regs[2];
|
const auto type = regs[2];
|
||||||
|
@ -269,26 +269,25 @@ void Kernel::getProcessInfo() {
|
||||||
regs[2] = 0;
|
regs[2] = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 20: // Returns 0x20000000 - <linear memory base vaddr for process>
|
case 20: // Returns 0x20000000 - <linear memory base vaddr for process>
|
||||||
regs[1] = PhysicalAddrs::FCRAM - mem.getLinearHeapVaddr();
|
regs[1] = PhysicalAddrs::FCRAM - mem.getLinearHeapVaddr();
|
||||||
regs[2] = 0;
|
regs[2] = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default: Helpers::panic("GetProcessInfo: unimplemented type %d", type);
|
||||||
Helpers::panic("GetProcessInfo: unimplemented type %d", type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
regs[0] = Result::Success;
|
regs[0] = Result::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Result DuplicateHandle(Handle* out, Handle original)
|
// Result DuplicateHandle(HandleType* out, HandleType original)
|
||||||
void Kernel::duplicateHandle() {
|
void Kernel::duplicateHandle() {
|
||||||
Handle original = regs[1];
|
HandleType original = regs[1];
|
||||||
logSVC("DuplicateHandle(handle = %X)\n", original);
|
logSVC("DuplicateHandle(handle = %X)\n", original);
|
||||||
|
|
||||||
if (original == KernelHandles::CurrentThread) {
|
if (original == KernelHandles::CurrentThread) {
|
||||||
regs[0] = Result::Success;
|
regs[0] = Result::Success;
|
||||||
Handle ret = makeObject(KernelObjectType::Thread);
|
HandleType ret = makeObject(KernelObjectType::Thread);
|
||||||
objects[ret].data = &threads[currentThreadIndex];
|
objects[ret].data = &threads[currentThreadIndex];
|
||||||
|
|
||||||
regs[1] = ret;
|
regs[1] = ret;
|
||||||
|
@ -379,7 +378,7 @@ void Kernel::getSystemInfo() {
|
||||||
regs[2] = 0;
|
regs[2] = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Helpers::warn("GetSystemInfo: Unknown PandaInformation subtype %x\n", subtype);
|
Helpers::warn("GetSystemInfo: Unknown PandaInformation subtype %x\n", subtype);
|
||||||
regs[0] = Result::FailurePlaceholder;
|
regs[0] = Result::FailurePlaceholder;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -17,37 +17,35 @@ namespace Operation {
|
||||||
|
|
||||||
namespace MemoryPermissions {
|
namespace MemoryPermissions {
|
||||||
enum : u32 {
|
enum : u32 {
|
||||||
None = 0, // ---
|
None = 0, // ---
|
||||||
Read = 1, // R--
|
Read = 1, // R--
|
||||||
Write = 2, // -W-
|
Write = 2, // -W-
|
||||||
ReadWrite = 3, // RW-
|
ReadWrite = 3, // RW-
|
||||||
Execute = 4, // --X
|
Execute = 4, // --X
|
||||||
ReadExecute = 5, // R-X
|
ReadExecute = 5, // R-X
|
||||||
WriteExecute = 6, // -WX
|
WriteExecute = 6, // -WX
|
||||||
ReadWriteExecute = 7, // RWX
|
ReadWriteExecute = 7, // RWX
|
||||||
|
|
||||||
DontCare = 0x10000000
|
DontCare = 0x10000000
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns whether "value" is aligned to a page boundary (Ie a boundary of 4096 bytes)
|
// Returns whether "value" is aligned to a page boundary (Ie a boundary of 4096 bytes)
|
||||||
static constexpr bool isAligned(u32 value) {
|
static constexpr bool isAligned(u32 value) { return (value & 0xFFF) == 0; }
|
||||||
return (value & 0xFFF) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Result ControlMemory(u32* outaddr, u32 addr0, u32 addr1, u32 size,
|
// Result ControlMemory(u32* outaddr, u32 addr0, u32 addr1, u32 size,
|
||||||
// MemoryOperation operation, MemoryPermission permissions)
|
// MemoryOperation operation, MemoryPermission permissions)
|
||||||
// This has a weird ABI documented here https://www.3dbrew.org/wiki/Kernel_ABI
|
// This has a weird ABI documented here https://www.3dbrew.org/wiki/Kernel_ABI
|
||||||
// TODO: Does this need to write to outaddr?
|
// TODO: Does this need to write to outaddr?
|
||||||
void Kernel::controlMemory() {
|
void Kernel::controlMemory() {
|
||||||
u32 operation = regs[0]; // The base address is written here
|
u32 operation = regs[0]; // The base address is written here
|
||||||
u32 addr0 = regs[1];
|
u32 addr0 = regs[1];
|
||||||
u32 addr1 = regs[2];
|
u32 addr1 = regs[2];
|
||||||
u32 size = regs[3];
|
u32 size = regs[3];
|
||||||
u32 perms = regs[4];
|
u32 perms = regs[4];
|
||||||
|
|
||||||
if (perms == MemoryPermissions::DontCare) {
|
if (perms == MemoryPermissions::DontCare) {
|
||||||
perms = MemoryPermissions::ReadWrite; // We make "don't care" equivalent to read-write
|
perms = MemoryPermissions::ReadWrite; // We make "don't care" equivalent to read-write
|
||||||
Helpers::panic("Unimplemented allocation permission: DONTCARE");
|
Helpers::panic("Unimplemented allocation permission: DONTCARE");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,33 +55,33 @@ void Kernel::controlMemory() {
|
||||||
bool x = perms & 0b100;
|
bool x = perms & 0b100;
|
||||||
bool linear = operation & Operation::Linear;
|
bool linear = operation & Operation::Linear;
|
||||||
|
|
||||||
if (x)
|
if (x) Helpers::panic("ControlMemory: attempted to allocate executable memory");
|
||||||
Helpers::panic("ControlMemory: attempted to allocate executable memory");
|
|
||||||
|
|
||||||
if (!isAligned(addr0) || !isAligned(addr1) || !isAligned(size)) {
|
if (!isAligned(addr0) || !isAligned(addr1) || !isAligned(size)) {
|
||||||
Helpers::panic("ControlMemory: Unaligned parameters\nAddr0: %08X\nAddr1: %08X\nSize: %08X", addr0, addr1, size);
|
Helpers::panic("ControlMemory: Unaligned parameters\nAddr0: %08X\nAddr1: %08X\nSize: %08X", addr0, addr1, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
logSVC("ControlMemory(addr0 = %08X, addr1 = %08X, size = %08X, operation = %X (%c%c%c)%s\n",
|
logSVC(
|
||||||
addr0, addr1, size, operation, r ? 'r' : '-', w ? 'w' : '-', x ? 'x' : '-', linear ? ", linear" : ""
|
"ControlMemory(addr0 = %08X, addr1 = %08X, size = %08X, operation = %X (%c%c%c)%s\n", addr0, addr1, size, operation, r ? 'r' : '-',
|
||||||
|
w ? 'w' : '-', x ? 'x' : '-', linear ? ", linear" : ""
|
||||||
);
|
);
|
||||||
|
|
||||||
switch (operation & 0xFF) {
|
switch (operation & 0xFF) {
|
||||||
case Operation::Commit: {
|
case Operation::Commit: {
|
||||||
std::optional<u32> address = mem.allocateMemory(addr0, 0, size, linear, r, w, x, true);
|
std::optional<u32> address = mem.allocateMemory(addr0, 0, size, linear, r, w, x, true);
|
||||||
if (!address.has_value())
|
if (!address.has_value()) Helpers::panic("ControlMemory: Failed to allocate memory");
|
||||||
Helpers::panic("ControlMemory: Failed to allocate memory");
|
|
||||||
|
|
||||||
regs[1] = address.value();
|
regs[1] = address.value();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Operation::Map:
|
case Operation::Map: mem.mirrorMapping(addr0, addr1, size); break;
|
||||||
mem.mirrorMapping(addr0, addr1, size);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Operation::Protect:
|
case Operation::Protect:
|
||||||
Helpers::warn("Ignoring mprotect! Hope nothing goes wrong but if the game accesses invalid memory or crashes then we prolly need to implement this\n");
|
Helpers::warn(
|
||||||
|
"Ignoring mprotect! Hope nothing goes wrong but if the game accesses invalid memory or crashes then we prolly need to implement "
|
||||||
|
"this\n"
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: Helpers::warn("ControlMemory: unknown operation %X\n", operation); break;
|
default: Helpers::warn("ControlMemory: unknown operation %X\n", operation); break;
|
||||||
|
@ -106,12 +104,12 @@ void Kernel::queryMemory() {
|
||||||
regs[2] = info.size;
|
regs[2] = info.size;
|
||||||
regs[3] = info.perms;
|
regs[3] = info.perms;
|
||||||
regs[4] = info.state;
|
regs[4] = info.state;
|
||||||
regs[5] = 0; // page flags
|
regs[5] = 0; // page flags
|
||||||
}
|
}
|
||||||
|
|
||||||
// Result MapMemoryBlock(Handle memblock, u32 addr, MemoryPermission myPermissions, MemoryPermission otherPermission)
|
// Result MapMemoryBlock(HandleType memblock, u32 addr, MemoryPermission myPermissions, MemoryPermission otherPermission)
|
||||||
void Kernel::mapMemoryBlock() {
|
void Kernel::mapMemoryBlock() {
|
||||||
const Handle block = regs[0];
|
const HandleType block = regs[0];
|
||||||
u32 addr = regs[1];
|
u32 addr = regs[1];
|
||||||
const u32 myPerms = regs[2];
|
const u32 myPerms = regs[2];
|
||||||
const u32 otherPerms = regs[3];
|
const u32 otherPerms = regs[3];
|
||||||
|
@ -123,21 +121,15 @@ void Kernel::mapMemoryBlock() {
|
||||||
|
|
||||||
if (KernelHandles::isSharedMemHandle(block)) {
|
if (KernelHandles::isSharedMemHandle(block)) {
|
||||||
if (block == KernelHandles::FontSharedMemHandle && addr == 0) addr = 0x18000000;
|
if (block == KernelHandles::FontSharedMemHandle && addr == 0) addr = 0x18000000;
|
||||||
u8* ptr = mem.mapSharedMemory(block, addr, myPerms, otherPerms); // Map shared memory block
|
u8* ptr = mem.mapSharedMemory(block, addr, myPerms, otherPerms); // Map shared memory block
|
||||||
|
|
||||||
// Pass pointer to shared memory to the appropriate service
|
// Pass pointer to shared memory to the appropriate service
|
||||||
switch (block) {
|
switch (block) {
|
||||||
case KernelHandles::HIDSharedMemHandle:
|
case KernelHandles::HIDSharedMemHandle: serviceManager.setHIDSharedMem(ptr); break;
|
||||||
serviceManager.setHIDSharedMem(ptr);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case KernelHandles::GSPSharedMemHandle:
|
case KernelHandles::GSPSharedMemHandle: serviceManager.setGSPSharedMem(ptr); break;
|
||||||
serviceManager.setGSPSharedMem(ptr);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case KernelHandles::FontSharedMemHandle:
|
case KernelHandles::FontSharedMemHandle: mem.copySharedFont(ptr); break;
|
||||||
mem.copySharedFont(ptr);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case KernelHandles::CSNDSharedMemHandle:
|
case KernelHandles::CSNDSharedMemHandle:
|
||||||
serviceManager.setCSNDSharedMem(ptr);
|
serviceManager.setCSNDSharedMem(ptr);
|
||||||
|
@ -154,8 +146,8 @@ void Kernel::mapMemoryBlock() {
|
||||||
regs[0] = Result::Success;
|
regs[0] = Result::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle Kernel::makeMemoryBlock(u32 addr, u32 size, u32 myPermission, u32 otherPermission) {
|
HandleType Kernel::makeMemoryBlock(u32 addr, u32 size, u32 myPermission, u32 otherPermission) {
|
||||||
Handle ret = makeObject(KernelObjectType::MemoryBlock);
|
HandleType ret = makeObject(KernelObjectType::MemoryBlock);
|
||||||
objects[ret].data = new MemoryBlock(addr, size, myPermission, otherPermission);
|
objects[ret].data = new MemoryBlock(addr, size, myPermission, otherPermission);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -165,7 +157,7 @@ void Kernel::createMemoryBlock() {
|
||||||
const u32 addr = regs[1];
|
const u32 addr = regs[1];
|
||||||
const u32 size = regs[2];
|
const u32 size = regs[2];
|
||||||
u32 myPermission = regs[3];
|
u32 myPermission = regs[3];
|
||||||
u32 otherPermission = mem.read32(regs[13] + 4); // This is placed on the stack rather than r4
|
u32 otherPermission = mem.read32(regs[13] + 4); // This is placed on the stack rather than r4
|
||||||
logSVC("CreateMemoryBlock (addr = %08X, size = %08X, myPermission = %d, otherPermission = %d)\n", addr, size, myPermission, otherPermission);
|
logSVC("CreateMemoryBlock (addr = %08X, size = %08X, myPermission = %d, otherPermission = %d)\n", addr, size, myPermission, otherPermission);
|
||||||
|
|
||||||
// Returns whether a permission is valid
|
// Returns whether a permission is valid
|
||||||
|
@ -175,10 +167,9 @@ void Kernel::createMemoryBlock() {
|
||||||
case MemoryPermissions::Read:
|
case MemoryPermissions::Read:
|
||||||
case MemoryPermissions::Write:
|
case MemoryPermissions::Write:
|
||||||
case MemoryPermissions::ReadWrite:
|
case MemoryPermissions::ReadWrite:
|
||||||
case MemoryPermissions::DontCare:
|
case MemoryPermissions::DontCare: return true;
|
||||||
return true;
|
|
||||||
|
|
||||||
default: // Permissions with the executable flag enabled or invalid permissions are not allowed
|
default: // Permissions with the executable flag enabled or invalid permissions are not allowed
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -197,8 +188,7 @@ void Kernel::createMemoryBlock() {
|
||||||
|
|
||||||
// TODO: The address needs to be in a specific range otherwise it throws an invalid address error
|
// TODO: The address needs to be in a specific range otherwise it throws an invalid address error
|
||||||
|
|
||||||
if (addr == 0)
|
if (addr == 0) Helpers::panic("CreateMemoryBlock: Tried to use addr = 0");
|
||||||
Helpers::panic("CreateMemoryBlock: Tried to use addr = 0");
|
|
||||||
|
|
||||||
// Implement "Don't care" permission as RW
|
// Implement "Don't care" permission as RW
|
||||||
if (myPermission == MemoryPermissions::DontCare) myPermission = MemoryPermissions::ReadWrite;
|
if (myPermission == MemoryPermissions::DontCare) myPermission = MemoryPermissions::ReadWrite;
|
||||||
|
@ -209,7 +199,7 @@ void Kernel::createMemoryBlock() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::unmapMemoryBlock() {
|
void Kernel::unmapMemoryBlock() {
|
||||||
Handle block = regs[0];
|
HandleType block = regs[0];
|
||||||
u32 addr = regs[1];
|
u32 addr = regs[1];
|
||||||
logSVC("Unmap memory block (block handle = %X, addr = %08X)\n", block, addr);
|
logSVC("Unmap memory block (block handle = %X, addr = %08X)\n", block, addr);
|
||||||
|
|
||||||
|
|
|
@ -1,29 +1,30 @@
|
||||||
#include "kernel.hpp"
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
Handle Kernel::makePort(const char* name) {
|
#include "kernel.hpp"
|
||||||
Handle ret = makeObject(KernelObjectType::Port);
|
|
||||||
portHandles.push_back(ret); // Push the port handle to our cache of port handles
|
HandleType Kernel::makePort(const char* name) {
|
||||||
|
HandleType ret = makeObject(KernelObjectType::Port);
|
||||||
|
portHandles.push_back(ret); // Push the port handle to our cache of port handles
|
||||||
objects[ret].data = new Port(name);
|
objects[ret].data = new Port(name);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle Kernel::makeSession(Handle portHandle) {
|
HandleType Kernel::makeSession(HandleType portHandle) {
|
||||||
const auto port = getObject(portHandle, KernelObjectType::Port);
|
const auto port = getObject(portHandle, KernelObjectType::Port);
|
||||||
if (port == nullptr) [[unlikely]] {
|
if (port == nullptr) [[unlikely]] {
|
||||||
Helpers::panic("Trying to make session for non-existent port");
|
Helpers::panic("Trying to make session for non-existent port");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate data for session
|
// Allocate data for session
|
||||||
const Handle ret = makeObject(KernelObjectType::Session);
|
const HandleType ret = makeObject(KernelObjectType::Session);
|
||||||
objects[ret].data = new Session(portHandle);
|
objects[ret].data = new Session(portHandle);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the handle of a port based on its name
|
// Get the handle of a port based on its name
|
||||||
// If there's no such port, return nullopt
|
// If there's no such port, return nullopt
|
||||||
std::optional<Handle> Kernel::getPortHandle(const char* name) {
|
std::optional<HandleType> Kernel::getPortHandle(const char* name) {
|
||||||
for (auto handle : portHandles) {
|
for (auto handle : portHandles) {
|
||||||
const auto data = objects[handle].getData<Port>();
|
const auto data = objects[handle].getData<Port>();
|
||||||
if (std::strncmp(name, data->name, Port::maxNameLen) == 0) {
|
if (std::strncmp(name, data->name, Port::maxNameLen) == 0) {
|
||||||
|
@ -34,7 +35,7 @@ std::optional<Handle> Kernel::getPortHandle(const char* name) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Result ConnectToPort(Handle* out, const char* portName)
|
// Result ConnectToPort(HandleType* out, const char* portName)
|
||||||
void Kernel::connectToPort() {
|
void Kernel::connectToPort() {
|
||||||
const u32 handlePointer = regs[0];
|
const u32 handlePointer = regs[0];
|
||||||
// Read up to max + 1 characters to see if the name is too long
|
// Read up to max + 1 characters to see if the name is too long
|
||||||
|
@ -48,14 +49,14 @@ void Kernel::connectToPort() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try getting a handle to the port
|
// Try getting a handle to the port
|
||||||
std::optional<Handle> optionalHandle = getPortHandle(port.c_str());
|
std::optional<HandleType> optionalHandle = getPortHandle(port.c_str());
|
||||||
if (!optionalHandle.has_value()) [[unlikely]] {
|
if (!optionalHandle.has_value()) [[unlikely]] {
|
||||||
Helpers::panic("ConnectToPort: Port doesn't exist\n");
|
Helpers::panic("ConnectToPort: Port doesn't exist\n");
|
||||||
regs[0] = Result::Kernel::NotFound;
|
regs[0] = Result::Kernel::NotFound;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle portHandle = optionalHandle.value();
|
HandleType portHandle = optionalHandle.value();
|
||||||
|
|
||||||
const auto portData = objects[portHandle].getData<Port>();
|
const auto portData = objects[portHandle].getData<Port>();
|
||||||
if (!portData->isPublic) {
|
if (!portData->isPublic) {
|
||||||
|
@ -63,17 +64,17 @@ void Kernel::connectToPort() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Actually create session
|
// TODO: Actually create session
|
||||||
Handle sessionHandle = makeSession(portHandle);
|
HandleType sessionHandle = makeSession(portHandle);
|
||||||
|
|
||||||
regs[0] = Result::Success;
|
regs[0] = Result::Success;
|
||||||
regs[1] = sessionHandle;
|
regs[1] = sessionHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Result SendSyncRequest(Handle session)
|
// Result SendSyncRequest(HandleType session)
|
||||||
// Send an IPC message to a port (typically "srv:") or a service
|
// Send an IPC message to a port (typically "srv:") or a service
|
||||||
void Kernel::sendSyncRequest() {
|
void Kernel::sendSyncRequest() {
|
||||||
const auto handle = regs[0];
|
const auto handle = regs[0];
|
||||||
u32 messagePointer = getTLSPointer() + 0x80; // The message is stored starting at TLS+0x80
|
u32 messagePointer = getTLSPointer() + 0x80; // The message is stored starting at TLS+0x80
|
||||||
logSVC("SendSyncRequest(session handle = %X)\n", handle);
|
logSVC("SendSyncRequest(session handle = %X)\n", handle);
|
||||||
|
|
||||||
// Service calls via SendSyncRequest and file access needs to put the caller to sleep for a given amount of time
|
// Service calls via SendSyncRequest and file access needs to put the caller to sleep for a given amount of time
|
||||||
|
@ -93,7 +94,7 @@ void Kernel::sendSyncRequest() {
|
||||||
// Check if our sync request is targetting a file instead of a service
|
// Check if our sync request is targetting a file instead of a service
|
||||||
bool isFileOperation = getObject(handle, KernelObjectType::File) != nullptr;
|
bool isFileOperation = getObject(handle, KernelObjectType::File) != nullptr;
|
||||||
if (isFileOperation) {
|
if (isFileOperation) {
|
||||||
regs[0] = Result::Success; // r0 goes first here too
|
regs[0] = Result::Success; // r0 goes first here too
|
||||||
handleFileOperation(messagePointer, handle);
|
handleFileOperation(messagePointer, handle);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -101,7 +102,7 @@ void Kernel::sendSyncRequest() {
|
||||||
// Check if our sync request is targetting a directory instead of a service
|
// Check if our sync request is targetting a directory instead of a service
|
||||||
bool isDirectoryOperation = getObject(handle, KernelObjectType::Directory) != nullptr;
|
bool isDirectoryOperation = getObject(handle, KernelObjectType::Directory) != nullptr;
|
||||||
if (isDirectoryOperation) {
|
if (isDirectoryOperation) {
|
||||||
regs[0] = Result::Success; // r0 goes first here too
|
regs[0] = Result::Success; // r0 goes first here too
|
||||||
handleDirectoryOperation(messagePointer, handle);
|
handleDirectoryOperation(messagePointer, handle);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -115,12 +116,12 @@ void Kernel::sendSyncRequest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto sessionData = static_cast<Session*>(session->data);
|
const auto sessionData = static_cast<Session*>(session->data);
|
||||||
const Handle portHandle = sessionData->portHandle;
|
const HandleType portHandle = sessionData->portHandle;
|
||||||
|
|
||||||
if (portHandle == srvHandle) { // Special-case SendSyncRequest targetting the "srv: port"
|
if (portHandle == srvHandle) { // Special-case SendSyncRequest targetting the "srv: port"
|
||||||
regs[0] = Result::Success;
|
regs[0] = Result::Success;
|
||||||
serviceManager.handleSyncRequest(messagePointer);
|
serviceManager.handleSyncRequest(messagePointer);
|
||||||
} else if (portHandle == errorPortHandle) { // Special-case "err:f" for juicy logs too
|
} else if (portHandle == errorPortHandle) { // Special-case "err:f" for juicy logs too
|
||||||
regs[0] = Result::Success;
|
regs[0] = Result::Success;
|
||||||
handleErrorSyncRequest(messagePointer);
|
handleErrorSyncRequest(messagePointer);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#include "resource_limits.hpp"
|
#include "resource_limits.hpp"
|
||||||
|
|
||||||
#include "kernel.hpp"
|
#include "kernel.hpp"
|
||||||
|
|
||||||
// Result GetResourceLimit(Handle* resourceLimit, Handle process)
|
// Result GetResourceLimit(HandleType* resourceLimit, HandleType process)
|
||||||
// out: r0 -> result, r1 -> handle
|
// out: r0 -> result, r1 -> handle
|
||||||
void Kernel::getResourceLimit() {
|
void Kernel::getResourceLimit() {
|
||||||
const auto handlePointer = regs[0];
|
const auto handlePointer = regs[0];
|
||||||
|
@ -20,10 +21,10 @@ void Kernel::getResourceLimit() {
|
||||||
regs[1] = processData->limits.handle;
|
regs[1] = processData->limits.handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Result GetResourceLimitLimitValues(s64* values, Handle resourceLimit, LimitableResource* names, s32 nameCount)
|
// Result GetResourceLimitLimitValues(s64* values, HandleType resourceLimit, LimitableResource* names, s32 nameCount)
|
||||||
void Kernel::getResourceLimitLimitValues() {
|
void Kernel::getResourceLimitLimitValues() {
|
||||||
u32 values = regs[0]; // Pointer to values (The resource limits get output here)
|
u32 values = regs[0]; // Pointer to values (The resource limits get output here)
|
||||||
const Handle resourceLimit = regs[1];
|
const HandleType resourceLimit = regs[1];
|
||||||
u32 names = regs[2]; // Pointer to resources that we should return
|
u32 names = regs[2]; // Pointer to resources that we should return
|
||||||
u32 count = regs[3]; // Number of resources
|
u32 count = regs[3]; // Number of resources
|
||||||
|
|
||||||
|
@ -49,10 +50,10 @@ void Kernel::getResourceLimitLimitValues() {
|
||||||
regs[0] = Result::Success;
|
regs[0] = Result::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Result GetResourceLimitCurrentValues(s64* values, Handle resourceLimit, LimitableResource* names, s32 nameCount)
|
// Result GetResourceLimitCurrentValues(s64* values, HandleType resourceLimit, LimitableResource* names, s32 nameCount)
|
||||||
void Kernel::getResourceLimitCurrentValues() {
|
void Kernel::getResourceLimitCurrentValues() {
|
||||||
u32 values = regs[0]; // Pointer to values (The resource limits get output here)
|
u32 values = regs[0]; // Pointer to values (The resource limits get output here)
|
||||||
const Handle resourceLimit = regs[1];
|
const HandleType resourceLimit = regs[1];
|
||||||
u32 names = regs[2]; // Pointer to resources that we should return
|
u32 names = regs[2]; // Pointer to resources that we should return
|
||||||
u32 count = regs[3]; // Number of resources
|
u32 count = regs[3]; // Number of resources
|
||||||
logSVC("GetResourceLimitCurrentValues(values = %08X, handle = %X, names = %08X, count = %d)\n", values, resourceLimit, names, count);
|
logSVC("GetResourceLimitCurrentValues(values = %08X, handle = %X, names = %08X, count = %d)\n", values, resourceLimit, names, count);
|
||||||
|
|
|
@ -33,7 +33,7 @@ void Kernel::switchThread(int newThreadIndex) {
|
||||||
std::memcpy(cpu.fprs().data(), newThread.fprs.data(), cpu.fprs().size_bytes()); // Load 32 FPRs
|
std::memcpy(cpu.fprs().data(), newThread.fprs.data(), cpu.fprs().size_bytes()); // Load 32 FPRs
|
||||||
cpu.setCPSR(newThread.cpsr); // Load CPSR
|
cpu.setCPSR(newThread.cpsr); // Load CPSR
|
||||||
cpu.setFPSCR(newThread.fpscr); // Load FPSCR
|
cpu.setFPSCR(newThread.fpscr); // Load FPSCR
|
||||||
cpu.setTLSBase(newThread.tlsBase); // Load CP15 thread-local-storage pointer register
|
cpu.setTLSBase(newThread.tlsBase); // Load CP15 thread-local-storage pointer register
|
||||||
|
|
||||||
currentThreadIndex = newThreadIndex;
|
currentThreadIndex = newThreadIndex;
|
||||||
}
|
}
|
||||||
|
@ -42,21 +42,19 @@ void Kernel::switchThread(int newThreadIndex) {
|
||||||
// The threads with higher priority (aka the ones with a lower priority value) should come first in the vector
|
// The threads with higher priority (aka the ones with a lower priority value) should come first in the vector
|
||||||
void Kernel::sortThreads() {
|
void Kernel::sortThreads() {
|
||||||
std::vector<int>& v = threadIndices;
|
std::vector<int>& v = threadIndices;
|
||||||
std::sort(v.begin(), v.end(), [&](int a, int b) {
|
std::sort(v.begin(), v.end(), [&](int a, int b) { return threads[a].priority < threads[b].priority; });
|
||||||
return threads[a].priority < threads[b].priority;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Kernel::canThreadRun(const Thread& t) {
|
bool Kernel::canThreadRun(const Thread& t) {
|
||||||
if (t.status == ThreadStatus::Ready) {
|
if (t.status == ThreadStatus::Ready) {
|
||||||
return true;
|
return true;
|
||||||
} else if (t.status == ThreadStatus::WaitSleep || t.status == ThreadStatus::WaitSync1
|
} else if (t.status == ThreadStatus::WaitSleep || t.status == ThreadStatus::WaitSync1 || t.status == ThreadStatus::WaitSyncAny ||
|
||||||
|| t.status == ThreadStatus::WaitSyncAny || t.status == ThreadStatus::WaitSyncAll) {
|
t.status == ThreadStatus::WaitSyncAll) {
|
||||||
// TODO: Set r0 to the correct error code on timeout for WaitSync{1/Any/All}
|
// TODO: Set r0 to the correct error code on timeout for WaitSync{1/Any/All}
|
||||||
return cpu.getTicks() >= t.wakeupTick;
|
return cpu.getTicks() >= t.wakeupTick;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle timeouts and stuff here
|
// HandleType timeouts and stuff here
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,8 +98,8 @@ void Kernel::rescheduleThreads() {
|
||||||
// Case 1: A thread can run
|
// Case 1: A thread can run
|
||||||
if (newThreadIndex.has_value()) {
|
if (newThreadIndex.has_value()) {
|
||||||
switchThread(newThreadIndex.value());
|
switchThread(newThreadIndex.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Case 2: No other thread can run, straight to the idle thread
|
// Case 2: No other thread can run, straight to the idle thread
|
||||||
else {
|
else {
|
||||||
switchThread(idleThreadIndex);
|
switchThread(idleThreadIndex);
|
||||||
|
@ -109,30 +107,30 @@ void Kernel::rescheduleThreads() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal OS function to spawn a thread
|
// Internal OS function to spawn a thread
|
||||||
Handle Kernel::makeThread(u32 entrypoint, u32 initialSP, u32 priority, ProcessorID id, u32 arg, ThreadStatus status) {
|
HandleType Kernel::makeThread(u32 entrypoint, u32 initialSP, u32 priority, ProcessorID id, u32 arg, ThreadStatus status) {
|
||||||
int index; // Index of the created thread in the threads array
|
int index; // Index of the created thread in the threads array
|
||||||
|
|
||||||
if (threadCount < appResourceLimits.maxThreads) [[likely]] { // If we have not yet created over too many threads
|
if (threadCount < appResourceLimits.maxThreads) [[likely]] { // If we have not yet created over too many threads
|
||||||
index = threadCount++;
|
index = threadCount++;
|
||||||
} else if (aliveThreadCount < appResourceLimits.maxThreads) { // If we have created many threads but at least one is dead & reusable
|
} else if (aliveThreadCount < appResourceLimits.maxThreads) { // If we have created many threads but at least one is dead & reusable
|
||||||
for (int i = 0; i < threads.size(); i++) {
|
for (int i = 0; i < threads.size(); i++) {
|
||||||
if (threads[i].status == ThreadStatus::Dead) {
|
if (threads[i].status == ThreadStatus::Dead) {
|
||||||
index = i;
|
index = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else { // There is no thread we can use, we're screwed
|
} else { // There is no thread we can use, we're screwed
|
||||||
Helpers::panic("Overflowed thread count!!");
|
Helpers::panic("Overflowed thread count!!");
|
||||||
}
|
}
|
||||||
|
|
||||||
aliveThreadCount++;
|
aliveThreadCount++;
|
||||||
|
|
||||||
threadIndices.push_back(index);
|
threadIndices.push_back(index);
|
||||||
Thread& t = threads[index]; // Reference to thread data
|
Thread& t = threads[index]; // Reference to thread data
|
||||||
Handle ret = makeObject(KernelObjectType::Thread);
|
HandleType ret = makeObject(KernelObjectType::Thread);
|
||||||
objects[ret].data = &t;
|
objects[ret].data = &t;
|
||||||
|
|
||||||
const bool isThumb = (entrypoint & 1) != 0; // Whether the thread starts in thumb mode or not
|
const bool isThumb = (entrypoint & 1) != 0; // Whether the thread starts in thumb mode or not
|
||||||
|
|
||||||
// Set up initial thread context
|
// Set up initial thread context
|
||||||
t.gprs.fill(0);
|
t.gprs.fill(0);
|
||||||
|
@ -150,7 +148,7 @@ Handle Kernel::makeThread(u32 entrypoint, u32 initialSP, u32 priority, Processor
|
||||||
t.status = status;
|
t.status = status;
|
||||||
t.handle = ret;
|
t.handle = ret;
|
||||||
t.waitingAddress = 0;
|
t.waitingAddress = 0;
|
||||||
t.threadsWaitingForTermination = 0; // Thread just spawned, no other threads waiting for it to terminate
|
t.threadsWaitingForTermination = 0; // Thread just spawned, no other threads waiting for it to terminate
|
||||||
|
|
||||||
t.cpsr = CPSR::UserMode | (isThumb ? CPSR::Thumb : 0);
|
t.cpsr = CPSR::UserMode | (isThumb ? CPSR::Thumb : 0);
|
||||||
t.fpscr = FPSCR::ThreadDefault;
|
t.fpscr = FPSCR::ThreadDefault;
|
||||||
|
@ -161,8 +159,8 @@ Handle Kernel::makeThread(u32 entrypoint, u32 initialSP, u32 priority, Processor
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle Kernel::makeMutex(bool locked) {
|
HandleType Kernel::makeMutex(bool locked) {
|
||||||
Handle ret = makeObject(KernelObjectType::Mutex);
|
HandleType ret = makeObject(KernelObjectType::Mutex);
|
||||||
objects[ret].data = new Mutex(locked, ret);
|
objects[ret].data = new Mutex(locked, ret);
|
||||||
|
|
||||||
// If the mutex is initially locked, store the index of the thread that owns it and set lock count to 1
|
// If the mutex is initially locked, store the index of the thread that owns it and set lock count to 1
|
||||||
|
@ -181,15 +179,15 @@ Handle Kernel::makeMutex(bool locked) {
|
||||||
|
|
||||||
void Kernel::releaseMutex(Mutex* moo) {
|
void Kernel::releaseMutex(Mutex* moo) {
|
||||||
// TODO: Assert lockCount > 0 before release, maybe. The SVC should be safe at least.
|
// TODO: Assert lockCount > 0 before release, maybe. The SVC should be safe at least.
|
||||||
moo->lockCount--; // Decrement lock count
|
moo->lockCount--; // Decrement lock count
|
||||||
|
|
||||||
// If the lock count reached 0 then the thread no longer owns the mootex and it can be given to a new one
|
// If the lock count reached 0 then the thread no longer owns the mootex and it can be given to a new one
|
||||||
if (moo->lockCount == 0) {
|
if (moo->lockCount == 0) {
|
||||||
moo->locked = false;
|
moo->locked = false;
|
||||||
|
|
||||||
if (moo->waitlist != 0) {
|
if (moo->waitlist != 0) {
|
||||||
int index = wakeupOneThread(moo->waitlist, moo->handle); // Wake up one thread and get its index
|
int index = wakeupOneThread(moo->waitlist, moo->handle); // Wake up one thread and get its index
|
||||||
moo->waitlist ^= (1ull << index); // Remove thread from waitlist
|
moo->waitlist ^= (1ull << index); // Remove thread from waitlist
|
||||||
|
|
||||||
// Have new thread acquire mutex
|
// Have new thread acquire mutex
|
||||||
moo->locked = true;
|
moo->locked = true;
|
||||||
|
@ -201,8 +199,8 @@ void Kernel::releaseMutex(Mutex* moo) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle Kernel::makeSemaphore(u32 initialCount, u32 maximumCount) {
|
HandleType Kernel::makeSemaphore(u32 initialCount, u32 maximumCount) {
|
||||||
Handle ret = makeObject(KernelObjectType::Semaphore);
|
HandleType ret = makeObject(KernelObjectType::Semaphore);
|
||||||
objects[ret].data = new Semaphore(initialCount, maximumCount);
|
objects[ret].data = new Semaphore(initialCount, maximumCount);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -221,7 +219,7 @@ void Kernel::acquireSyncObject(KernelObject* object, const Thread& thread) {
|
||||||
switch (object->type) {
|
switch (object->type) {
|
||||||
case KernelObjectType::Event: {
|
case KernelObjectType::Event: {
|
||||||
Event* e = object->getData<Event>();
|
Event* e = object->getData<Event>();
|
||||||
if (e->resetType == ResetType::OneShot) { // One-shot events automatically get cleared after waking up a thread
|
if (e->resetType == ResetType::OneShot) { // One-shot events automatically get cleared after waking up a thread
|
||||||
e->fired = false;
|
e->fired = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -245,15 +243,14 @@ void Kernel::acquireSyncObject(KernelObject* object, const Thread& thread) {
|
||||||
|
|
||||||
case KernelObjectType::Semaphore: {
|
case KernelObjectType::Semaphore: {
|
||||||
Semaphore* s = object->getData<Semaphore>();
|
Semaphore* s = object->getData<Semaphore>();
|
||||||
if (s->availableCount <= 0) [[unlikely]] // This should be unreachable but let's check anyways
|
if (s->availableCount <= 0) [[unlikely]] // This should be unreachable but let's check anyways
|
||||||
Helpers::panic("Tried to acquire unacquirable semaphore");
|
Helpers::panic("Tried to acquire unacquirable semaphore");
|
||||||
|
|
||||||
s->availableCount -= 1;
|
s->availableCount -= 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case KernelObjectType::Thread:
|
case KernelObjectType::Thread: break;
|
||||||
break;
|
|
||||||
|
|
||||||
case KernelObjectType::Timer: {
|
case KernelObjectType::Timer: {
|
||||||
Timer* timer = object->getData<Timer>();
|
Timer* timer = object->getData<Timer>();
|
||||||
|
@ -269,36 +266,36 @@ void Kernel::acquireSyncObject(KernelObject* object, const Thread& thread) {
|
||||||
|
|
||||||
// Wake up one of the threads in the waitlist (the one with highest prio) and return its index
|
// Wake up one of the threads in the waitlist (the one with highest prio) and return its index
|
||||||
// Must not be called with an empty waitlist
|
// Must not be called with an empty waitlist
|
||||||
int Kernel::wakeupOneThread(u64 waitlist, Handle handle) {
|
int Kernel::wakeupOneThread(u64 waitlist, HandleType handle) {
|
||||||
if (waitlist == 0) [[unlikely]]
|
if (waitlist == 0) [[unlikely]]
|
||||||
Helpers::panic("[Internal error] It shouldn't be possible to call wakeupOneThread when there's 0 threads waiting!");
|
Helpers::panic("[Internal error] It shouldn't be possible to call wakeupOneThread when there's 0 threads waiting!");
|
||||||
|
|
||||||
// Find the waiting thread with the highest priority.
|
// Find the waiting thread with the highest priority.
|
||||||
// We do this by first picking the first thread in the waitlist, then checking each other thread and comparing priority
|
// We do this by first picking the first thread in the waitlist, then checking each other thread and comparing priority
|
||||||
int threadIndex = std::countr_zero(waitlist); // Index of first thread
|
int threadIndex = std::countr_zero(waitlist); // Index of first thread
|
||||||
int maxPriority = threads[threadIndex].priority; // Set initial max prio to the prio of the first thread
|
int maxPriority = threads[threadIndex].priority; // Set initial max prio to the prio of the first thread
|
||||||
waitlist ^= (1ull << threadIndex); // Remove thread from the waitlist
|
waitlist ^= (1ull << threadIndex); // Remove thread from the waitlist
|
||||||
|
|
||||||
while (waitlist != 0) {
|
while (waitlist != 0) {
|
||||||
int newThread = std::countr_zero(waitlist); // Get new thread and evaluate whether it has a higher priority
|
int newThread = std::countr_zero(waitlist); // Get new thread and evaluate whether it has a higher priority
|
||||||
if (threads[newThread].priority < maxPriority) { // Low priority value means high priority
|
if (threads[newThread].priority < maxPriority) { // Low priority value means high priority
|
||||||
threadIndex = newThread;
|
threadIndex = newThread;
|
||||||
maxPriority = threads[newThread].priority;
|
maxPriority = threads[newThread].priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
waitlist ^= (1ull << threadIndex); // Remove thread from waitlist
|
waitlist ^= (1ull << threadIndex); // Remove thread from waitlist
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread& t = threads[threadIndex];
|
Thread& t = threads[threadIndex];
|
||||||
switch (t.status) {
|
switch (t.status) {
|
||||||
case ThreadStatus::WaitSync1:
|
case ThreadStatus::WaitSync1:
|
||||||
t.status = ThreadStatus::Ready;
|
t.status = ThreadStatus::Ready;
|
||||||
t.gprs[0] = Result::Success; // The thread did not timeout, so write success to r0
|
t.gprs[0] = Result::Success; // The thread did not timeout, so write success to r0
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ThreadStatus::WaitSyncAny:
|
case ThreadStatus::WaitSyncAny:
|
||||||
t.status = ThreadStatus::Ready;
|
t.status = ThreadStatus::Ready;
|
||||||
t.gprs[0] = Result::Success; // The thread did not timeout, so write success to r0
|
t.gprs[0] = Result::Success; // The thread did not timeout, so write success to r0
|
||||||
|
|
||||||
// Get the index of the event in the object's waitlist, write it to r1
|
// Get the index of the event in the object's waitlist, write it to r1
|
||||||
for (size_t i = 0; i < t.waitList.size(); i++) {
|
for (size_t i = 0; i < t.waitList.size(); i++) {
|
||||||
|
@ -309,44 +306,40 @@ int Kernel::wakeupOneThread(u64 waitlist, Handle handle) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ThreadStatus::WaitSyncAll:
|
case ThreadStatus::WaitSyncAll: Helpers::panic("WakeupOneThread: Thread on WaitSyncAll"); break;
|
||||||
Helpers::panic("WakeupOneThread: Thread on WaitSyncAll");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return threadIndex;
|
return threadIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wake up every single thread in the waitlist using a bit scanning algorithm
|
// Wake up every single thread in the waitlist using a bit scanning algorithm
|
||||||
void Kernel::wakeupAllThreads(u64 waitlist, Handle handle) {
|
void Kernel::wakeupAllThreads(u64 waitlist, HandleType handle) {
|
||||||
while (waitlist != 0) {
|
while (waitlist != 0) {
|
||||||
const uint index = std::countr_zero(waitlist); // Get one of the set bits to see which thread is waiting
|
const uint index = std::countr_zero(waitlist); // Get one of the set bits to see which thread is waiting
|
||||||
waitlist ^= (1ull << index); // Remove thread from waitlist by toggling its bit
|
waitlist ^= (1ull << index); // Remove thread from waitlist by toggling its bit
|
||||||
|
|
||||||
// Get the thread we'll be signalling
|
// Get the thread we'll be signalling
|
||||||
Thread& t = threads[index];
|
Thread& t = threads[index];
|
||||||
switch (t.status) {
|
switch (t.status) {
|
||||||
case ThreadStatus::WaitSync1:
|
case ThreadStatus::WaitSync1:
|
||||||
t.status = ThreadStatus::Ready;
|
t.status = ThreadStatus::Ready;
|
||||||
t.gprs[0] = Result::Success; // The thread did not timeout, so write success to r0
|
t.gprs[0] = Result::Success; // The thread did not timeout, so write success to r0
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ThreadStatus::WaitSyncAny:
|
case ThreadStatus::WaitSyncAny:
|
||||||
t.status = ThreadStatus::Ready;
|
t.status = ThreadStatus::Ready;
|
||||||
t.gprs[0] = Result::Success; // The thread did not timeout, so write success to r0
|
t.gprs[0] = Result::Success; // The thread did not timeout, so write success to r0
|
||||||
|
|
||||||
// Get the index of the event in the object's waitlist, write it to r1
|
// Get the index of the event in the object's waitlist, write it to r1
|
||||||
for (size_t i = 0; i < t.waitList.size(); i++) {
|
for (size_t i = 0; i < t.waitList.size(); i++) {
|
||||||
if (t.waitList[i] == handle) {
|
if (t.waitList[i] == handle) {
|
||||||
t.gprs[1] = u32(i);
|
t.gprs[1] = u32(i);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
break;
|
|
||||||
|
|
||||||
case ThreadStatus::WaitSyncAll:
|
case ThreadStatus::WaitSyncAll: Helpers::panic("WakeupAllThreads: Thread on WaitSyncAll"); break;
|
||||||
Helpers::panic("WakeupAllThreads: Thread on WaitSyncAll");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -404,12 +397,11 @@ void Kernel::sleepThread(s64 ns) {
|
||||||
void Kernel::createThread() {
|
void Kernel::createThread() {
|
||||||
u32 priority = regs[0];
|
u32 priority = regs[0];
|
||||||
u32 entrypoint = regs[1];
|
u32 entrypoint = regs[1];
|
||||||
u32 arg = regs[2]; // An argument value stored in r0 of the new thread
|
u32 arg = regs[2]; // An argument value stored in r0 of the new thread
|
||||||
u32 initialSP = regs[3] & ~7; // SP is force-aligned to 8 bytes
|
u32 initialSP = regs[3] & ~7; // SP is force-aligned to 8 bytes
|
||||||
s32 id = static_cast<s32>(regs[4]);
|
s32 id = static_cast<s32>(regs[4]);
|
||||||
|
|
||||||
logSVC("CreateThread(entry = %08X, stacktop = %08X, arg = %X, priority = %X, processor ID = %d)\n", entrypoint,
|
logSVC("CreateThread(entry = %08X, stacktop = %08X, arg = %X, priority = %X, processor ID = %d)\n", entrypoint, initialSP, arg, priority, id);
|
||||||
initialSP, arg, priority, id);
|
|
||||||
|
|
||||||
if (priority > 0x3F) [[unlikely]] {
|
if (priority > 0x3F) [[unlikely]] {
|
||||||
Helpers::panic("Created thread with bad priority value %X", priority);
|
Helpers::panic("Created thread with bad priority value %X", priority);
|
||||||
|
@ -429,14 +421,14 @@ void Kernel::createThread() {
|
||||||
// void SleepThread(s64 nanoseconds)
|
// void SleepThread(s64 nanoseconds)
|
||||||
void Kernel::svcSleepThread() {
|
void Kernel::svcSleepThread() {
|
||||||
const s64 ns = s64(u64(regs[0]) | (u64(regs[1]) << 32));
|
const s64 ns = s64(u64(regs[0]) | (u64(regs[1]) << 32));
|
||||||
//logSVC("SleepThread(ns = %lld)\n", ns);
|
// logSVC("SleepThread(ns = %lld)\n", ns);
|
||||||
|
|
||||||
regs[0] = Result::Success;
|
regs[0] = Result::Success;
|
||||||
sleepThread(ns);
|
sleepThread(ns);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::getThreadID() {
|
void Kernel::getThreadID() {
|
||||||
Handle handle = regs[1];
|
HandleType handle = regs[1];
|
||||||
logSVC("GetThreadID(handle = %X)\n", handle);
|
logSVC("GetThreadID(handle = %X)\n", handle);
|
||||||
|
|
||||||
if (handle == KernelHandles::CurrentThread) {
|
if (handle == KernelHandles::CurrentThread) {
|
||||||
|
@ -456,7 +448,7 @@ void Kernel::getThreadID() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::getThreadPriority() {
|
void Kernel::getThreadPriority() {
|
||||||
const Handle handle = regs[1];
|
const HandleType handle = regs[1];
|
||||||
logSVC("GetThreadPriority (handle = %X)\n", handle);
|
logSVC("GetThreadPriority (handle = %X)\n", handle);
|
||||||
|
|
||||||
if (handle == KernelHandles::CurrentThread) {
|
if (handle == KernelHandles::CurrentThread) {
|
||||||
|
@ -474,7 +466,7 @@ void Kernel::getThreadPriority() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::getThreadIdealProcessor() {
|
void Kernel::getThreadIdealProcessor() {
|
||||||
const Handle handle = regs[1]; // Thread handle
|
const HandleType handle = regs[1]; // Thread handle
|
||||||
logSVC("GetThreadIdealProcessor (handle = %X)\n", handle);
|
logSVC("GetThreadIdealProcessor (handle = %X)\n", handle);
|
||||||
|
|
||||||
// TODO: Not documented what this is or what it does. Citra doesn't implement it at all. Return AppCore as the ideal processor for now
|
// TODO: Not documented what this is or what it does. Citra doesn't implement it at all. Return AppCore as the ideal processor for now
|
||||||
|
@ -490,7 +482,7 @@ void Kernel::getThreadContext() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::setThreadPriority() {
|
void Kernel::setThreadPriority() {
|
||||||
const Handle handle = regs[0];
|
const HandleType handle = regs[0];
|
||||||
const u32 priority = regs[1];
|
const u32 priority = regs[1];
|
||||||
logSVC("SetThreadPriority (handle = %X, priority = %X)\n", handle, priority);
|
logSVC("SetThreadPriority (handle = %X, priority = %X)\n", handle, priority);
|
||||||
|
|
||||||
|
@ -524,9 +516,7 @@ void Kernel::getCurrentProcessorNumber() {
|
||||||
// Until we properly implement per-core schedulers, return whatever processor ID passed to svcCreateThread
|
// Until we properly implement per-core schedulers, return whatever processor ID passed to svcCreateThread
|
||||||
switch (id) {
|
switch (id) {
|
||||||
// TODO: This is picked from exheader
|
// TODO: This is picked from exheader
|
||||||
case ProcessorID::Default:
|
case ProcessorID::Default: ret = static_cast<s32>(ProcessorID::AppCore); break;
|
||||||
ret = static_cast<s32>(ProcessorID::AppCore);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ProcessorID::AllCPUs:
|
case ProcessorID::AllCPUs:
|
||||||
ret = static_cast<s32>(ProcessorID::AppCore);
|
ret = static_cast<s32>(ProcessorID::AppCore);
|
||||||
|
@ -565,8 +555,7 @@ void Kernel::exitThread() {
|
||||||
|
|
||||||
// Remove the index of this thread from the thread indices vector
|
// Remove the index of this thread from the thread indices vector
|
||||||
for (int i = 0; i < threadIndices.size(); i++) {
|
for (int i = 0; i < threadIndices.size(); i++) {
|
||||||
if (threadIndices[i] == currentThreadIndex)
|
if (threadIndices[i] == currentThreadIndex) threadIndices.erase(threadIndices.begin() + i);
|
||||||
threadIndices.erase(threadIndices.begin() + i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread& t = threads[currentThreadIndex];
|
Thread& t = threads[currentThreadIndex];
|
||||||
|
@ -576,9 +565,9 @@ void Kernel::exitThread() {
|
||||||
// Check if any threads are sleeping, waiting for this thread to terminate, and wake them up
|
// Check if any threads are sleeping, waiting for this thread to terminate, and wake them up
|
||||||
// This is how thread joining is implemented in the kernel - you wait on a thread, like any other wait object.
|
// This is how thread joining is implemented in the kernel - you wait on a thread, like any other wait object.
|
||||||
if (t.threadsWaitingForTermination != 0) {
|
if (t.threadsWaitingForTermination != 0) {
|
||||||
// TODO: Handle cloned handles? Not sure how those interact with wait object signalling
|
// TODO: HandleType cloned handles? Not sure how those interact with wait object signalling
|
||||||
wakeupAllThreads(t.threadsWaitingForTermination, t.handle);
|
wakeupAllThreads(t.threadsWaitingForTermination, t.handle);
|
||||||
t.threadsWaitingForTermination = 0; // No other threads waiting
|
t.threadsWaitingForTermination = 0; // No other threads waiting
|
||||||
}
|
}
|
||||||
|
|
||||||
requireReschedule();
|
requireReschedule();
|
||||||
|
@ -593,7 +582,7 @@ void Kernel::svcCreateMutex() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::svcReleaseMutex() {
|
void Kernel::svcReleaseMutex() {
|
||||||
const Handle handle = regs[0];
|
const HandleType handle = regs[0];
|
||||||
logSVC("ReleaseMutex (handle = %x)\n", handle);
|
logSVC("ReleaseMutex (handle = %x)\n", handle);
|
||||||
|
|
||||||
const auto object = getObject(handle, KernelObjectType::Mutex);
|
const auto object = getObject(handle, KernelObjectType::Mutex);
|
||||||
|
@ -619,18 +608,16 @@ void Kernel::svcCreateSemaphore() {
|
||||||
s32 maxCount = static_cast<s32>(regs[2]);
|
s32 maxCount = static_cast<s32>(regs[2]);
|
||||||
logSVC("CreateSemaphore (initial count = %d, max count = %d)\n", initialCount, maxCount);
|
logSVC("CreateSemaphore (initial count = %d, max count = %d)\n", initialCount, maxCount);
|
||||||
|
|
||||||
if (initialCount > maxCount)
|
if (initialCount > maxCount) Helpers::panic("CreateSemaphore: Initial count higher than max count");
|
||||||
Helpers::panic("CreateSemaphore: Initial count higher than max count");
|
|
||||||
|
|
||||||
if (initialCount < 0 || maxCount < 0)
|
if (initialCount < 0 || maxCount < 0) Helpers::panic("CreateSemaphore: Negative count value");
|
||||||
Helpers::panic("CreateSemaphore: Negative count value");
|
|
||||||
|
|
||||||
regs[0] = Result::Success;
|
regs[0] = Result::Success;
|
||||||
regs[1] = makeSemaphore(initialCount, maxCount);
|
regs[1] = makeSemaphore(initialCount, maxCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::svcReleaseSemaphore() {
|
void Kernel::svcReleaseSemaphore() {
|
||||||
const Handle handle = regs[1];
|
const HandleType handle = regs[1];
|
||||||
const s32 releaseCount = static_cast<s32>(regs[2]);
|
const s32 releaseCount = static_cast<s32>(regs[2]);
|
||||||
logSVC("ReleaseSemaphore (handle = %X, release count = %d)\n", handle, releaseCount);
|
logSVC("ReleaseSemaphore (handle = %X, release count = %d)\n", handle, releaseCount);
|
||||||
|
|
||||||
|
@ -641,12 +628,10 @@ void Kernel::svcReleaseSemaphore() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (releaseCount < 0)
|
if (releaseCount < 0) Helpers::panic("ReleaseSemaphore: Negative count");
|
||||||
Helpers::panic("ReleaseSemaphore: Negative count");
|
|
||||||
|
|
||||||
Semaphore* s = object->getData<Semaphore>();
|
Semaphore* s = object->getData<Semaphore>();
|
||||||
if (s->maximumCount - s->availableCount < releaseCount)
|
if (s->maximumCount - s->availableCount < releaseCount) Helpers::panic("ReleaseSemaphore: Release count too high");
|
||||||
Helpers::panic("ReleaseSemaphore: Release count too high");
|
|
||||||
|
|
||||||
// Write success and old available count to r0 and r1 respectively
|
// Write success and old available count to r0 and r1 respectively
|
||||||
regs[0] = Result::Success;
|
regs[0] = Result::Success;
|
||||||
|
@ -656,10 +641,10 @@ void Kernel::svcReleaseSemaphore() {
|
||||||
|
|
||||||
// Wake up threads one by one until the available count hits 0 or we run out of threads to wake up
|
// Wake up threads one by one until the available count hits 0 or we run out of threads to wake up
|
||||||
while (s->availableCount > 0 && s->waitlist != 0) {
|
while (s->availableCount > 0 && s->waitlist != 0) {
|
||||||
int index = wakeupOneThread(s->waitlist, handle); // Wake up highest priority thread
|
int index = wakeupOneThread(s->waitlist, handle); // Wake up highest priority thread
|
||||||
s->waitlist ^= (1ull << index); // Remove thread from waitlist
|
s->waitlist ^= (1ull << index); // Remove thread from waitlist
|
||||||
|
|
||||||
s->availableCount--; // Decrement available count
|
s->availableCount--; // Decrement available count
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -675,25 +660,23 @@ bool Kernel::isWaitable(const KernelObject* object) {
|
||||||
// Returns whether we should wait on a sync object or not
|
// Returns whether we should wait on a sync object or not
|
||||||
bool Kernel::shouldWaitOnObject(KernelObject* object) {
|
bool Kernel::shouldWaitOnObject(KernelObject* object) {
|
||||||
switch (object->type) {
|
switch (object->type) {
|
||||||
case KernelObjectType::Event: // We should wait on an event only if it has not been signalled
|
case KernelObjectType::Event: // We should wait on an event only if it has not been signalled
|
||||||
return !object->getData<Event>()->fired;
|
return !object->getData<Event>()->fired;
|
||||||
|
|
||||||
case KernelObjectType::Mutex: {
|
case KernelObjectType::Mutex: {
|
||||||
Mutex* moo = object->getData<Mutex>(); // mooooooooooo
|
Mutex* moo = object->getData<Mutex>(); // mooooooooooo
|
||||||
return moo->locked && moo->ownerThread != currentThreadIndex; // If the current thread owns the moo then no reason to wait
|
return moo->locked && moo->ownerThread != currentThreadIndex; // If the current thread owns the moo then no reason to wait
|
||||||
}
|
}
|
||||||
|
|
||||||
case KernelObjectType::Thread: // Waiting on a thread waits until it's dead. If it's dead then no need to wait
|
case KernelObjectType::Thread: // Waiting on a thread waits until it's dead. If it's dead then no need to wait
|
||||||
return object->getData<Thread>()->status != ThreadStatus::Dead;
|
return object->getData<Thread>()->status != ThreadStatus::Dead;
|
||||||
|
|
||||||
case KernelObjectType::Timer: // We should wait on a timer only if it has not been signalled
|
case KernelObjectType::Timer: // We should wait on a timer only if it has not been signalled
|
||||||
return !object->getData<Timer>()->fired;
|
return !object->getData<Timer>()->fired;
|
||||||
|
|
||||||
case KernelObjectType::Semaphore: // Wait if the semaphore count <= 0
|
case KernelObjectType::Semaphore: // Wait if the semaphore count <= 0
|
||||||
return object->getData<Semaphore>()->availableCount <= 0;
|
return object->getData<Semaphore>()->availableCount <= 0;
|
||||||
|
|
||||||
default:
|
default: Helpers::panic("Not sure whether to wait on object (type: %s)", object->getTypeName()); return true;
|
||||||
Helpers::panic("Not sure whether to wait on object (type: %s)", object->getTypeName());
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
#include "kernel.hpp"
|
#include "kernel.hpp"
|
||||||
#include "scheduler.hpp"
|
#include "scheduler.hpp"
|
||||||
|
|
||||||
Handle Kernel::makeTimer(ResetType type) {
|
HandleType Kernel::makeTimer(ResetType type) {
|
||||||
Handle ret = makeObject(KernelObjectType::Timer);
|
HandleType ret = makeObject(KernelObjectType::Timer);
|
||||||
objects[ret].data = new Timer(type);
|
objects[ret].data = new Timer(type);
|
||||||
|
|
||||||
if (type == ResetType::Pulse) {
|
if (type == ResetType::Pulse) {
|
||||||
|
@ -52,11 +52,9 @@ void Kernel::pollTimers() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::cancelTimer(Timer* timer) {
|
void Kernel::cancelTimer(Timer* timer) { timer->running = false; }
|
||||||
timer->running = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Kernel::signalTimer(Handle timerHandle, Timer* timer) {
|
void Kernel::signalTimer(HandleType timerHandle, Timer* timer) {
|
||||||
timer->fired = true;
|
timer->fired = true;
|
||||||
requireReschedule();
|
requireReschedule();
|
||||||
|
|
||||||
|
@ -94,7 +92,7 @@ void Kernel::svcCreateTimer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::svcSetTimer() {
|
void Kernel::svcSetTimer() {
|
||||||
Handle handle = regs[0];
|
HandleType handle = regs[0];
|
||||||
// TODO: Is this actually s64 or u64? 3DBrew says s64, but u64 makes more sense
|
// TODO: Is this actually s64 or u64? 3DBrew says s64, but u64 makes more sense
|
||||||
const s64 initial = s64(u64(regs[2]) | (u64(regs[3]) << 32));
|
const s64 initial = s64(u64(regs[2]) | (u64(regs[3]) << 32));
|
||||||
const s64 interval = s64(u64(regs[1]) | (u64(regs[4]) << 32));
|
const s64 interval = s64(u64(regs[1]) | (u64(regs[4]) << 32));
|
||||||
|
@ -112,7 +110,7 @@ void Kernel::svcSetTimer() {
|
||||||
timer->interval = interval;
|
timer->interval = interval;
|
||||||
timer->running = true;
|
timer->running = true;
|
||||||
timer->fireTick = cpu.getTicks() + Scheduler::nsToCycles(initial);
|
timer->fireTick = cpu.getTicks() + Scheduler::nsToCycles(initial);
|
||||||
|
|
||||||
Scheduler& scheduler = cpu.getScheduler();
|
Scheduler& scheduler = cpu.getScheduler();
|
||||||
// Signal an event to poll timers as soon as possible
|
// Signal an event to poll timers as soon as possible
|
||||||
scheduler.removeEvent(Scheduler::EventType::UpdateTimers);
|
scheduler.removeEvent(Scheduler::EventType::UpdateTimers);
|
||||||
|
@ -127,7 +125,7 @@ void Kernel::svcSetTimer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::svcClearTimer() {
|
void Kernel::svcClearTimer() {
|
||||||
Handle handle = regs[0];
|
HandleType handle = regs[0];
|
||||||
logSVC("ClearTimer (handle = %X)\n", handle);
|
logSVC("ClearTimer (handle = %X)\n", handle);
|
||||||
KernelObject* object = getObject(handle, KernelObjectType::Timer);
|
KernelObject* object = getObject(handle, KernelObjectType::Timer);
|
||||||
|
|
||||||
|
@ -141,7 +139,7 @@ void Kernel::svcClearTimer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::svcCancelTimer() {
|
void Kernel::svcCancelTimer() {
|
||||||
Handle handle = regs[0];
|
HandleType handle = regs[0];
|
||||||
logSVC("CancelTimer (handle = %X)\n", handle);
|
logSVC("CancelTimer (handle = %X)\n", handle);
|
||||||
KernelObject* object = getObject(handle, KernelObjectType::Timer);
|
KernelObject* object = getObject(handle, KernelObjectType::Timer);
|
||||||
|
|
||||||
|
@ -152,4 +150,4 @@ void Kernel::svcCancelTimer() {
|
||||||
cancelTimer(object->getData<Timer>());
|
cancelTimer(object->getData<Timer>());
|
||||||
regs[0] = Result::Success;
|
regs[0] = Result::Success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,7 +119,7 @@ u8 Memory::read8(u32 vaddr) {
|
||||||
case ConfigMem::FirmRevision: return firm.revision;
|
case ConfigMem::FirmRevision: return firm.revision;
|
||||||
case ConfigMem::FirmVersionMinor: return firm.minor;
|
case ConfigMem::FirmVersionMinor: return firm.minor;
|
||||||
case ConfigMem::FirmVersionMajor: return firm.major;
|
case ConfigMem::FirmVersionMajor: return firm.major;
|
||||||
case ConfigMem::WifiLevel: return 0; // No wifi :(
|
case ConfigMem::WifiLevel: return 0; // No wifi :(
|
||||||
|
|
||||||
case ConfigMem::WifiMac:
|
case ConfigMem::WifiMac:
|
||||||
case ConfigMem::WifiMac + 1:
|
case ConfigMem::WifiMac + 1:
|
||||||
|
@ -171,11 +171,10 @@ u32 Memory::read32(u32 vaddr) {
|
||||||
|
|
||||||
case ConfigMem::AppMemAlloc: return appResourceLimits.maxCommit;
|
case ConfigMem::AppMemAlloc: return appResourceLimits.maxCommit;
|
||||||
case ConfigMem::SyscoreVer: return 2;
|
case ConfigMem::SyscoreVer: return 2;
|
||||||
case 0x1FF81000: return 0; // TODO: Figure out what this config mem address does
|
case 0x1FF81000:
|
||||||
|
return 0; // TODO: Figure out what this config mem address does
|
||||||
// Wifi MAC: First 4 bytes of MAC Address
|
// Wifi MAC: First 4 bytes of MAC Address
|
||||||
case ConfigMem::WifiMac:
|
case ConfigMem::WifiMac: return (u32(MACAddress[3]) << 24) | (u32(MACAddress[2]) << 16) | (u32(MACAddress[1]) << 8) | MACAddress[0];
|
||||||
return (u32(MACAddress[3]) << 24) | (u32(MACAddress[2]) << 16) | (u32(MACAddress[1]) << 8) |
|
|
||||||
MACAddress[0];
|
|
||||||
|
|
||||||
// 3D slider. Float in range 0.0 = off, 1.0 = max.
|
// 3D slider. Float in range 0.0 = off, 1.0 = max.
|
||||||
case ConfigMem::SliderState3D: return Helpers::bit_cast<u32, float>(0.0f);
|
case ConfigMem::SliderState3D: return Helpers::bit_cast<u32, float>(0.0f);
|
||||||
|
@ -185,7 +184,7 @@ u32 Memory::read32(u32 vaddr) {
|
||||||
default:
|
default:
|
||||||
if (vaddr >= VirtualAddrs::VramStart && vaddr < VirtualAddrs::VramStart + VirtualAddrs::VramSize) {
|
if (vaddr >= VirtualAddrs::VramStart && vaddr < VirtualAddrs::VramStart + VirtualAddrs::VramSize) {
|
||||||
static int shutUpCounter = 0;
|
static int shutUpCounter = 0;
|
||||||
if (shutUpCounter < 5) { // Stop spamming about VRAM reads after the first 5
|
if (shutUpCounter < 5) { // Stop spamming about VRAM reads after the first 5
|
||||||
shutUpCounter++;
|
shutUpCounter++;
|
||||||
Helpers::warn("VRAM read!\n");
|
Helpers::warn("VRAM read!\n");
|
||||||
}
|
}
|
||||||
|
@ -440,7 +439,7 @@ MemoryInfo Memory::queryMemory(u32 vaddr) {
|
||||||
return MemoryInfo(vaddr, pageSize, 0, KernelMemoryTypes::Free);
|
return MemoryInfo(vaddr, pageSize, 0, KernelMemoryTypes::Free);
|
||||||
}
|
}
|
||||||
|
|
||||||
u8* Memory::mapSharedMemory(Handle handle, u32 vaddr, u32 myPerms, u32 otherPerms) {
|
u8* Memory::mapSharedMemory(HandleType handle, u32 vaddr, u32 myPerms, u32 otherPerms) {
|
||||||
for (auto& e : sharedMemBlocks) {
|
for (auto& e : sharedMemBlocks) {
|
||||||
if (e.handle == handle) {
|
if (e.handle == handle) {
|
||||||
// Virtual Console titles trigger this. TODO: Investigate how it should work
|
// Virtual Console titles trigger this. TODO: Investigate how it should work
|
||||||
|
@ -534,4 +533,4 @@ std::optional<u64> Memory::getProgramID() {
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
6
src/core/renderer_mtl/metal_cpp_impl.cpp
Normal file
6
src/core/renderer_mtl/metal_cpp_impl.cpp
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#define NS_PRIVATE_IMPLEMENTATION
|
||||||
|
#define CA_PRIVATE_IMPLEMENTATION
|
||||||
|
#define MTL_PRIVATE_IMPLEMENTATION
|
||||||
|
#include <Foundation/Foundation.hpp>
|
||||||
|
#include <Metal/Metal.hpp>
|
||||||
|
#include <QuartzCore/QuartzCore.hpp>
|
41
src/core/renderer_mtl/renderer_mtl.cpp
Normal file
41
src/core/renderer_mtl/renderer_mtl.cpp
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#include "renderer_mtl/renderer_mtl.hpp"
|
||||||
|
|
||||||
|
RendererMTL::RendererMTL(GPU& gpu, const std::array<u32, regNum>& internalRegs, const std::array<u32, extRegNum>& externalRegs)
|
||||||
|
: Renderer(gpu, internalRegs, externalRegs) {}
|
||||||
|
RendererMTL::~RendererMTL() {}
|
||||||
|
|
||||||
|
void RendererMTL::reset() {
|
||||||
|
// TODO: implement
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererMTL::display() {
|
||||||
|
// TODO: implement
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererMTL::initGraphicsContext(SDL_Window* window) {
|
||||||
|
// TODO: implement
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererMTL::clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control) {
|
||||||
|
// TODO: implement
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererMTL::displayTransfer(u32 inputAddr, u32 outputAddr, u32 inputSize, u32 outputSize, u32 flags) {
|
||||||
|
// TODO: implement
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererMTL::textureCopy(u32 inputAddr, u32 outputAddr, u32 totalBytes, u32 inputSize, u32 outputSize, u32 flags) {
|
||||||
|
// TODO: implement
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererMTL::drawVertices(PICA::PrimType primType, std::span<const PICA::Vertex> vertices) {
|
||||||
|
// TODO: implement
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererMTL::screenshot(const std::string& name) {
|
||||||
|
// TODO: implement
|
||||||
|
}
|
||||||
|
|
||||||
|
void RendererMTL::deinitGraphicsContext() {
|
||||||
|
// TODO: implement
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
#include "services/ac.hpp"
|
#include "services/ac.hpp"
|
||||||
|
|
||||||
#include "ipc.hpp"
|
#include "ipc.hpp"
|
||||||
|
|
||||||
namespace ACCommands {
|
namespace ACCommands {
|
||||||
|
@ -72,7 +73,7 @@ void ACService::getLastErrorCode(u32 messagePointer) {
|
||||||
|
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x0A, 2, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0x0A, 2, 0));
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
mem.write32(messagePointer + 8, 0); // Hopefully this means no error?
|
mem.write32(messagePointer + 8, 0); // Hopefully this means no error?
|
||||||
}
|
}
|
||||||
|
|
||||||
void ACService::getConnectingInfraPriority(u32 messagePointer) {
|
void ACService::getConnectingInfraPriority(u32 messagePointer) {
|
||||||
|
@ -130,10 +131,10 @@ void ACService::registerDisconnectEvent(u32 messagePointer) {
|
||||||
const u32 pidHeader = mem.read32(messagePointer + 4);
|
const u32 pidHeader = mem.read32(messagePointer + 4);
|
||||||
const u32 copyHandleHeader = mem.read32(messagePointer + 12);
|
const u32 copyHandleHeader = mem.read32(messagePointer + 12);
|
||||||
// Event signaled when disconnecting from AC. TODO: Properly implement it.
|
// Event signaled when disconnecting from AC. TODO: Properly implement it.
|
||||||
const Handle eventHandle = mem.read32(messagePointer + 16);
|
const HandleType eventHandle = mem.read32(messagePointer + 16);
|
||||||
|
|
||||||
disconnectEvent = eventHandle;
|
disconnectEvent = eventHandle;
|
||||||
|
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x30, 1, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0x30, 1, 0));
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
#include "services/apt.hpp"
|
#include "services/apt.hpp"
|
||||||
#include "ipc.hpp"
|
|
||||||
#include "kernel.hpp"
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "ipc.hpp"
|
||||||
|
#include "kernel.hpp"
|
||||||
|
|
||||||
namespace APTCommands {
|
namespace APTCommands {
|
||||||
enum : u32 {
|
enum : u32 {
|
||||||
GetLockHandle = 0x00010040,
|
GetLockHandle = 0x00010040,
|
||||||
|
@ -84,8 +85,7 @@ void APTService::appletUtility(u32 messagePointer) {
|
||||||
u32 outputSize = mem.read32(messagePointer + 12);
|
u32 outputSize = mem.read32(messagePointer + 12);
|
||||||
u32 inputPointer = mem.read32(messagePointer + 20);
|
u32 inputPointer = mem.read32(messagePointer + 20);
|
||||||
|
|
||||||
log("APT::AppletUtility(utility = %d, input size = %x, output size = %x, inputPointer = %08X)\n", utility, inputSize, outputSize,
|
log("APT::AppletUtility(utility = %d, input size = %x, output size = %x, inputPointer = %08X)\n", utility, inputSize, outputSize, inputPointer);
|
||||||
inputPointer);
|
|
||||||
|
|
||||||
std::vector<u8> out(outputSize);
|
std::vector<u8> out(outputSize);
|
||||||
const u32 outputBuffer = mem.read32(messagePointer + 0x104);
|
const u32 outputBuffer = mem.read32(messagePointer + 0x104);
|
||||||
|
@ -111,9 +111,9 @@ void APTService::getAppletInfo(u32 messagePointer) {
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x06, 7, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0x06, 7, 0));
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
|
|
||||||
mem.write8(messagePointer + 20, 1); // 1 = registered
|
mem.write8(messagePointer + 20, 1); // 1 = registered
|
||||||
mem.write8(messagePointer + 24, 1); // 1 = loaded
|
mem.write8(messagePointer + 24, 1); // 1 = loaded
|
||||||
// TODO: The rest of this
|
// TODO: The rest of this
|
||||||
}
|
}
|
||||||
|
|
||||||
void APTService::isRegistered(u32 messagePointer) {
|
void APTService::isRegistered(u32 messagePointer) {
|
||||||
|
@ -122,7 +122,7 @@ void APTService::isRegistered(u32 messagePointer) {
|
||||||
|
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x09, 2, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0x09, 2, 0));
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
mem.write8(messagePointer + 8, 1); // Return that the app is always registered. This might break with home menu?
|
mem.write8(messagePointer + 8, 1); // Return that the app is always registered. This might break with home menu?
|
||||||
}
|
}
|
||||||
|
|
||||||
void APTService::preloadLibraryApplet(u32 messagePointer) {
|
void APTService::preloadLibraryApplet(u32 messagePointer) {
|
||||||
|
@ -144,7 +144,7 @@ void APTService::prepareToStartLibraryApplet(u32 messagePointer) {
|
||||||
void APTService::startLibraryApplet(u32 messagePointer) {
|
void APTService::startLibraryApplet(u32 messagePointer) {
|
||||||
const u32 appID = mem.read32(messagePointer + 4);
|
const u32 appID = mem.read32(messagePointer + 4);
|
||||||
const u32 bufferSize = mem.read32(messagePointer + 8);
|
const u32 bufferSize = mem.read32(messagePointer + 8);
|
||||||
const Handle parameters = mem.read32(messagePointer + 16);
|
const HandleType parameters = mem.read32(messagePointer + 16);
|
||||||
const u32 buffer = mem.read32(messagePointer + 24);
|
const u32 buffer = mem.read32(messagePointer + 24);
|
||||||
log("APT::StartLibraryApplet (app ID = %X)\n", appID);
|
log("APT::StartLibraryApplet (app ID = %X)\n", appID);
|
||||||
|
|
||||||
|
@ -178,7 +178,7 @@ void APTService::checkNew3DS(u32 messagePointer) {
|
||||||
log("APT::CheckNew3DS\n");
|
log("APT::CheckNew3DS\n");
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x102, 2, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0x102, 2, 0));
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
mem.write8(messagePointer + 8, (model == ConsoleModel::New3DS) ? 1 : 0); // u8, Status (0 = Old 3DS, 1 = New 3DS)
|
mem.write8(messagePointer + 8, (model == ConsoleModel::New3DS) ? 1 : 0); // u8, Status (0 = Old 3DS, 1 = New 3DS)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Figure out the slight way this differs from APT::CheckNew3DS
|
// TODO: Figure out the slight way this differs from APT::CheckNew3DS
|
||||||
|
@ -186,7 +186,7 @@ void APTService::checkNew3DSApp(u32 messagePointer) {
|
||||||
log("APT::CheckNew3DSApp\n");
|
log("APT::CheckNew3DSApp\n");
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x101, 2, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0x101, 2, 0));
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
mem.write8(messagePointer + 8, (model == ConsoleModel::New3DS) ? 1 : 0); // u8, Status (0 = Old 3DS, 1 = New 3DS)
|
mem.write8(messagePointer + 8, (model == ConsoleModel::New3DS) ? 1 : 0); // u8, Status (0 = Old 3DS, 1 = New 3DS)
|
||||||
}
|
}
|
||||||
|
|
||||||
void APTService::enable(u32 messagePointer) {
|
void APTService::enable(u32 messagePointer) {
|
||||||
|
@ -207,14 +207,14 @@ void APTService::initialize(u32 messagePointer) {
|
||||||
notificationEvent = kernel.makeEvent(ResetType::OneShot);
|
notificationEvent = kernel.makeEvent(ResetType::OneShot);
|
||||||
resumeEvent = kernel.makeEvent(ResetType::OneShot);
|
resumeEvent = kernel.makeEvent(ResetType::OneShot);
|
||||||
|
|
||||||
kernel.signalEvent(resumeEvent.value()); // Seems to be signalled on startup
|
kernel.signalEvent(resumeEvent.value()); // Seems to be signalled on startup
|
||||||
}
|
}
|
||||||
|
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x2, 1, 3));
|
mem.write32(messagePointer, IPC::responseHeader(0x2, 1, 3));
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
mem.write32(messagePointer + 8, 0x04000000); // Translation descriptor
|
mem.write32(messagePointer + 8, 0x04000000); // Translation descriptor
|
||||||
mem.write32(messagePointer + 12, notificationEvent.value()); // Notification Event Handle
|
mem.write32(messagePointer + 12, notificationEvent.value()); // Notification Event HandleType
|
||||||
mem.write32(messagePointer + 16, resumeEvent.value()); // Resume Event Handle
|
mem.write32(messagePointer + 16, resumeEvent.value()); // Resume Event HandleType
|
||||||
}
|
}
|
||||||
|
|
||||||
void APTService::inquireNotification(u32 messagePointer) {
|
void APTService::inquireNotification(u32 messagePointer) {
|
||||||
|
@ -234,11 +234,11 @@ void APTService::getLockHandle(u32 messagePointer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x1, 3, 2));
|
mem.write32(messagePointer, IPC::responseHeader(0x1, 3, 2));
|
||||||
mem.write32(messagePointer + 4, Result::Success); // Result code
|
mem.write32(messagePointer + 4, Result::Success); // Result code
|
||||||
mem.write32(messagePointer + 8, 0); // AppletAttr
|
mem.write32(messagePointer + 8, 0); // AppletAttr
|
||||||
mem.write32(messagePointer + 12, 0); // APT State (bit0 = Power Button State, bit1 = Order To Close State)
|
mem.write32(messagePointer + 12, 0); // APT State (bit0 = Power Button State, bit1 = Order To Close State)
|
||||||
mem.write32(messagePointer + 16, 0); // Translation descriptor
|
mem.write32(messagePointer + 16, 0); // Translation descriptor
|
||||||
mem.write32(messagePointer + 20, lockHandle.value()); // Lock handle
|
mem.write32(messagePointer + 20, lockHandle.value()); // Lock handle
|
||||||
}
|
}
|
||||||
|
|
||||||
// This apparently does nothing on the original kernel either?
|
// This apparently does nothing on the original kernel either?
|
||||||
|
@ -254,7 +254,7 @@ void APTService::sendParameter(u32 messagePointer) {
|
||||||
const u32 cmd = mem.read32(messagePointer + 12);
|
const u32 cmd = mem.read32(messagePointer + 12);
|
||||||
const u32 paramSize = mem.read32(messagePointer + 16);
|
const u32 paramSize = mem.read32(messagePointer + 16);
|
||||||
|
|
||||||
const u32 parameterHandle = mem.read32(messagePointer + 24); // What dis?
|
const u32 parameterHandle = mem.read32(messagePointer + 24); // What dis?
|
||||||
const u32 parameterPointer = mem.read32(messagePointer + 32);
|
const u32 parameterPointer = mem.read32(messagePointer + 32);
|
||||||
log("APT::SendParameter (source app = %X, dest app = %X, cmd = %X, size = %X)", sourceAppID, destAppID, cmd, paramSize);
|
log("APT::SendParameter (source app = %X, dest app = %X, cmd = %X, size = %X)", sourceAppID, destAppID, cmd, paramSize);
|
||||||
|
|
||||||
|
@ -355,8 +355,8 @@ void APTService::replySleepQuery(u32 messagePointer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void APTService::setApplicationCpuTimeLimit(u32 messagePointer) {
|
void APTService::setApplicationCpuTimeLimit(u32 messagePointer) {
|
||||||
u32 fixed = mem.read32(messagePointer + 4); // MUST be 1.
|
u32 fixed = mem.read32(messagePointer + 4); // MUST be 1.
|
||||||
u32 percentage = mem.read32(messagePointer + 8); // CPU time percentage between 5% and 89%
|
u32 percentage = mem.read32(messagePointer + 8); // CPU time percentage between 5% and 89%
|
||||||
log("APT::SetApplicationCpuTimeLimit (percentage = %d%%)\n", percentage);
|
log("APT::SetApplicationCpuTimeLimit (percentage = %d%%)\n", percentage);
|
||||||
|
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x4F, 1, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0x4F, 1, 0));
|
||||||
|
@ -409,15 +409,14 @@ void APTService::theSmashBrosFunction(u32 messagePointer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void APTService::getWirelessRebootInfo(u32 messagePointer) {
|
void APTService::getWirelessRebootInfo(u32 messagePointer) {
|
||||||
const u32 size = mem.read32(messagePointer + 4); // Size of data to read
|
const u32 size = mem.read32(messagePointer + 4); // Size of data to read
|
||||||
log("APT::GetWirelessRebootInfo (size = %X)\n", size);
|
log("APT::GetWirelessRebootInfo (size = %X)\n", size);
|
||||||
|
|
||||||
if (size > 0x10)
|
if (size > 0x10) Helpers::panic("APT::GetWirelessInfo with size > 0x10 bytes");
|
||||||
Helpers::panic("APT::GetWirelessInfo with size > 0x10 bytes");
|
|
||||||
|
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x45, 1, 2));
|
mem.write32(messagePointer, IPC::responseHeader(0x45, 1, 2));
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
for (u32 i = 0; i < size; i++) {
|
for (u32 i = 0; i < size; i++) {
|
||||||
mem.write8(messagePointer + 0x104 + i, 0); // Temporarily stub this until we add SetWirelessRebootInfo
|
mem.write8(messagePointer + 0x104 + i, 0); // Temporarily stub this until we add SetWirelessRebootInfo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "services/boss.hpp"
|
#include "services/boss.hpp"
|
||||||
|
|
||||||
#include "ipc.hpp"
|
#include "ipc.hpp"
|
||||||
|
|
||||||
namespace BOSSCommands {
|
namespace BOSSCommands {
|
||||||
|
@ -31,9 +32,7 @@ namespace BOSSCommands {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void BOSSService::reset() {
|
void BOSSService::reset() { optoutFlag = 0; }
|
||||||
optoutFlag = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BOSSService::handleSyncRequest(u32 messagePointer) {
|
void BOSSService::handleSyncRequest(u32 messagePointer) {
|
||||||
const u32 command = mem.read32(messagePointer);
|
const u32 command = mem.read32(messagePointer);
|
||||||
|
@ -44,8 +43,7 @@ void BOSSService::handleSyncRequest(u32 messagePointer) {
|
||||||
case BOSSCommands::GetNsDataIdList:
|
case BOSSCommands::GetNsDataIdList:
|
||||||
case BOSSCommands::GetNsDataIdList1:
|
case BOSSCommands::GetNsDataIdList1:
|
||||||
case BOSSCommands::GetNsDataIdList2:
|
case BOSSCommands::GetNsDataIdList2:
|
||||||
case BOSSCommands::GetNsDataIdList3:
|
case BOSSCommands::GetNsDataIdList3: getNsDataIdList(messagePointer, command); break;
|
||||||
getNsDataIdList(messagePointer, command); break;
|
|
||||||
case BOSSCommands::GetOptoutFlag: getOptoutFlag(messagePointer); break;
|
case BOSSCommands::GetOptoutFlag: getOptoutFlag(messagePointer); break;
|
||||||
case BOSSCommands::GetStorageEntryInfo: getStorageEntryInfo(messagePointer); break;
|
case BOSSCommands::GetStorageEntryInfo: getStorageEntryInfo(messagePointer); break;
|
||||||
case BOSSCommands::GetTaskIdList: getTaskIdList(messagePointer); break;
|
case BOSSCommands::GetTaskIdList: getTaskIdList(messagePointer); break;
|
||||||
|
@ -99,7 +97,7 @@ void BOSSService::getTaskState(u32 messagePointer) {
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
mem.write8(messagePointer + 8, 0); // TaskStatus: Report the task finished successfully
|
mem.write8(messagePointer + 8, 0); // TaskStatus: Report the task finished successfully
|
||||||
mem.write32(messagePointer + 12, 0); // Current state value for task PropertyID 0x4
|
mem.write32(messagePointer + 12, 0); // Current state value for task PropertyID 0x4
|
||||||
mem.write8(messagePointer + 16, 0); // TODO: Figure out what this should be
|
mem.write8(messagePointer + 16, 0); // TODO: Figure out what this should be
|
||||||
}
|
}
|
||||||
|
|
||||||
void BOSSService::getTaskStatus(u32 messagePointer) {
|
void BOSSService::getTaskStatus(u32 messagePointer) {
|
||||||
|
@ -150,15 +148,15 @@ void BOSSService::getErrorCode(u32 messagePointer) {
|
||||||
log("BOSS::GetErrorCode (stubbed)\n");
|
log("BOSS::GetErrorCode (stubbed)\n");
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x2E, 2, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0x2E, 2, 0));
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
mem.write32(messagePointer + 8, Result::Success); // No error code
|
mem.write32(messagePointer + 8, Result::Success); // No error code
|
||||||
}
|
}
|
||||||
|
|
||||||
void BOSSService::getStorageEntryInfo(u32 messagePointer) {
|
void BOSSService::getStorageEntryInfo(u32 messagePointer) {
|
||||||
log("BOSS::GetStorageEntryInfo (undocumented)\n");
|
log("BOSS::GetStorageEntryInfo (undocumented)\n");
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x30, 3, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0x30, 3, 0));
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
mem.write32(messagePointer + 8, 0); // u32, unknown meaning
|
mem.write32(messagePointer + 8, 0); // u32, unknown meaning
|
||||||
mem.write16(messagePointer + 12, 0); // s16, unknown meaning
|
mem.write16(messagePointer + 12, 0); // s16, unknown meaning
|
||||||
}
|
}
|
||||||
|
|
||||||
void BOSSService::sendProperty(u32 messagePointer) {
|
void BOSSService::sendProperty(u32 messagePointer) {
|
||||||
|
@ -170,10 +168,9 @@ void BOSSService::sendProperty(u32 messagePointer) {
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x14, 1, 2));
|
mem.write32(messagePointer, IPC::responseHeader(0x14, 1, 2));
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
mem.write32(messagePointer + 8, 0); // Read size
|
mem.write32(messagePointer + 8, 0); // Read size
|
||||||
// TODO: Should this do anything else?
|
// TODO: Should this do anything else?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void BOSSService::receiveProperty(u32 messagePointer) {
|
void BOSSService::receiveProperty(u32 messagePointer) {
|
||||||
const u32 id = mem.read32(messagePointer + 4);
|
const u32 id = mem.read32(messagePointer + 4);
|
||||||
const u32 size = mem.read32(messagePointer + 8);
|
const u32 size = mem.read32(messagePointer + 8);
|
||||||
|
@ -182,13 +179,13 @@ void BOSSService::receiveProperty(u32 messagePointer) {
|
||||||
log("BOSS::ReceiveProperty (id = %d, size = %08X, ptr = %08X) (stubbed)\n", id, size, ptr);
|
log("BOSS::ReceiveProperty (id = %d, size = %08X, ptr = %08X) (stubbed)\n", id, size, ptr);
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x16, 2, 2));
|
mem.write32(messagePointer, IPC::responseHeader(0x16, 2, 2));
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
mem.write32(messagePointer + 8, 0); // Read size
|
mem.write32(messagePointer + 8, 0); // Read size
|
||||||
}
|
}
|
||||||
|
|
||||||
// This seems to accept a KEvent as a parameter and register it for something Spotpass related
|
// This seems to accept a KEvent as a parameter and register it for something Spotpass related
|
||||||
// I need to update the 3DBrew page when it's known what it does properly
|
// I need to update the 3DBrew page when it's known what it does properly
|
||||||
void BOSSService::registerNewArrivalEvent(u32 messagePointer) {
|
void BOSSService::registerNewArrivalEvent(u32 messagePointer) {
|
||||||
const Handle eventHandle = mem.read32(messagePointer + 4); // Kernel event handle to register
|
const HandleType eventHandle = mem.read32(messagePointer + 4); // Kernel event handle to register
|
||||||
log("BOSS::RegisterNewArrivalEvent (handle = %X)\n", eventHandle);
|
log("BOSS::RegisterNewArrivalEvent (handle = %X)\n", eventHandle);
|
||||||
|
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x8, 1, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0x8, 1, 0));
|
||||||
|
@ -252,5 +249,5 @@ void BOSSService::getNewArrivalFlag(u32 messagePointer) {
|
||||||
log("BOSS::GetNewArrivalFlag (stubbed)\n");
|
log("BOSS::GetNewArrivalFlag (stubbed)\n");
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x7, 2, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0x7, 2, 0));
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
mem.write8(messagePointer + 8, 0); // Flag
|
mem.write8(messagePointer + 8, 0); // Flag
|
||||||
}
|
}
|
||||||
|
|
|
@ -312,7 +312,7 @@ void CAMService::setReceiving(u32 messagePointer) {
|
||||||
const u32 portIndex = mem.read8(messagePointer + 8);
|
const u32 portIndex = mem.read8(messagePointer + 8);
|
||||||
const u32 size = mem.read32(messagePointer + 12);
|
const u32 size = mem.read32(messagePointer + 12);
|
||||||
const u16 transferUnit = mem.read16(messagePointer + 16);
|
const u16 transferUnit = mem.read16(messagePointer + 16);
|
||||||
const Handle process = mem.read32(messagePointer + 24);
|
const HandleType process = mem.read32(messagePointer + 24);
|
||||||
|
|
||||||
const PortSelect port(portIndex);
|
const PortSelect port(portIndex);
|
||||||
log("CAM::SetReceiving (port = %d)\n", portIndex);
|
log("CAM::SetReceiving (port = %d)\n", portIndex);
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
#include "services/dsp.hpp"
|
#include "services/dsp.hpp"
|
||||||
#include "ipc.hpp"
|
|
||||||
#include "kernel.hpp"
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
#include "ipc.hpp"
|
||||||
|
#include "kernel.hpp"
|
||||||
|
|
||||||
namespace DSPCommands {
|
namespace DSPCommands {
|
||||||
enum : u32 {
|
enum : u32 {
|
||||||
RecvData = 0x00010040,
|
RecvData = 0x00010040,
|
||||||
|
@ -25,10 +26,7 @@ namespace DSPCommands {
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Result {
|
namespace Result {
|
||||||
enum : u32 {
|
enum : u32 { HeadphonesNotInserted = 0, HeadphonesInserted = 1 };
|
||||||
HeadphonesNotInserted = 0,
|
|
||||||
HeadphonesInserted = 1
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPService::reset() {
|
void DSPService::reset() {
|
||||||
|
@ -74,7 +72,7 @@ void DSPService::convertProcessAddressFromDspDram(u32 messagePointer) {
|
||||||
|
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0xC, 2, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0xC, 2, 0));
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
mem.write32(messagePointer + 8, converted); // Converted address
|
mem.write32(messagePointer + 8, converted); // Converted address
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPService::loadComponent(u32 messagePointer) {
|
void DSPService::loadComponent(u32 messagePointer) {
|
||||||
|
@ -94,9 +92,9 @@ void DSPService::loadComponent(u32 messagePointer) {
|
||||||
|
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x11, 2, 2));
|
mem.write32(messagePointer, IPC::responseHeader(0x11, 2, 2));
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
mem.write32(messagePointer + 8, 1); // Component loaded
|
mem.write32(messagePointer + 8, 1); // Component loaded
|
||||||
mem.write32(messagePointer + 12, (size << 4) | 0xA);
|
mem.write32(messagePointer + 12, (size << 4) | 0xA);
|
||||||
mem.write32(messagePointer + 16, mem.read32(messagePointer + 20)); // Component buffer
|
mem.write32(messagePointer + 16, mem.read32(messagePointer + 20)); // Component buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPService::unloadComponent(u32 messagePointer) {
|
void DSPService::unloadComponent(u32 messagePointer) {
|
||||||
|
@ -121,7 +119,7 @@ void DSPService::readPipeIfPossible(u32 messagePointer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
mem.write16(messagePointer + 8, u16(data.size())); // Number of bytes read
|
mem.write16(messagePointer + 8, u16(data.size())); // Number of bytes read
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPService::recvData(u32 messagePointer) {
|
void DSPService::recvData(u32 messagePointer) {
|
||||||
|
@ -153,12 +151,10 @@ DSPService::DSPEvent& DSPService::getEventRef(u32 type, u32 pipe) {
|
||||||
case 1: return interrupt1;
|
case 1: return interrupt1;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
if (pipe >= pipeCount)
|
if (pipe >= pipeCount) Helpers::panic("Tried to access the event of an invalid pipe");
|
||||||
Helpers::panic("Tried to access the event of an invalid pipe");
|
|
||||||
return pipeEvents[pipe];
|
return pipeEvents[pipe];
|
||||||
|
|
||||||
default:
|
default: Helpers::panic("Unknown type for DSP::getEventRef");
|
||||||
Helpers::panic("Unknown type for DSP::getEventRef");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,8 +166,8 @@ void DSPService::registerInterruptEvents(u32 messagePointer) {
|
||||||
|
|
||||||
// The event handle being 0 means we're removing an event
|
// The event handle being 0 means we're removing an event
|
||||||
if (eventHandle == 0) {
|
if (eventHandle == 0) {
|
||||||
DSPEvent& e = getEventRef(interrupt, channel); // Get event
|
DSPEvent& e = getEventRef(interrupt, channel); // Get event
|
||||||
if (e.has_value()) { // Remove if it exists
|
if (e.has_value()) { // Remove if it exists
|
||||||
totalEventCount--;
|
totalEventCount--;
|
||||||
e = std::nullopt;
|
e = std::nullopt;
|
||||||
}
|
}
|
||||||
|
@ -198,7 +194,7 @@ void DSPService::getHeadphoneStatus(u32 messagePointer) {
|
||||||
|
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x1F, 2, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0x1F, 2, 0));
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
mem.write32(messagePointer + 8, Result::HeadphonesInserted); // This should be toggleable for shits and giggles
|
mem.write32(messagePointer + 8, Result::HeadphonesInserted); // This should be toggleable for shits and giggles
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPService::getSemaphoreEventHandle(u32 messagePointer) {
|
void DSPService::getSemaphoreEventHandle(u32 messagePointer) {
|
||||||
|
@ -211,7 +207,7 @@ void DSPService::getSemaphoreEventHandle(u32 messagePointer) {
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x16, 1, 2));
|
mem.write32(messagePointer, IPC::responseHeader(0x16, 1, 2));
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
// TODO: Translation descriptor here?
|
// TODO: Translation descriptor here?
|
||||||
mem.write32(messagePointer + 12, semaphoreEvent.value()); // Semaphore event handle
|
mem.write32(messagePointer + 12, semaphoreEvent.value()); // Semaphore event handle
|
||||||
kernel.signalEvent(semaphoreEvent.value());
|
kernel.signalEvent(semaphoreEvent.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,7 +245,7 @@ void DSPService::writeProcessPipe(u32 messagePointer) {
|
||||||
void DSPService::flushDataCache(u32 messagePointer) {
|
void DSPService::flushDataCache(u32 messagePointer) {
|
||||||
const u32 address = mem.read32(messagePointer + 4);
|
const u32 address = mem.read32(messagePointer + 4);
|
||||||
const u32 size = mem.read32(messagePointer + 8);
|
const u32 size = mem.read32(messagePointer + 8);
|
||||||
const Handle process = mem.read32(messagePointer + 16);
|
const HandleType process = mem.read32(messagePointer + 16);
|
||||||
|
|
||||||
log("DSP::FlushDataCache (addr = %08X, size = %08X, process = %X)\n", address, size, process);
|
log("DSP::FlushDataCache (addr = %08X, size = %08X, process = %X)\n", address, size, process);
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x13, 1, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0x13, 1, 0));
|
||||||
|
@ -259,7 +255,7 @@ void DSPService::flushDataCache(u32 messagePointer) {
|
||||||
void DSPService::invalidateDCache(u32 messagePointer) {
|
void DSPService::invalidateDCache(u32 messagePointer) {
|
||||||
const u32 address = mem.read32(messagePointer + 4);
|
const u32 address = mem.read32(messagePointer + 4);
|
||||||
const u32 size = mem.read32(messagePointer + 8);
|
const u32 size = mem.read32(messagePointer + 8);
|
||||||
const Handle process = mem.read32(messagePointer + 16);
|
const HandleType process = mem.read32(messagePointer + 16);
|
||||||
|
|
||||||
log("DSP::InvalidateDataCache (addr = %08X, size = %08X, process = %X)\n", address, size, process);
|
log("DSP::InvalidateDataCache (addr = %08X, size = %08X, process = %X)\n", address, size, process);
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x14, 1, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0x14, 1, 0));
|
||||||
|
@ -303,4 +299,4 @@ void DSPService::triggerInterrupt1() {
|
||||||
if (interrupt1.has_value()) {
|
if (interrupt1.has_value()) {
|
||||||
kernel.signalEvent(*interrupt1);
|
kernel.signalEvent(*interrupt1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
#include "services/fs.hpp"
|
#include "services/fs.hpp"
|
||||||
#include "kernel/kernel.hpp"
|
|
||||||
#include "io_file.hpp"
|
#include "io_file.hpp"
|
||||||
#include "ipc.hpp"
|
#include "ipc.hpp"
|
||||||
|
#include "kernel/kernel.hpp"
|
||||||
#include "result/result.hpp"
|
#include "result/result.hpp"
|
||||||
|
|
||||||
#ifdef CreateFile // windows.h defines CreateFile & DeleteFile because of course it does.
|
#ifdef CreateFile // windows.h defines CreateFile & DeleteFile because of course it does.
|
||||||
#undef CreateDirectory
|
#undef CreateDirectory
|
||||||
#undef CreateFile
|
#undef CreateFile
|
||||||
#undef DeleteFile
|
#undef DeleteFile
|
||||||
|
@ -47,21 +48,18 @@ namespace FSCommands {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void FSService::reset() {
|
void FSService::reset() { priority = 0; }
|
||||||
priority = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates directories for NAND, ExtSaveData, etc if they don't already exist. Should be executed after loading a new ROM.
|
// Creates directories for NAND, ExtSaveData, etc if they don't already exist. Should be executed after loading a new ROM.
|
||||||
void FSService::initializeFilesystem() {
|
void FSService::initializeFilesystem() {
|
||||||
const auto sdmcPath = IOFile::getAppData() / "SDMC"; // Create SDMC directory
|
const auto sdmcPath = IOFile::getAppData() / "SDMC"; // Create SDMC directory
|
||||||
const auto nandSharedpath = IOFile::getAppData() / ".." / "SharedFiles" / "NAND";
|
const auto nandSharedpath = IOFile::getAppData() / ".." / "SharedFiles" / "NAND";
|
||||||
|
|
||||||
const auto savePath = IOFile::getAppData() / "SaveData"; // Create SaveData
|
const auto savePath = IOFile::getAppData() / "SaveData"; // Create SaveData
|
||||||
const auto formatPath = IOFile::getAppData() / "FormatInfo"; // Create folder for storing archive formatting info
|
const auto formatPath = IOFile::getAppData() / "FormatInfo"; // Create folder for storing archive formatting info
|
||||||
const auto systemSaveDataPath = IOFile::getAppData() / ".." / "SharedFiles" / "SystemSaveData";
|
const auto systemSaveDataPath = IOFile::getAppData() / ".." / "SharedFiles" / "SystemSaveData";
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
|
||||||
if (!fs::is_directory(nandSharedpath)) {
|
if (!fs::is_directory(nandSharedpath)) {
|
||||||
fs::create_directories(nandSharedpath);
|
fs::create_directories(nandSharedpath);
|
||||||
}
|
}
|
||||||
|
@ -89,25 +87,21 @@ ArchiveBase* FSService::getArchiveFromID(u32 id, const FSPath& archivePath) {
|
||||||
case ArchiveID::SaveData: return &saveData;
|
case ArchiveID::SaveData: return &saveData;
|
||||||
case ArchiveID::UserSaveData2: return &userSaveData2;
|
case ArchiveID::UserSaveData2: return &userSaveData2;
|
||||||
|
|
||||||
case ArchiveID::ExtSaveData:
|
case ArchiveID::ExtSaveData: return &extSaveData_sdmc;
|
||||||
return &extSaveData_sdmc;
|
|
||||||
|
|
||||||
case ArchiveID::SharedExtSaveData:
|
case ArchiveID::SharedExtSaveData: return &sharedExtSaveData_nand;
|
||||||
return &sharedExtSaveData_nand;
|
|
||||||
|
|
||||||
case ArchiveID::SystemSaveData: return &systemSaveData;
|
case ArchiveID::SystemSaveData: return &systemSaveData;
|
||||||
case ArchiveID::SDMC: return &sdmc;
|
case ArchiveID::SDMC: return &sdmc;
|
||||||
case ArchiveID::SDMCWriteOnly: return &sdmcWriteOnly;
|
case ArchiveID::SDMCWriteOnly: return &sdmcWriteOnly;
|
||||||
case ArchiveID::SavedataAndNcch: return &ncch; // This can only access NCCH outside of FSPXI
|
case ArchiveID::SavedataAndNcch: return &ncch; // This can only access NCCH outside of FSPXI
|
||||||
default:
|
default: Helpers::panic("Unknown archive. ID: %d\n", id); return nullptr;
|
||||||
Helpers::panic("Unknown archive. ID: %d\n", id);
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Handle> FSService::openFileHandle(ArchiveBase* archive, const FSPath& path, const FSPath& archivePath, const FilePerms& perms) {
|
std::optional<HandleType> FSService::openFileHandle(ArchiveBase* archive, const FSPath& path, const FSPath& archivePath, const FilePerms& perms) {
|
||||||
FileDescriptor opened = archive->openFile(path, perms);
|
FileDescriptor opened = archive->openFile(path, perms);
|
||||||
if (opened.has_value()) { // If opened doesn't have a value, we failed to open the file
|
if (opened.has_value()) { // If opened doesn't have a value, we failed to open the file
|
||||||
auto handle = kernel.makeObject(KernelObjectType::File);
|
auto handle = kernel.makeObject(KernelObjectType::File);
|
||||||
|
|
||||||
auto& file = kernel.getObjects()[handle];
|
auto& file = kernel.getObjects()[handle];
|
||||||
|
@ -119,9 +113,9 @@ std::optional<Handle> FSService::openFileHandle(ArchiveBase* archive, const FSPa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rust::Result<Handle, Result::HorizonResult> FSService::openDirectoryHandle(ArchiveBase* archive, const FSPath& path) {
|
Rust::Result<HandleType, Result::HorizonResult> FSService::openDirectoryHandle(ArchiveBase* archive, const FSPath& path) {
|
||||||
Rust::Result<DirectorySession, Result::HorizonResult> opened = archive->openDirectory(path);
|
Rust::Result<DirectorySession, Result::HorizonResult> opened = archive->openDirectory(path);
|
||||||
if (opened.isOk()) { // If opened doesn't have a value, we failed to open the directory
|
if (opened.isOk()) { // If opened doesn't have a value, we failed to open the directory
|
||||||
auto handle = kernel.makeObject(KernelObjectType::Directory);
|
auto handle = kernel.makeObject(KernelObjectType::Directory);
|
||||||
auto& object = kernel.getObjects()[handle];
|
auto& object = kernel.getObjects()[handle];
|
||||||
object.data = new DirectorySession(opened.unwrap());
|
object.data = new DirectorySession(opened.unwrap());
|
||||||
|
@ -132,7 +126,7 @@ Rust::Result<Handle, Result::HorizonResult> FSService::openDirectoryHandle(Archi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rust::Result<Handle, Result::HorizonResult> FSService::openArchiveHandle(u32 archiveID, const FSPath& path) {
|
Rust::Result<HandleType, Result::HorizonResult> FSService::openArchiveHandle(u32 archiveID, const FSPath& path) {
|
||||||
ArchiveBase* archive = getArchiveFromID(archiveID, path);
|
ArchiveBase* archive = getArchiveFromID(archiveID, path);
|
||||||
|
|
||||||
if (archive == nullptr) [[unlikely]] {
|
if (archive == nullptr) [[unlikely]] {
|
||||||
|
@ -147,8 +141,7 @@ Rust::Result<Handle, Result::HorizonResult> FSService::openArchiveHandle(u32 arc
|
||||||
archiveObject.data = new ArchiveSession(res.unwrap(), path);
|
archiveObject.data = new ArchiveSession(res.unwrap(), path);
|
||||||
|
|
||||||
return Ok(handle);
|
return Ok(handle);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return Err(res.unwrapErr());
|
return Err(res.unwrapErr());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,8 +150,7 @@ FSPath FSService::readPath(u32 type, u32 pointer, u32 size) {
|
||||||
std::vector<u8> data;
|
std::vector<u8> data;
|
||||||
data.resize(size);
|
data.resize(size);
|
||||||
|
|
||||||
for (u32 i = 0; i < size; i++)
|
for (u32 i = 0; i < size; i++) data[i] = mem.read8(pointer + i);
|
||||||
data[i] = mem.read8(pointer + i);
|
|
||||||
|
|
||||||
return FSPath(type, data);
|
return FSPath(type, data);
|
||||||
}
|
}
|
||||||
|
@ -217,7 +209,7 @@ void FSService::initializeWithSdkVersion(u32 messagePointer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FSService::closeArchive(u32 messagePointer) {
|
void FSService::closeArchive(u32 messagePointer) {
|
||||||
const Handle handle = static_cast<u32>(mem.read64(messagePointer + 4)); // TODO: archive handles should be 64-bit
|
const HandleType handle = static_cast<u32>(mem.read64(messagePointer + 4)); // TODO: archive handles should be 64-bit
|
||||||
const auto object = kernel.getObject(handle, KernelObjectType::Archive);
|
const auto object = kernel.getObject(handle, KernelObjectType::Archive);
|
||||||
log("FSService::CloseArchive(handle = %X)\n", handle);
|
log("FSService::CloseArchive(handle = %X)\n", handle);
|
||||||
|
|
||||||
|
@ -241,7 +233,7 @@ void FSService::openArchive(u32 messagePointer) {
|
||||||
auto archivePath = readPath(archivePathType, archivePathPointer, archivePathSize);
|
auto archivePath = readPath(archivePathType, archivePathPointer, archivePathSize);
|
||||||
log("FS::OpenArchive(archive ID = %d, archive path type = %d)\n", archiveID, archivePathType);
|
log("FS::OpenArchive(archive ID = %d, archive path type = %d)\n", archiveID, archivePathType);
|
||||||
|
|
||||||
Rust::Result<Handle, Result::HorizonResult> res = openArchiveHandle(archiveID, archivePath);
|
Rust::Result<HandleType, Result::HorizonResult> res = openArchiveHandle(archiveID, archivePath);
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x80C, 3, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0x80C, 3, 0));
|
||||||
if (res.isOk()) {
|
if (res.isOk()) {
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
|
@ -254,7 +246,7 @@ void FSService::openArchive(u32 messagePointer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FSService::openFile(u32 messagePointer) {
|
void FSService::openFile(u32 messagePointer) {
|
||||||
const Handle archiveHandle = Handle(mem.read64(messagePointer + 8));
|
const HandleType archiveHandle = HandleType(mem.read64(messagePointer + 8));
|
||||||
const u32 filePathType = mem.read32(messagePointer + 16);
|
const u32 filePathType = mem.read32(messagePointer + 16);
|
||||||
const u32 filePathSize = mem.read32(messagePointer + 20);
|
const u32 filePathSize = mem.read32(messagePointer + 20);
|
||||||
const u32 openFlags = mem.read32(messagePointer + 24);
|
const u32 openFlags = mem.read32(messagePointer + 24);
|
||||||
|
@ -276,14 +268,14 @@ void FSService::openFile(u32 messagePointer) {
|
||||||
auto filePath = readPath(filePathType, filePathPointer, filePathSize);
|
auto filePath = readPath(filePathType, filePathPointer, filePathSize);
|
||||||
const FilePerms perms(openFlags);
|
const FilePerms perms(openFlags);
|
||||||
|
|
||||||
std::optional<Handle> handle = openFileHandle(archive, filePath, archivePath, perms);
|
std::optional<HandleType> handle = openFileHandle(archive, filePath, archivePath, perms);
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x802, 1, 2));
|
mem.write32(messagePointer, IPC::responseHeader(0x802, 1, 2));
|
||||||
if (!handle.has_value()) {
|
if (!handle.has_value()) {
|
||||||
printf("OpenFile failed\n");
|
printf("OpenFile failed\n");
|
||||||
mem.write32(messagePointer + 4, Result::FS::FileNotFound);
|
mem.write32(messagePointer + 4, Result::FS::FileNotFound);
|
||||||
} else {
|
} else {
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
mem.write32(messagePointer + 8, 0x10); // "Move handle descriptor"
|
mem.write32(messagePointer + 8, 0x10); // "Move handle descriptor"
|
||||||
mem.write32(messagePointer + 12, handle.value());
|
mem.write32(messagePointer + 12, handle.value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -291,7 +283,7 @@ void FSService::openFile(u32 messagePointer) {
|
||||||
void FSService::createDirectory(u32 messagePointer) {
|
void FSService::createDirectory(u32 messagePointer) {
|
||||||
log("FS::CreateDirectory\n");
|
log("FS::CreateDirectory\n");
|
||||||
|
|
||||||
const Handle archiveHandle = (Handle)mem.read64(messagePointer + 8);
|
const HandleType archiveHandle = (HandleType)mem.read64(messagePointer + 8);
|
||||||
const u32 pathType = mem.read32(messagePointer + 16);
|
const u32 pathType = mem.read32(messagePointer + 16);
|
||||||
const u32 pathSize = mem.read32(messagePointer + 20);
|
const u32 pathSize = mem.read32(messagePointer + 20);
|
||||||
const u32 pathPointer = mem.read32(messagePointer + 32);
|
const u32 pathPointer = mem.read32(messagePointer + 32);
|
||||||
|
@ -313,7 +305,7 @@ void FSService::createDirectory(u32 messagePointer) {
|
||||||
|
|
||||||
void FSService::openDirectory(u32 messagePointer) {
|
void FSService::openDirectory(u32 messagePointer) {
|
||||||
log("FS::OpenDirectory\n");
|
log("FS::OpenDirectory\n");
|
||||||
const Handle archiveHandle = (Handle)mem.read64(messagePointer + 4);
|
const HandleType archiveHandle = (HandleType)mem.read64(messagePointer + 4);
|
||||||
const u32 pathType = mem.read32(messagePointer + 12);
|
const u32 pathType = mem.read32(messagePointer + 12);
|
||||||
const u32 pathSize = mem.read32(messagePointer + 16);
|
const u32 pathSize = mem.read32(messagePointer + 16);
|
||||||
const u32 pathPointer = mem.read32(messagePointer + 24);
|
const u32 pathPointer = mem.read32(messagePointer + 24);
|
||||||
|
@ -366,7 +358,7 @@ void FSService::openFileDirectly(u32 messagePointer) {
|
||||||
}
|
}
|
||||||
archive = res.unwrap();
|
archive = res.unwrap();
|
||||||
|
|
||||||
std::optional<Handle> handle = openFileHandle(archive, filePath, archivePath, perms);
|
std::optional<HandleType> handle = openFileHandle(archive, filePath, archivePath, perms);
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x803, 1, 2));
|
mem.write32(messagePointer, IPC::responseHeader(0x803, 1, 2));
|
||||||
if (!handle.has_value()) {
|
if (!handle.has_value()) {
|
||||||
printf("OpenFileDirectly failed\n");
|
printf("OpenFileDirectly failed\n");
|
||||||
|
@ -378,7 +370,7 @@ void FSService::openFileDirectly(u32 messagePointer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FSService::createFile(u32 messagePointer) {
|
void FSService::createFile(u32 messagePointer) {
|
||||||
const Handle archiveHandle = Handle(mem.read64(messagePointer + 8));
|
const HandleType archiveHandle = HandleType(mem.read64(messagePointer + 8));
|
||||||
const u32 filePathType = mem.read32(messagePointer + 16);
|
const u32 filePathType = mem.read32(messagePointer + 16);
|
||||||
const u32 filePathSize = mem.read32(messagePointer + 20);
|
const u32 filePathSize = mem.read32(messagePointer + 20);
|
||||||
const u32 attributes = mem.read32(messagePointer + 24);
|
const u32 attributes = mem.read32(messagePointer + 24);
|
||||||
|
@ -403,7 +395,7 @@ void FSService::createFile(u32 messagePointer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FSService::deleteFile(u32 messagePointer) {
|
void FSService::deleteFile(u32 messagePointer) {
|
||||||
const Handle archiveHandle = Handle(mem.read64(messagePointer + 8));
|
const HandleType archiveHandle = HandleType(mem.read64(messagePointer + 8));
|
||||||
const u32 filePathType = mem.read32(messagePointer + 16);
|
const u32 filePathType = mem.read32(messagePointer + 16);
|
||||||
const u32 filePathSize = mem.read32(messagePointer + 20);
|
const u32 filePathSize = mem.read32(messagePointer + 20);
|
||||||
const u32 filePathPointer = mem.read32(messagePointer + 28);
|
const u32 filePathPointer = mem.read32(messagePointer + 28);
|
||||||
|
@ -425,7 +417,7 @@ void FSService::deleteFile(u32 messagePointer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FSService::deleteDirectory(u32 messagePointer) {
|
void FSService::deleteDirectory(u32 messagePointer) {
|
||||||
const Handle archiveHandle = Handle(mem.read64(messagePointer + 8));
|
const HandleType archiveHandle = HandleType(mem.read64(messagePointer + 8));
|
||||||
const u32 filePathType = mem.read32(messagePointer + 16);
|
const u32 filePathType = mem.read32(messagePointer + 16);
|
||||||
const u32 filePathSize = mem.read32(messagePointer + 20);
|
const u32 filePathSize = mem.read32(messagePointer + 20);
|
||||||
const u32 filePathPointer = mem.read32(messagePointer + 28);
|
const u32 filePathPointer = mem.read32(messagePointer + 28);
|
||||||
|
@ -470,8 +462,7 @@ void FSService::formatSaveData(u32 messagePointer) {
|
||||||
log("FS::FormatSaveData\n");
|
log("FS::FormatSaveData\n");
|
||||||
|
|
||||||
const u32 archiveID = mem.read32(messagePointer + 4);
|
const u32 archiveID = mem.read32(messagePointer + 4);
|
||||||
if (archiveID != ArchiveID::SaveData)
|
if (archiveID != ArchiveID::SaveData) Helpers::panic("FS::FormatSaveData: Archive is not SaveData");
|
||||||
Helpers::panic("FS::FormatSaveData: Archive is not SaveData");
|
|
||||||
|
|
||||||
// Read path and path info
|
// Read path and path info
|
||||||
const u32 pathType = mem.read32(messagePointer + 8);
|
const u32 pathType = mem.read32(messagePointer + 8);
|
||||||
|
@ -481,21 +472,15 @@ void FSService::formatSaveData(u32 messagePointer) {
|
||||||
// Size of a block. Seems to always be 0x200
|
// Size of a block. Seems to always be 0x200
|
||||||
const u32 blockSize = mem.read32(messagePointer + 16);
|
const u32 blockSize = mem.read32(messagePointer + 16);
|
||||||
|
|
||||||
if (blockSize != 0x200 && blockSize != 0x1000)
|
if (blockSize != 0x200 && blockSize != 0x1000) Helpers::panic("FS::FormatSaveData: Invalid SaveData block size");
|
||||||
Helpers::panic("FS::FormatSaveData: Invalid SaveData block size");
|
|
||||||
|
|
||||||
const u32 directoryNum = mem.read32(messagePointer + 20); // Max number of directories
|
const u32 directoryNum = mem.read32(messagePointer + 20); // Max number of directories
|
||||||
const u32 fileNum = mem.read32(messagePointer + 24); // Max number of files
|
const u32 fileNum = mem.read32(messagePointer + 24); // Max number of files
|
||||||
const u32 directoryBucketNum = mem.read32(messagePointer + 28); // Not sure what a directory bucket is...?
|
const u32 directoryBucketNum = mem.read32(messagePointer + 28); // Not sure what a directory bucket is...?
|
||||||
const u32 fileBucketNum = mem.read32(messagePointer + 32); // Same here
|
const u32 fileBucketNum = mem.read32(messagePointer + 32); // Same here
|
||||||
const bool duplicateData = mem.read8(messagePointer + 36) != 0;
|
const bool duplicateData = mem.read8(messagePointer + 36) != 0;
|
||||||
|
|
||||||
ArchiveBase::FormatInfo info {
|
ArchiveBase::FormatInfo info{.size = blockSize * 0x200, .numOfDirectories = directoryNum, .numOfFiles = fileNum, .duplicateData = duplicateData};
|
||||||
.size = blockSize * 0x200,
|
|
||||||
.numOfDirectories = directoryNum,
|
|
||||||
.numOfFiles = fileNum,
|
|
||||||
.duplicateData = duplicateData
|
|
||||||
};
|
|
||||||
|
|
||||||
saveData.format(path, info);
|
saveData.format(path, info);
|
||||||
|
|
||||||
|
@ -512,8 +497,8 @@ void FSService::deleteExtSaveData(u32 messagePointer) {
|
||||||
log("FS::DeleteExtSaveData (media type = %d, saveID = %llx) (stubbed)\n", mediaType, saveID);
|
log("FS::DeleteExtSaveData (media type = %d, saveID = %llx) (stubbed)\n", mediaType, saveID);
|
||||||
|
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x0852, 1, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0x0852, 1, 0));
|
||||||
// TODO: We can't properly implement this yet until we properly support title/save IDs. We will stub this and insert a warning for now. Required for Planet Robobot
|
// TODO: We can't properly implement this yet until we properly support title/save IDs. We will stub this and insert a warning for now. Required
|
||||||
// When we properly implement it, it will just be a recursive directory deletion
|
// for Planet Robobot When we properly implement it, it will just be a recursive directory deletion
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -521,7 +506,8 @@ void FSService::createExtSaveData(u32 messagePointer) {
|
||||||
Helpers::warn("Stubbed call to FS::CreateExtSaveData!");
|
Helpers::warn("Stubbed call to FS::CreateExtSaveData!");
|
||||||
// First 4 words of parameters are the ExtSaveData info
|
// First 4 words of parameters are the ExtSaveData info
|
||||||
// https://www.3dbrew.org/wiki/Filesystem_services#ExtSaveDataInfo
|
// https://www.3dbrew.org/wiki/Filesystem_services#ExtSaveDataInfo
|
||||||
// This creates the ExtSaveData with the specified saveid in the specified media type. It stores the SMDH as "icon" in the root of the created directory.
|
// This creates the ExtSaveData with the specified saveid in the specified media type. It stores the SMDH as "icon" in the root of the created
|
||||||
|
// directory.
|
||||||
const u8 mediaType = mem.read8(messagePointer + 4);
|
const u8 mediaType = mem.read8(messagePointer + 4);
|
||||||
const u64 saveID = mem.read64(messagePointer + 8);
|
const u64 saveID = mem.read64(messagePointer + 8);
|
||||||
const u32 numOfDirectories = mem.read32(messagePointer + 20);
|
const u32 numOfDirectories = mem.read32(messagePointer + 20);
|
||||||
|
@ -541,18 +527,13 @@ void FSService::formatThisUserSaveData(u32 messagePointer) {
|
||||||
log("FS::FormatThisUserSaveData\n");
|
log("FS::FormatThisUserSaveData\n");
|
||||||
|
|
||||||
const u32 blockSize = mem.read32(messagePointer + 4);
|
const u32 blockSize = mem.read32(messagePointer + 4);
|
||||||
const u32 directoryNum = mem.read32(messagePointer + 8); // Max number of directories
|
const u32 directoryNum = mem.read32(messagePointer + 8); // Max number of directories
|
||||||
const u32 fileNum = mem.read32(messagePointer + 12); // Max number of files
|
const u32 fileNum = mem.read32(messagePointer + 12); // Max number of files
|
||||||
const u32 directoryBucketNum = mem.read32(messagePointer + 16); // Not sure what a directory bucket is...?
|
const u32 directoryBucketNum = mem.read32(messagePointer + 16); // Not sure what a directory bucket is...?
|
||||||
const u32 fileBucketNum = mem.read32(messagePointer + 20); // Same here
|
const u32 fileBucketNum = mem.read32(messagePointer + 20); // Same here
|
||||||
const bool duplicateData = mem.read8(messagePointer + 24) != 0;
|
const bool duplicateData = mem.read8(messagePointer + 24) != 0;
|
||||||
|
|
||||||
ArchiveBase::FormatInfo info {
|
ArchiveBase::FormatInfo info{.size = blockSize * 0x200, .numOfDirectories = directoryNum, .numOfFiles = fileNum, .duplicateData = duplicateData};
|
||||||
.size = blockSize * 0x200,
|
|
||||||
.numOfDirectories = directoryNum,
|
|
||||||
.numOfFiles = fileNum,
|
|
||||||
.duplicateData = duplicateData
|
|
||||||
};
|
|
||||||
FSPath emptyPath;
|
FSPath emptyPath;
|
||||||
|
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x080F, 1, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0x080F, 1, 0));
|
||||||
|
@ -560,7 +541,7 @@ void FSService::formatThisUserSaveData(u32 messagePointer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FSService::controlArchive(u32 messagePointer) {
|
void FSService::controlArchive(u32 messagePointer) {
|
||||||
const Handle archiveHandle = Handle(mem.read64(messagePointer + 4));
|
const HandleType archiveHandle = HandleType(mem.read64(messagePointer + 4));
|
||||||
const u32 action = mem.read32(messagePointer + 12);
|
const u32 action = mem.read32(messagePointer + 12);
|
||||||
const u32 inputSize = mem.read32(messagePointer + 16);
|
const u32 inputSize = mem.read32(messagePointer + 16);
|
||||||
const u32 outputSize = mem.read32(messagePointer + 20);
|
const u32 outputSize = mem.read32(messagePointer + 20);
|
||||||
|
@ -578,24 +559,22 @@ void FSService::controlArchive(u32 messagePointer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case 0: // Commit save data changes. Shouldn't need us to do anything
|
case 0: // Commit save data changes. Shouldn't need us to do anything
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1: // Retrieves a file's last-modified timestamp. Seen in DDLC, stubbed for the moment
|
case 1: // Retrieves a file's last-modified timestamp. Seen in DDLC, stubbed for the moment
|
||||||
Helpers::warn("FS::ControlArchive: Tried to retrieve a file's last-modified timestamp");
|
Helpers::warn("FS::ControlArchive: Tried to retrieve a file's last-modified timestamp");
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default: Helpers::panic("Unimplemented action for ControlArchive (action = %X)\n", action); break;
|
||||||
Helpers::panic("Unimplemented action for ControlArchive (action = %X)\n", action);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FSService::getFreeBytes(u32 messagePointer) {
|
void FSService::getFreeBytes(u32 messagePointer) {
|
||||||
log("FS::GetFreeBytes\n");
|
log("FS::GetFreeBytes\n");
|
||||||
const Handle archiveHandle = (Handle)mem.read64(messagePointer + 4);
|
const HandleType archiveHandle = (HandleType)mem.read64(messagePointer + 4);
|
||||||
auto session = kernel.getObject(archiveHandle, KernelObjectType::Archive);
|
auto session = kernel.getObject(archiveHandle, KernelObjectType::Archive);
|
||||||
|
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x812, 3, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0x812, 3, 0));
|
||||||
|
@ -639,7 +618,7 @@ void FSService::getArchiveResource(u32 messagePointer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FSService::setArchivePriority(u32 messagePointer) {
|
void FSService::setArchivePriority(u32 messagePointer) {
|
||||||
Handle archive = mem.read64(messagePointer + 4);
|
HandleType archive = mem.read64(messagePointer + 4);
|
||||||
const u32 value = mem.read32(messagePointer + 12);
|
const u32 value = mem.read32(messagePointer + 12);
|
||||||
log("FS::SetArchivePriority (priority = %d, archive handle = %X)\n", value, handle);
|
log("FS::SetArchivePriority (priority = %d, archive handle = %X)\n", value, handle);
|
||||||
|
|
||||||
|
@ -673,9 +652,9 @@ void FSService::getThisSaveDataSecureValue(u32 messagePointer) {
|
||||||
|
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x86F, 1, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0x86F, 1, 0));
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
mem.write8(messagePointer + 8, 0); // Secure value does not exist
|
mem.write8(messagePointer + 8, 0); // Secure value does not exist
|
||||||
mem.write8(messagePointer + 12, 1); // TODO: What is this?
|
mem.write8(messagePointer + 12, 1); // TODO: What is this?
|
||||||
mem.write64(messagePointer + 16, 0); // Secure value
|
mem.write64(messagePointer + 16, 0); // Secure value
|
||||||
}
|
}
|
||||||
|
|
||||||
void FSService::setThisSaveDataSecureValue(u32 messagePointer) {
|
void FSService::setThisSaveDataSecureValue(u32 messagePointer) {
|
||||||
|
@ -731,8 +710,8 @@ void FSService::renameFile(u32 messagePointer) {
|
||||||
|
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x805, 1, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0x805, 1, 0));
|
||||||
|
|
||||||
const Handle sourceArchiveHandle = mem.read64(messagePointer + 8);
|
const HandleType sourceArchiveHandle = mem.read64(messagePointer + 8);
|
||||||
const Handle destArchiveHandle = mem.read64(messagePointer + 24);
|
const HandleType destArchiveHandle = mem.read64(messagePointer + 24);
|
||||||
|
|
||||||
// Read path info
|
// Read path info
|
||||||
const u32 sourcePathType = mem.read32(messagePointer + 16);
|
const u32 sourcePathType = mem.read32(messagePointer + 16);
|
||||||
|
@ -785,4 +764,4 @@ void FSService::getSdmcArchiveResource(u32 messagePointer) {
|
||||||
mem.write32(messagePointer + 12, resource.clusterSize);
|
mem.write32(messagePointer + 12, resource.clusterSize);
|
||||||
mem.write32(messagePointer + 16, resource.partitionCapacityInClusters);
|
mem.write32(messagePointer + 16, resource.partitionCapacityInClusters);
|
||||||
mem.write32(messagePointer + 20, resource.freeSpaceInClusters);
|
mem.write32(messagePointer + 20, resource.freeSpaceInClusters);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
#include "services/hid.hpp"
|
#include "services/hid.hpp"
|
||||||
|
|
||||||
|
#include <bit>
|
||||||
|
|
||||||
#include "ipc.hpp"
|
#include "ipc.hpp"
|
||||||
#include "kernel.hpp"
|
#include "kernel.hpp"
|
||||||
#include <bit>
|
|
||||||
|
|
||||||
namespace HIDCommands {
|
namespace HIDCommands {
|
||||||
enum : u32 {
|
enum : u32 {
|
||||||
|
@ -86,24 +88,24 @@ void HIDService::disableGyroscopeLow(u32 messagePointer) {
|
||||||
|
|
||||||
void HIDService::getGyroscopeLowCalibrateParam(u32 messagePointer) {
|
void HIDService::getGyroscopeLowCalibrateParam(u32 messagePointer) {
|
||||||
log("HID::GetGyroscopeLowCalibrateParam\n");
|
log("HID::GetGyroscopeLowCalibrateParam\n");
|
||||||
constexpr s16 unit = 6700; // Approximately from Citra which took it from hardware
|
constexpr s16 unit = 6700; // Approximately from Citra which took it from hardware
|
||||||
|
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x16, 6, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0x16, 6, 0));
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
// Fill calibration data (for x/y/z depending on i)
|
// Fill calibration data (for x/y/z depending on i)
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
const u32 pointer = messagePointer + 8 + i * 3 * sizeof(u16); // Pointer to write the calibration info for the current coordinate
|
const u32 pointer = messagePointer + 8 + i * 3 * sizeof(u16); // Pointer to write the calibration info for the current coordinate
|
||||||
|
|
||||||
mem.write16(pointer, 0); // Zero point
|
mem.write16(pointer, 0); // Zero point
|
||||||
mem.write16(pointer + 1 * sizeof(u16), unit); // Positive unit point
|
mem.write16(pointer + 1 * sizeof(u16), unit); // Positive unit point
|
||||||
mem.write16(pointer + 2 * sizeof(u16), -unit); // Negative unit point
|
mem.write16(pointer + 2 * sizeof(u16), -unit); // Negative unit point
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HIDService::getGyroscopeCoefficient(u32 messagePointer) {
|
void HIDService::getGyroscopeCoefficient(u32 messagePointer) {
|
||||||
log("HID::GetGyroscopeLowRawToDpsCoefficient\n");
|
log("HID::GetGyroscopeLowRawToDpsCoefficient\n");
|
||||||
|
|
||||||
constexpr float gyroscopeCoeff = 14.375f; // Same as retail 3DS
|
constexpr float gyroscopeCoeff = 14.375f; // Same as retail 3DS
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x15, 2, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0x15, 2, 0));
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
mem.write32(messagePointer + 8, Helpers::bit_cast<u32, float>(gyroscopeCoeff));
|
mem.write32(messagePointer + 8, Helpers::bit_cast<u32, float>(gyroscopeCoeff));
|
||||||
|
@ -134,13 +136,13 @@ void HIDService::getIPCHandles(u32 messagePointer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0xA, 1, 7));
|
mem.write32(messagePointer, IPC::responseHeader(0xA, 1, 7));
|
||||||
mem.write32(messagePointer + 4, Result::Success); // Result code
|
mem.write32(messagePointer + 4, Result::Success); // Result code
|
||||||
mem.write32(messagePointer + 8, 0x14000000); // Translation descriptor
|
mem.write32(messagePointer + 8, 0x14000000); // Translation descriptor
|
||||||
mem.write32(messagePointer + 12, KernelHandles::HIDSharedMemHandle); // Shared memory handle
|
mem.write32(messagePointer + 12, KernelHandles::HIDSharedMemHandle); // Shared memory handle
|
||||||
|
|
||||||
// Write HID event handles
|
// Write HID event handles
|
||||||
for (int i = 0; i < events.size(); i++) {
|
for (int i = 0; i < events.size(); i++) {
|
||||||
mem.write32(messagePointer + 16 + sizeof(Handle) * i, events[i].value());
|
mem.write32(messagePointer + 16 + sizeof(HandleType) * i, events[i].value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,20 +151,20 @@ void HIDService::updateInputs(u64 currentTick) {
|
||||||
if (sharedMem) {
|
if (sharedMem) {
|
||||||
// First, update the pad state
|
// First, update the pad state
|
||||||
if (nextPadIndex == 0) {
|
if (nextPadIndex == 0) {
|
||||||
writeSharedMem<u64>(0x8, readSharedMem<u64>(0x0)); // Copy previous tick count
|
writeSharedMem<u64>(0x8, readSharedMem<u64>(0x0)); // Copy previous tick count
|
||||||
writeSharedMem<u64>(0x0, currentTick); // Write new tick count
|
writeSharedMem<u64>(0x0, currentTick); // Write new tick count
|
||||||
}
|
}
|
||||||
|
|
||||||
writeSharedMem<u32>(0x10, nextPadIndex); // Index last updated by the HID module
|
writeSharedMem<u32>(0x10, nextPadIndex); // Index last updated by the HID module
|
||||||
writeSharedMem<u32>(0x1C, newButtons); // Current PAD state
|
writeSharedMem<u32>(0x1C, newButtons); // Current PAD state
|
||||||
writeSharedMem<s16>(0x20, circlePadX); // Current circle pad state
|
writeSharedMem<s16>(0x20, circlePadX); // Current circle pad state
|
||||||
writeSharedMem<s16>(0x22, circlePadY);
|
writeSharedMem<s16>(0x22, circlePadY);
|
||||||
|
|
||||||
const size_t padEntryOffset = 0x28 + (nextPadIndex * 0x10); // Offset in the array of 8 pad entries
|
const size_t padEntryOffset = 0x28 + (nextPadIndex * 0x10); // Offset in the array of 8 pad entries
|
||||||
nextPadIndex = (nextPadIndex + 1) % 8; // Move to next entry
|
nextPadIndex = (nextPadIndex + 1) % 8; // Move to next entry
|
||||||
|
|
||||||
const u32 pressed = (newButtons ^ oldButtons) & newButtons; // Pressed buttons
|
const u32 pressed = (newButtons ^ oldButtons) & newButtons; // Pressed buttons
|
||||||
const u32 released = (newButtons ^ oldButtons) & oldButtons; // Released buttons
|
const u32 released = (newButtons ^ oldButtons) & oldButtons; // Released buttons
|
||||||
oldButtons = newButtons;
|
oldButtons = newButtons;
|
||||||
|
|
||||||
writeSharedMem<u32>(padEntryOffset, newButtons);
|
writeSharedMem<u32>(padEntryOffset, newButtons);
|
||||||
|
@ -173,12 +175,12 @@ void HIDService::updateInputs(u64 currentTick) {
|
||||||
|
|
||||||
// Next, update touchscreen state
|
// Next, update touchscreen state
|
||||||
if (nextTouchscreenIndex == 0) {
|
if (nextTouchscreenIndex == 0) {
|
||||||
writeSharedMem<u64>(0xB0, readSharedMem<u64>(0xA8)); // Copy previous tick count
|
writeSharedMem<u64>(0xB0, readSharedMem<u64>(0xA8)); // Copy previous tick count
|
||||||
writeSharedMem<u64>(0xA8, currentTick); // Write new tick count
|
writeSharedMem<u64>(0xA8, currentTick); // Write new tick count
|
||||||
}
|
}
|
||||||
writeSharedMem<u32>(0xB8, nextTouchscreenIndex); // Index last updated by the HID module
|
writeSharedMem<u32>(0xB8, nextTouchscreenIndex); // Index last updated by the HID module
|
||||||
const size_t touchEntryOffset = 0xC8 + (nextTouchscreenIndex * 8); // Offset in the array of 8 touchscreen entries
|
const size_t touchEntryOffset = 0xC8 + (nextTouchscreenIndex * 8); // Offset in the array of 8 touchscreen entries
|
||||||
nextTouchscreenIndex = (nextTouchscreenIndex + 1) % 8; // Move to next entry
|
nextTouchscreenIndex = (nextTouchscreenIndex + 1) % 8; // Move to next entry
|
||||||
|
|
||||||
writeSharedMem<u16>(touchEntryOffset, touchScreenX);
|
writeSharedMem<u16>(touchEntryOffset, touchScreenX);
|
||||||
writeSharedMem<u16>(touchEntryOffset + 2, touchScreenY);
|
writeSharedMem<u16>(touchEntryOffset + 2, touchScreenY);
|
||||||
|
@ -186,16 +188,16 @@ void HIDService::updateInputs(u64 currentTick) {
|
||||||
|
|
||||||
// Next, update accelerometer state
|
// Next, update accelerometer state
|
||||||
if (nextAccelerometerIndex == 0) {
|
if (nextAccelerometerIndex == 0) {
|
||||||
writeSharedMem<u64>(0x110, readSharedMem<u64>(0x108)); // Copy previous tick count
|
writeSharedMem<u64>(0x110, readSharedMem<u64>(0x108)); // Copy previous tick count
|
||||||
writeSharedMem<u64>(0x108, currentTick); // Write new tick count
|
writeSharedMem<u64>(0x108, currentTick); // Write new tick count
|
||||||
}
|
}
|
||||||
writeSharedMem<u32>(0x118, nextAccelerometerIndex); // Index last updated by the HID module
|
writeSharedMem<u32>(0x118, nextAccelerometerIndex); // Index last updated by the HID module
|
||||||
nextAccelerometerIndex = (nextAccelerometerIndex + 1) % 8; // Move to next entry
|
nextAccelerometerIndex = (nextAccelerometerIndex + 1) % 8; // Move to next entry
|
||||||
|
|
||||||
// Next, update gyro state
|
// Next, update gyro state
|
||||||
if (nextGyroIndex == 0) {
|
if (nextGyroIndex == 0) {
|
||||||
writeSharedMem<u64>(0x160, readSharedMem<u64>(0x158)); // Copy previous tick count
|
writeSharedMem<u64>(0x160, readSharedMem<u64>(0x158)); // Copy previous tick count
|
||||||
writeSharedMem<u64>(0x158, currentTick); // Write new tick count
|
writeSharedMem<u64>(0x158, currentTick); // Write new tick count
|
||||||
}
|
}
|
||||||
const size_t gyroEntryOffset = 0x178 + (nextGyroIndex * 6); // Offset in the array of 8 touchscreen entries
|
const size_t gyroEntryOffset = 0x178 + (nextGyroIndex * 6); // Offset in the array of 8 touchscreen entries
|
||||||
writeSharedMem<u16>(gyroEntryOffset, pitch);
|
writeSharedMem<u16>(gyroEntryOffset, pitch);
|
||||||
|
@ -205,8 +207,8 @@ void HIDService::updateInputs(u64 currentTick) {
|
||||||
// Since gyroscope euler angles are relative, we zero them out here and the frontend will update them again when we receive a new rotation
|
// Since gyroscope euler angles are relative, we zero them out here and the frontend will update them again when we receive a new rotation
|
||||||
roll = pitch = yaw = 0;
|
roll = pitch = yaw = 0;
|
||||||
|
|
||||||
writeSharedMem<u32>(0x168, nextGyroIndex); // Index last updated by the HID module
|
writeSharedMem<u32>(0x168, nextGyroIndex); // Index last updated by the HID module
|
||||||
nextGyroIndex = (nextGyroIndex + 1) % 32; // Move to next entry
|
nextGyroIndex = (nextGyroIndex + 1) % 32; // Move to next entry
|
||||||
}
|
}
|
||||||
|
|
||||||
// For some reason, the original developers decided to signal the HID events each time the OS rescanned inputs
|
// For some reason, the original developers decided to signal the HID events each time the OS rescanned inputs
|
||||||
|
@ -218,4 +220,4 @@ void HIDService::updateInputs(u64 currentTick) {
|
||||||
kernel.signalEvent(e.value());
|
kernel.signalEvent(e.value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
#include "services/ldr_ro.hpp"
|
#include "services/ldr_ro.hpp"
|
||||||
#include "ipc.hpp"
|
|
||||||
#include "kernel.hpp"
|
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "ipc.hpp"
|
||||||
|
#include "kernel.hpp"
|
||||||
|
|
||||||
namespace LDRCommands {
|
namespace LDRCommands {
|
||||||
enum : u32 {
|
enum : u32 {
|
||||||
Initialize = 0x000100C2,
|
Initialize = 0x000100C2,
|
||||||
|
@ -65,10 +66,13 @@ namespace SegmentTable {
|
||||||
|
|
||||||
namespace SegmentID {
|
namespace SegmentID {
|
||||||
enum : u32 {
|
enum : u32 {
|
||||||
TEXT, RODATA, DATA, BSS,
|
TEXT,
|
||||||
|
RODATA,
|
||||||
|
DATA,
|
||||||
|
BSS,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
} // namespace SegmentTable
|
||||||
|
|
||||||
namespace NamedExportTable {
|
namespace NamedExportTable {
|
||||||
enum : u32 {
|
enum : u32 {
|
||||||
|
@ -118,8 +122,8 @@ namespace RelocationPatch {
|
||||||
enum : u32 {
|
enum : u32 {
|
||||||
SegmentOffset = 0,
|
SegmentOffset = 0,
|
||||||
PatchType = 4,
|
PatchType = 4,
|
||||||
IsLastEntry = 5, // For import patches
|
IsLastEntry = 5, // For import patches
|
||||||
SegmentIndex = 5, // For relocation patches
|
SegmentIndex = 5, // For relocation patches
|
||||||
IsResolved = 6,
|
IsResolved = 6,
|
||||||
Addend = 8,
|
Addend = 8,
|
||||||
};
|
};
|
||||||
|
@ -129,7 +133,7 @@ namespace RelocationPatch {
|
||||||
AbsoluteAddress = 2,
|
AbsoluteAddress = 2,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
}; // namespace RelocationPatch
|
||||||
|
|
||||||
struct CROHeaderEntry {
|
struct CROHeaderEntry {
|
||||||
u32 offset, size;
|
u32 offset, size;
|
||||||
|
@ -144,12 +148,12 @@ static const std::string CRR_MAGIC("CRR0");
|
||||||
class CRO {
|
class CRO {
|
||||||
Memory &mem;
|
Memory &mem;
|
||||||
|
|
||||||
u32 croPointer; // Origin address of CRO in RAM
|
u32 croPointer; // Origin address of CRO in RAM
|
||||||
u32 oldDataSegmentOffset;
|
u32 oldDataSegmentOffset;
|
||||||
|
|
||||||
bool isCRO; // False if CRS
|
bool isCRO; // False if CRS
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CRO(Memory &mem, u32 croPointer, bool isCRO) : mem(mem), croPointer(croPointer), oldDataSegmentOffset(0), isCRO(isCRO) {}
|
CRO(Memory &mem, u32 croPointer, bool isCRO) : mem(mem), croPointer(croPointer), oldDataSegmentOffset(0), isCRO(isCRO) {}
|
||||||
~CRO() = default;
|
~CRO() = default;
|
||||||
|
|
||||||
|
@ -159,21 +163,13 @@ public:
|
||||||
return mem.readString(moduleName.offset, moduleName.size);
|
return mem.readString(moduleName.offset, moduleName.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 getNextCRO() {
|
u32 getNextCRO() { return mem.read32(croPointer + CROHeader::NextCRO); }
|
||||||
return mem.read32(croPointer + CROHeader::NextCRO);
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 getPrevCRO() {
|
|
||||||
return mem.read32(croPointer + CROHeader::PrevCRO);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setNextCRO(u32 nextCRO) {
|
u32 getPrevCRO() { return mem.read32(croPointer + CROHeader::PrevCRO); }
|
||||||
mem.write32(croPointer + CROHeader::NextCRO, nextCRO);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setPrevCRO(u32 prevCRO) {
|
void setNextCRO(u32 nextCRO) { mem.write32(croPointer + CROHeader::NextCRO, nextCRO); }
|
||||||
mem.write32(croPointer + CROHeader::PrevCRO, prevCRO);
|
|
||||||
}
|
void setPrevCRO(u32 prevCRO) { mem.write32(croPointer + CROHeader::PrevCRO, prevCRO); }
|
||||||
|
|
||||||
void write32(u32 addr, u32 value) {
|
void write32(u32 addr, u32 value) {
|
||||||
// Note: some games export symbols to the static module, which doesn't contain any segments.
|
// Note: some games export symbols to the static module, which doesn't contain any segments.
|
||||||
|
@ -181,11 +177,11 @@ public:
|
||||||
// can't be accessed via mem.write32()
|
// can't be accessed via mem.write32()
|
||||||
auto writePointer = mem.getWritePointer(addr);
|
auto writePointer = mem.getWritePointer(addr);
|
||||||
if (writePointer) {
|
if (writePointer) {
|
||||||
*(u32*)writePointer = value;
|
*(u32 *)writePointer = value;
|
||||||
} else {
|
} else {
|
||||||
auto readPointer = mem.getReadPointer(addr);
|
auto readPointer = mem.getReadPointer(addr);
|
||||||
if (readPointer) {
|
if (readPointer) {
|
||||||
*(u32*)readPointer = value;
|
*(u32 *)readPointer = value;
|
||||||
} else {
|
} else {
|
||||||
Helpers::panic("LDR_RO write to invalid address = %X\n", addr);
|
Helpers::panic("LDR_RO write to invalid address = %X\n", addr);
|
||||||
}
|
}
|
||||||
|
@ -219,11 +215,9 @@ public:
|
||||||
return entryOffset + offset;
|
return entryOffset + offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 getOnUnresolvedAddr() {
|
u32 getOnUnresolvedAddr() { return getSegmentAddr(mem.read32(croPointer + CROHeader::OnUnresolved)); }
|
||||||
return getSegmentAddr(mem.read32(croPointer + CROHeader::OnUnresolved));
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 getNamedExportSymbolAddr(const std::string& symbolName) {
|
u32 getNamedExportSymbolAddr(const std::string &symbolName) {
|
||||||
// Note: The CRO contains a trie for fast symbol lookup. For simplicity,
|
// Note: The CRO contains a trie for fast symbol lookup. For simplicity,
|
||||||
// we won't use it and instead look up the symbol in the named export symbol table
|
// we won't use it and instead look up the symbol in the named export symbol table
|
||||||
|
|
||||||
|
@ -233,7 +227,7 @@ public:
|
||||||
|
|
||||||
for (u32 namedExport = 0; namedExport < namedExportTable.size; namedExport++) {
|
for (u32 namedExport = 0; namedExport < namedExportTable.size; namedExport++) {
|
||||||
const u32 nameOffset = mem.read32(namedExportTable.offset + 8 * namedExport + NamedExportTable::NameOffset);
|
const u32 nameOffset = mem.read32(namedExportTable.offset + 8 * namedExport + NamedExportTable::NameOffset);
|
||||||
|
|
||||||
const std::string exportSymbolName = mem.readString(nameOffset, exportStringSize);
|
const std::string exportSymbolName = mem.readString(nameOffset, exportStringSize);
|
||||||
|
|
||||||
if (symbolName.compare(exportSymbolName) == 0) {
|
if (symbolName.compare(exportSymbolName) == 0) {
|
||||||
|
@ -437,13 +431,16 @@ public:
|
||||||
const u32 segmentID = mem.read32(segmentTable.offset + 12 * segment + SegmentTable::ID);
|
const u32 segmentID = mem.read32(segmentTable.offset + 12 * segment + SegmentTable::ID);
|
||||||
switch (segmentID) {
|
switch (segmentID) {
|
||||||
case SegmentTable::SegmentID::DATA:
|
case SegmentTable::SegmentID::DATA:
|
||||||
*oldDataVaddr = segmentOffset + croPointer; oldDataSegmentOffset = segmentOffset; segmentOffset = dataVaddr; break;
|
*oldDataVaddr = segmentOffset + croPointer;
|
||||||
|
oldDataSegmentOffset = segmentOffset;
|
||||||
|
segmentOffset = dataVaddr;
|
||||||
|
break;
|
||||||
case SegmentTable::SegmentID::BSS: segmentOffset = bssVaddr; break;
|
case SegmentTable::SegmentID::BSS: segmentOffset = bssVaddr; break;
|
||||||
case SegmentTable::SegmentID::TEXT:
|
case SegmentTable::SegmentID::TEXT:
|
||||||
case SegmentTable::SegmentID::RODATA:
|
case SegmentTable::SegmentID::RODATA:
|
||||||
if (segmentOffset != 0) segmentOffset += croPointer; break;
|
if (segmentOffset != 0) segmentOffset += croPointer;
|
||||||
default:
|
break;
|
||||||
Helpers::panic("Unknown segment ID = %u", segmentID);
|
default: Helpers::panic("Unknown segment ID = %u", segmentID);
|
||||||
}
|
}
|
||||||
|
|
||||||
mem.write32(segmentTable.offset + 12 * segment + SegmentTable::Offset, segmentOffset);
|
mem.write32(segmentTable.offset + 12 * segment + SegmentTable::Offset, segmentOffset);
|
||||||
|
@ -464,9 +461,9 @@ public:
|
||||||
case SegmentTable::SegmentID::BSS: segmentOffset = 0; break;
|
case SegmentTable::SegmentID::BSS: segmentOffset = 0; break;
|
||||||
case SegmentTable::SegmentID::TEXT:
|
case SegmentTable::SegmentID::TEXT:
|
||||||
case SegmentTable::SegmentID::RODATA:
|
case SegmentTable::SegmentID::RODATA:
|
||||||
if (segmentOffset != 0) segmentOffset -= croPointer; break;
|
if (segmentOffset != 0) segmentOffset -= croPointer;
|
||||||
default:
|
break;
|
||||||
Helpers::panic("Unknown segment ID = %u", segmentID);
|
default: Helpers::panic("Unknown segment ID = %u", segmentID);
|
||||||
}
|
}
|
||||||
|
|
||||||
mem.write32(segmentTable.offset + 12 * segment + SegmentTable::Offset, segmentOffset);
|
mem.write32(segmentTable.offset + 12 * segment + SegmentTable::Offset, segmentOffset);
|
||||||
|
@ -630,7 +627,9 @@ public:
|
||||||
u32 relocationOffset = mem.read32(anonymousImportTable.offset + 8 * anonymousImport + AnonymousImportTable::RelocationOffset);
|
u32 relocationOffset = mem.read32(anonymousImportTable.offset + 8 * anonymousImport + AnonymousImportTable::RelocationOffset);
|
||||||
|
|
||||||
if (relocationOffset != 0) {
|
if (relocationOffset != 0) {
|
||||||
mem.write32(anonymousImportTable.offset + 8 * anonymousImport + AnonymousImportTable::RelocationOffset, relocationOffset + croPointer);
|
mem.write32(
|
||||||
|
anonymousImportTable.offset + 8 * anonymousImport + AnonymousImportTable::RelocationOffset, relocationOffset + croPointer
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -644,7 +643,9 @@ public:
|
||||||
u32 relocationOffset = mem.read32(anonymousImportTable.offset + 8 * anonymousImport + AnonymousImportTable::RelocationOffset);
|
u32 relocationOffset = mem.read32(anonymousImportTable.offset + 8 * anonymousImport + AnonymousImportTable::RelocationOffset);
|
||||||
|
|
||||||
if (relocationOffset != 0) {
|
if (relocationOffset != 0) {
|
||||||
mem.write32(anonymousImportTable.offset + 8 * anonymousImport + AnonymousImportTable::RelocationOffset, relocationOffset - croPointer);
|
mem.write32(
|
||||||
|
anonymousImportTable.offset + 8 * anonymousImport + AnonymousImportTable::RelocationOffset, relocationOffset - croPointer
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -652,7 +653,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool relocateInternalSymbols(u32 oldDataVaddr) {
|
bool relocateInternalSymbols(u32 oldDataVaddr) {
|
||||||
const u8* header = (u8*)mem.getReadPointer(croPointer);
|
const u8 *header = (u8 *)mem.getReadPointer(croPointer);
|
||||||
|
|
||||||
const CROHeaderEntry relocationPatchTable = getHeaderEntry(CROHeader::RelocationPatchTableOffset);
|
const CROHeaderEntry relocationPatchTable = getHeaderEntry(CROHeader::RelocationPatchTableOffset);
|
||||||
const CROHeaderEntry segmentTable = getHeaderEntry(CROHeader::SegmentTableOffset);
|
const CROHeaderEntry segmentTable = getHeaderEntry(CROHeader::SegmentTableOffset);
|
||||||
|
@ -708,7 +709,7 @@ public:
|
||||||
for (u32 namedImport = 0; namedImport < namedImportTable.size; namedImport++) {
|
for (u32 namedImport = 0; namedImport < namedImportTable.size; namedImport++) {
|
||||||
const u32 nameOffset = mem.read32(namedImportTable.offset + 8 * namedImport + NamedImportTable::NameOffset);
|
const u32 nameOffset = mem.read32(namedImportTable.offset + 8 * namedImport + NamedImportTable::NameOffset);
|
||||||
const u32 relocationOffset = mem.read32(namedImportTable.offset + 8 * namedImport + NamedImportTable::RelocationOffset);
|
const u32 relocationOffset = mem.read32(namedImportTable.offset + 8 * namedImport + NamedImportTable::RelocationOffset);
|
||||||
|
|
||||||
const std::string symbolName = mem.readString(nameOffset, importStringSize);
|
const std::string symbolName = mem.readString(nameOffset, importStringSize);
|
||||||
|
|
||||||
if (symbolName.compare(std::string("__aeabi_atexit")) == 0) {
|
if (symbolName.compare(std::string("__aeabi_atexit")) == 0) {
|
||||||
|
@ -720,7 +721,7 @@ public:
|
||||||
const u32 exportSymbolAddr = cro.getNamedExportSymbolAddr(std::string("nnroAeabiAtexit_"));
|
const u32 exportSymbolAddr = cro.getNamedExportSymbolAddr(std::string("nnroAeabiAtexit_"));
|
||||||
if (exportSymbolAddr != 0) {
|
if (exportSymbolAddr != 0) {
|
||||||
patchBatch(relocationOffset, exportSymbolAddr);
|
patchBatch(relocationOffset, exportSymbolAddr);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -750,7 +751,7 @@ public:
|
||||||
|
|
||||||
if (isResolved == 0) {
|
if (isResolved == 0) {
|
||||||
const u32 nameOffset = mem.read32(namedImportTable.offset + 8 * namedImport + NamedImportTable::NameOffset);
|
const u32 nameOffset = mem.read32(namedImportTable.offset + 8 * namedImport + NamedImportTable::NameOffset);
|
||||||
|
|
||||||
const std::string symbolName = mem.readString(nameOffset, importStringSize);
|
const std::string symbolName = mem.readString(nameOffset, importStringSize);
|
||||||
|
|
||||||
// Check every loaded CRO for the symbol (the pain)
|
// Check every loaded CRO for the symbol (the pain)
|
||||||
|
@ -859,7 +860,7 @@ public:
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool clearModules() {
|
bool clearModules() {
|
||||||
const u32 onUnresolvedAddr = getOnUnresolvedAddr();
|
const u32 onUnresolvedAddr = getOnUnresolvedAddr();
|
||||||
|
|
||||||
|
@ -874,7 +875,7 @@ public:
|
||||||
if (indexedOffset == 0) {
|
if (indexedOffset == 0) {
|
||||||
Helpers::panic("Indexed symbol offset is NULL");
|
Helpers::panic("Indexed symbol offset is NULL");
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 relocationOffset = mem.read32(indexedOffset + 8 * indexedImport + IndexedImportTable::RelocationOffset);
|
const u32 relocationOffset = mem.read32(indexedOffset + 8 * indexedImport + IndexedImportTable::RelocationOffset);
|
||||||
|
|
||||||
patchBatch(relocationOffset, onUnresolvedAddr, true);
|
patchBatch(relocationOffset, onUnresolvedAddr, true);
|
||||||
|
@ -919,7 +920,7 @@ public:
|
||||||
|
|
||||||
if (isResolved == 0) {
|
if (isResolved == 0) {
|
||||||
const u32 nameOffset = mem.read32(namedImportTable.offset + 8 * namedImport + NamedImportTable::NameOffset);
|
const u32 nameOffset = mem.read32(namedImportTable.offset + 8 * namedImport + NamedImportTable::NameOffset);
|
||||||
|
|
||||||
const std::string symbolName = mem.readString(nameOffset, importStringSize);
|
const std::string symbolName = mem.readString(nameOffset, importStringSize);
|
||||||
|
|
||||||
// Check our current CRO for the symbol
|
// Check our current CRO for the symbol
|
||||||
|
@ -983,7 +984,7 @@ public:
|
||||||
u32 currentCROPointer = loadedCRS;
|
u32 currentCROPointer = loadedCRS;
|
||||||
while (currentCROPointer != 0) {
|
while (currentCROPointer != 0) {
|
||||||
CRO cro(mem, currentCROPointer, true);
|
CRO cro(mem, currentCROPointer, true);
|
||||||
|
|
||||||
const u32 onUnresolvedAddr = cro.getOnUnresolvedAddr();
|
const u32 onUnresolvedAddr = cro.getOnUnresolvedAddr();
|
||||||
|
|
||||||
const u32 importStringSize = mem.read32(currentCROPointer + CROHeader::ImportStringSize);
|
const u32 importStringSize = mem.read32(currentCROPointer + CROHeader::ImportStringSize);
|
||||||
|
@ -998,7 +999,7 @@ public:
|
||||||
|
|
||||||
if (isResolved != 0) {
|
if (isResolved != 0) {
|
||||||
const u32 nameOffset = mem.read32(namedImportTable.offset + 8 * namedImport + NamedImportTable::NameOffset);
|
const u32 nameOffset = mem.read32(namedImportTable.offset + 8 * namedImport + NamedImportTable::NameOffset);
|
||||||
|
|
||||||
const std::string symbolName = mem.readString(nameOffset, importStringSize);
|
const std::string symbolName = mem.readString(nameOffset, importStringSize);
|
||||||
|
|
||||||
// Check our current CRO for the symbol
|
// Check our current CRO for the symbol
|
||||||
|
@ -1106,7 +1107,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
CRO crs(mem, loadedCRS, false);
|
CRO crs(mem, loadedCRS, false);
|
||||||
|
|
||||||
u32 headAddr = crs.getPrevCRO();
|
u32 headAddr = crs.getPrevCRO();
|
||||||
if (autoLink) {
|
if (autoLink) {
|
||||||
headAddr = crs.getNextCRO();
|
headAddr = crs.getNextCRO();
|
||||||
|
@ -1189,9 +1190,7 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void LDRService::reset() {
|
void LDRService::reset() { loadedCRS = 0; }
|
||||||
loadedCRS = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LDRService::handleSyncRequest(u32 messagePointer) {
|
void LDRService::handleSyncRequest(u32 messagePointer) {
|
||||||
const u32 command = mem.read32(messagePointer);
|
const u32 command = mem.read32(messagePointer);
|
||||||
|
@ -1210,7 +1209,7 @@ void LDRService::initialize(u32 messagePointer) {
|
||||||
const u32 crsPointer = mem.read32(messagePointer + 4);
|
const u32 crsPointer = mem.read32(messagePointer + 4);
|
||||||
const u32 size = mem.read32(messagePointer + 8);
|
const u32 size = mem.read32(messagePointer + 8);
|
||||||
const u32 mapVaddr = mem.read32(messagePointer + 12);
|
const u32 mapVaddr = mem.read32(messagePointer + 12);
|
||||||
const Handle process = mem.read32(messagePointer + 20);
|
const HandleType process = mem.read32(messagePointer + 20);
|
||||||
|
|
||||||
log("LDR_RO::Initialize (buffer = %08X, size = %08X, vaddr = %08X, process = %X)\n", crsPointer, size, mapVaddr, process);
|
log("LDR_RO::Initialize (buffer = %08X, size = %08X, vaddr = %08X, process = %X)\n", crsPointer, size, mapVaddr, process);
|
||||||
|
|
||||||
|
@ -1258,7 +1257,7 @@ void LDRService::initialize(u32 messagePointer) {
|
||||||
|
|
||||||
void LDRService::linkCRO(u32 messagePointer) {
|
void LDRService::linkCRO(u32 messagePointer) {
|
||||||
const u32 mapVaddr = mem.read32(messagePointer + 4);
|
const u32 mapVaddr = mem.read32(messagePointer + 4);
|
||||||
const Handle process = mem.read32(messagePointer + 12);
|
const HandleType process = mem.read32(messagePointer + 12);
|
||||||
|
|
||||||
log("LDR_RO::LinkCRO (vaddr = %X, process = %X)\n", mapVaddr, process);
|
log("LDR_RO::LinkCRO (vaddr = %X, process = %X)\n", mapVaddr, process);
|
||||||
|
|
||||||
|
@ -1287,7 +1286,7 @@ void LDRService::linkCRO(u32 messagePointer) {
|
||||||
void LDRService::loadCRR(u32 messagePointer) {
|
void LDRService::loadCRR(u32 messagePointer) {
|
||||||
const u32 crrPointer = mem.read32(messagePointer + 4);
|
const u32 crrPointer = mem.read32(messagePointer + 4);
|
||||||
const u32 size = mem.read32(messagePointer + 8);
|
const u32 size = mem.read32(messagePointer + 8);
|
||||||
const Handle process = mem.read32(messagePointer + 20);
|
const HandleType process = mem.read32(messagePointer + 20);
|
||||||
|
|
||||||
log("LDR_RO::LoadCRR (buffer = %08X, size = %08X, process = %X)\n", crrPointer, size, process);
|
log("LDR_RO::LoadCRR (buffer = %08X, size = %08X, process = %X)\n", crrPointer, size, process);
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x2, 1, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0x2, 1, 0));
|
||||||
|
@ -1304,9 +1303,11 @@ void LDRService::loadCRO(u32 messagePointer, bool isNew) {
|
||||||
const u32 bssSize = mem.read32(messagePointer + 32);
|
const u32 bssSize = mem.read32(messagePointer + 32);
|
||||||
const bool autoLink = mem.read32(messagePointer + 36) != 0;
|
const bool autoLink = mem.read32(messagePointer + 36) != 0;
|
||||||
const u32 fixLevel = mem.read32(messagePointer + 40);
|
const u32 fixLevel = mem.read32(messagePointer + 40);
|
||||||
const Handle process = mem.read32(messagePointer + 52);
|
const HandleType process = mem.read32(messagePointer + 52);
|
||||||
|
|
||||||
log("LDR_RO::LoadCRO (isNew = %d, buffer = %08X, vaddr = %08X, size = %08X, .data vaddr = %08X, .data size = %08X, .bss vaddr = %08X, .bss size = %08X, auto link = %d, fix level = %X, process = %X)\n", isNew, croPointer, mapVaddr, size, dataVaddr, dataSize, bssVaddr, bssSize, autoLink, fixLevel, process);
|
log("LDR_RO::LoadCRO (isNew = %d, buffer = %08X, vaddr = %08X, size = %08X, .data vaddr = %08X, .data size = %08X, .bss vaddr = %08X, .bss size "
|
||||||
|
"= %08X, auto link = %d, fix level = %X, process = %X)\n",
|
||||||
|
isNew, croPointer, mapVaddr, size, dataVaddr, dataSize, bssVaddr, bssSize, autoLink, fixLevel, process);
|
||||||
|
|
||||||
// Sanity checks
|
// Sanity checks
|
||||||
if (size < CRO_HEADER_SIZE) {
|
if (size < CRO_HEADER_SIZE) {
|
||||||
|
@ -1362,7 +1363,7 @@ void LDRService::loadCRO(u32 messagePointer, bool isNew) {
|
||||||
void LDRService::unloadCRO(u32 messagePointer) {
|
void LDRService::unloadCRO(u32 messagePointer) {
|
||||||
const u32 mapVaddr = mem.read32(messagePointer + 4);
|
const u32 mapVaddr = mem.read32(messagePointer + 4);
|
||||||
const u32 croPointer = mem.read32(messagePointer + 12);
|
const u32 croPointer = mem.read32(messagePointer + 12);
|
||||||
const Handle process = mem.read32(messagePointer + 20);
|
const HandleType process = mem.read32(messagePointer + 20);
|
||||||
|
|
||||||
log("LDR_RO::UnloadCRO (vaddr = %08X, buffer = %08X, process = %X)\n", mapVaddr, croPointer, process);
|
log("LDR_RO::UnloadCRO (vaddr = %08X, buffer = %08X, process = %X)\n", mapVaddr, croPointer, process);
|
||||||
|
|
||||||
|
@ -1392,4 +1393,4 @@ void LDRService::unloadCRO(u32 messagePointer) {
|
||||||
|
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x5, 1, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0x5, 1, 0));
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
ServiceManager::ServiceManager(std::span<u32, 16> regs, Memory& mem, GPU& gpu, u32& currentPID, Kernel& kernel, const EmulatorConfig& config)
|
ServiceManager::ServiceManager(std::span<u32, 16> regs, Memory& mem, GPU& gpu, u32& currentPID, Kernel& kernel, const EmulatorConfig& config)
|
||||||
: regs(regs), mem(mem), kernel(kernel), ac(mem), am(mem), boss(mem), act(mem), apt(mem, kernel), cam(mem, kernel), cecd(mem, kernel), cfg(mem),
|
: regs(regs), mem(mem), kernel(kernel), ac(mem), am(mem), boss(mem), act(mem), apt(mem, kernel), cam(mem, kernel), cecd(mem, kernel), cfg(mem),
|
||||||
csnd(mem, kernel), dlp_srvr(mem), dsp(mem, kernel), hid(mem, kernel), http(mem), ir_user(mem, kernel), frd(mem), fs(mem, kernel, config),
|
csnd(mem, kernel), dlp_srvr(mem), dsp(mem, kernel), hid(mem, kernel), http(mem), ir_user(mem, kernel), frd(mem), fs(mem, kernel, config),
|
||||||
gsp_gpu(mem, gpu, kernel, currentPID), gsp_lcd(mem), ldr(mem, kernel), mcu_hwc(mem, config), mic(mem, kernel), nfc(mem, kernel), nim(mem), ndm(mem),
|
gsp_gpu(mem, gpu, kernel, currentPID), gsp_lcd(mem), ldr(mem, kernel), mcu_hwc(mem, config), mic(mem, kernel), nfc(mem, kernel), nim(mem),
|
||||||
news_u(mem), nwm_uds(mem, kernel), ptm(mem, config), soc(mem), ssl(mem), y2r(mem, kernel) {}
|
ndm(mem), news_u(mem), nwm_uds(mem, kernel), ptm(mem, config), soc(mem), ssl(mem), y2r(mem, kernel) {}
|
||||||
|
|
||||||
static constexpr int MAX_NOTIFICATION_COUNT = 16;
|
static constexpr int MAX_NOTIFICATION_COUNT = 16;
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ namespace Commands {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle an IPC message issued using the SendSyncRequest SVC
|
// HandleType an IPC message issued using the SendSyncRequest SVC
|
||||||
// The parameters are stored in thread-local storage in this format: https://www.3dbrew.org/wiki/IPC#Message_Structure
|
// The parameters are stored in thread-local storage in this format: https://www.3dbrew.org/wiki/IPC#Message_Structure
|
||||||
// messagePointer: The base pointer for the IPC message
|
// messagePointer: The base pointer for the IPC message
|
||||||
void ServiceManager::handleSyncRequest(u32 messagePointer) {
|
void ServiceManager::handleSyncRequest(u32 messagePointer) {
|
||||||
|
@ -93,7 +93,7 @@ void ServiceManager::registerClient(u32 messagePointer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static std::map<std::string, Handle> serviceMap = {
|
static std::map<std::string, HandleType> serviceMap = {
|
||||||
{ "ac:u", KernelHandles::AC },
|
{ "ac:u", KernelHandles::AC },
|
||||||
{ "act:a", KernelHandles::ACT },
|
{ "act:a", KernelHandles::ACT },
|
||||||
{ "act:u", KernelHandles::ACT },
|
{ "act:u", KernelHandles::ACT },
|
||||||
|
@ -165,9 +165,9 @@ void ServiceManager::enableNotification(u32 messagePointer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x2, 1, 2));
|
mem.write32(messagePointer, IPC::responseHeader(0x2, 1, 2));
|
||||||
mem.write32(messagePointer + 4, Result::Success); // Result code
|
mem.write32(messagePointer + 4, Result::Success); // Result code
|
||||||
mem.write32(messagePointer + 8, 0); // Translation descriptor
|
mem.write32(messagePointer + 8, 0); // Translation descriptor
|
||||||
// Handle to semaphore signaled on process notification
|
// HandleType to semaphore signaled on process notification
|
||||||
mem.write32(messagePointer + 12, notificationSemaphore.value());
|
mem.write32(messagePointer + 12, notificationSemaphore.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,8 +175,8 @@ void ServiceManager::receiveNotification(u32 messagePointer) {
|
||||||
log("srv::ReceiveNotification() (STUBBED)\n");
|
log("srv::ReceiveNotification() (STUBBED)\n");
|
||||||
|
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0xB, 2, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0xB, 2, 0));
|
||||||
mem.write32(messagePointer + 4, Result::Success); // Result code
|
mem.write32(messagePointer + 4, Result::Success); // Result code
|
||||||
mem.write32(messagePointer + 8, 0); // Notification ID
|
mem.write32(messagePointer + 8, 0); // Notification ID
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServiceManager::subscribe(u32 messagePointer) {
|
void ServiceManager::subscribe(u32 messagePointer) {
|
||||||
|
@ -195,7 +195,7 @@ void ServiceManager::unsubscribe(u32 messagePointer) {
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServiceManager::sendCommandToService(u32 messagePointer, Handle handle) {
|
void ServiceManager::sendCommandToService(u32 messagePointer, HandleType handle) {
|
||||||
switch (handle) {
|
switch (handle) {
|
||||||
// Breaking alphabetical order a bit to place the ones I think are most common at the top
|
// Breaking alphabetical order a bit to place the ones I think are most common at the top
|
||||||
case KernelHandles::GPU: [[likely]] gsp_gpu.handleSyncRequest(messagePointer); break;
|
case KernelHandles::GPU: [[likely]] gsp_gpu.handleSyncRequest(messagePointer); break;
|
||||||
|
@ -237,4 +237,4 @@ void ServiceManager::sendCommandToService(u32 messagePointer, Handle handle) {
|
||||||
case KernelHandles::Y2R: y2r.handleSyncRequest(messagePointer); break;
|
case KernelHandles::Y2R: y2r.handleSyncRequest(messagePointer); break;
|
||||||
default: Helpers::panic("Sent IPC message to unknown service %08X\n Command: %08X", handle, mem.read32(messagePointer));
|
default: Helpers::panic("Sent IPC message to unknown service %08X\n Command: %08X", handle, mem.read32(messagePointer));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ void SOCService::handleSyncRequest(u32 messagePointer) {
|
||||||
|
|
||||||
void SOCService::initializeSockets(u32 messagePointer) {
|
void SOCService::initializeSockets(u32 messagePointer) {
|
||||||
const u32 memoryBlockSize = mem.read32(messagePointer + 4);
|
const u32 memoryBlockSize = mem.read32(messagePointer + 4);
|
||||||
const Handle sharedMemHandle = mem.read32(messagePointer + 20);
|
const HandleType sharedMemHandle = mem.read32(messagePointer + 20);
|
||||||
log("SOC::InitializeSockets (memory block size = %08X, shared mem handle = %08X)\n", memoryBlockSize, sharedMemHandle);
|
log("SOC::InitializeSockets (memory block size = %08X, shared mem handle = %08X)\n", memoryBlockSize, sharedMemHandle);
|
||||||
|
|
||||||
// TODO: Does double initialization return an error code?
|
// TODO: Does double initialization return an error code?
|
||||||
|
@ -30,4 +30,4 @@ void SOCService::initializeSockets(u32 messagePointer) {
|
||||||
|
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x01, 1, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0x01, 1, 0));
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
}
|
}
|
||||||
|
|
16
src/host_shaders/metal_display.metal
Normal file
16
src/host_shaders/metal_display.metal
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
struct VertexOut {
|
||||||
|
float4 position [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
vertex VertexOut vertexMain(uint vid [[vertex_id]]) {
|
||||||
|
VertexOut out;
|
||||||
|
out.uv = float2((vid << 1) & 2, vid & 2);
|
||||||
|
out.position = float4(out.uv * 2.0f + -1.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment float4 fragmentMain(VertexOut in [[stage_in]], texture2d<float> tex [[texture(0)]], sampler samplr [[sampler(0)]]) {
|
||||||
|
return tex.sample(samplr, in.uv);
|
||||||
|
}
|
|
@ -11,7 +11,8 @@
|
||||||
#include "input_mappings.hpp"
|
#include "input_mappings.hpp"
|
||||||
#include "services/dsp.hpp"
|
#include "services/dsp.hpp"
|
||||||
|
|
||||||
MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent), keyboardMappings(InputMappings::defaultKeyboardMappings()), screen(this) {
|
MainWindow::MainWindow(QApplication* app, QWidget* parent)
|
||||||
|
: QMainWindow(parent), keyboardMappings(InputMappings::defaultKeyboardMappings()), screen(this) {
|
||||||
setWindowTitle("Alber");
|
setWindowTitle("Alber");
|
||||||
// Enable drop events for loading ROMs
|
// Enable drop events for loading ROMs
|
||||||
setAcceptDrops(true);
|
setAcceptDrops(true);
|
||||||
|
@ -90,6 +91,7 @@ MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent)
|
||||||
const RendererType rendererType = emu->getConfig().rendererType;
|
const RendererType rendererType = emu->getConfig().rendererType;
|
||||||
usingGL = (rendererType == RendererType::OpenGL || rendererType == RendererType::Software || rendererType == RendererType::Null);
|
usingGL = (rendererType == RendererType::OpenGL || rendererType == RendererType::Software || rendererType == RendererType::Null);
|
||||||
usingVk = (rendererType == RendererType::Vulkan);
|
usingVk = (rendererType == RendererType::Vulkan);
|
||||||
|
usingMtl = (rendererType == RendererType::Metal);
|
||||||
|
|
||||||
if (usingGL) {
|
if (usingGL) {
|
||||||
// Make GL context current for this thread, enable VSync
|
// Make GL context current for this thread, enable VSync
|
||||||
|
@ -100,6 +102,8 @@ MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent)
|
||||||
emu->initGraphicsContext(glContext);
|
emu->initGraphicsContext(glContext);
|
||||||
} else if (usingVk) {
|
} else if (usingVk) {
|
||||||
Helpers::panic("Vulkan on Qt is currently WIP, try the SDL frontend instead!");
|
Helpers::panic("Vulkan on Qt is currently WIP, try the SDL frontend instead!");
|
||||||
|
} else if (usingMtl) {
|
||||||
|
Helpers::panic("Metal on Qt is currently WIP, try the SDL frontend instead!");
|
||||||
} else {
|
} else {
|
||||||
Helpers::panic("Unsupported graphics backend for Qt frontend!");
|
Helpers::panic("Unsupported graphics backend for Qt frontend!");
|
||||||
}
|
}
|
||||||
|
@ -264,8 +268,7 @@ void MainWindow::dumpDspFirmware() {
|
||||||
case DSPService::ComponentDumpResult::Success: break;
|
case DSPService::ComponentDumpResult::Success: break;
|
||||||
case DSPService::ComponentDumpResult::NotLoaded: {
|
case DSPService::ComponentDumpResult::NotLoaded: {
|
||||||
QMessageBox messageBox(
|
QMessageBox messageBox(
|
||||||
QMessageBox::Icon::Warning, tr("No DSP firmware loaded"),
|
QMessageBox::Icon::Warning, tr("No DSP firmware loaded"), tr("The currently loaded app has not uploaded a firmware to the DSP")
|
||||||
tr("The currently loaded app has not uploaded a firmware to the DSP")
|
|
||||||
);
|
);
|
||||||
|
|
||||||
QAbstractButton* button = messageBox.addButton(tr("OK"), QMessageBox::ButtonRole::YesRole);
|
QAbstractButton* button = messageBox.addButton(tr("OK"), QMessageBox::ButtonRole::YesRole);
|
||||||
|
@ -559,4 +562,4 @@ void MainWindow::pollControllers() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,16 @@ FrontendSDL::FrontendSDL() : keyboardMappings(InputMappings::defaultKeyboardMapp
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef PANDA3DS_ENABLE_METAL
|
||||||
|
if (config.rendererType == RendererType::Metal) {
|
||||||
|
window = SDL_CreateWindow("Alber", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 400, 480, SDL_WINDOW_METAL);
|
||||||
|
|
||||||
|
if (window == nullptr) {
|
||||||
|
Helpers::warn("Window creation failed: %s", SDL_GetError());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
emu.initGraphicsContext(window);
|
emu.initGraphicsContext(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,7 +250,7 @@ void FrontendSDL::run() {
|
||||||
case SDL_MOUSEMOTION: {
|
case SDL_MOUSEMOTION: {
|
||||||
if (emu.romType == ROMType::None) break;
|
if (emu.romType == ROMType::None) break;
|
||||||
|
|
||||||
// Handle "dragging" across the touchscreen
|
// HandleType "dragging" across the touchscreen
|
||||||
if (hid.isTouchScreenPressed()) {
|
if (hid.isTouchScreenPressed()) {
|
||||||
const s32 x = event.motion.x;
|
const s32 x = event.motion.x;
|
||||||
const s32 y = event.motion.y;
|
const s32 y = event.motion.y;
|
||||||
|
|
|
@ -18,7 +18,7 @@ std::optional<RendererType> Renderer::typeFromString(std::string inString) {
|
||||||
{"gl", RendererType::OpenGL}, {"ogl", RendererType::OpenGL}, {"opengl", RendererType::OpenGL},
|
{"gl", RendererType::OpenGL}, {"ogl", RendererType::OpenGL}, {"opengl", RendererType::OpenGL},
|
||||||
{"vk", RendererType::Vulkan}, {"vulkan", RendererType::Vulkan}, {"vulcan", RendererType::Vulkan},
|
{"vk", RendererType::Vulkan}, {"vulkan", RendererType::Vulkan}, {"vulcan", RendererType::Vulkan},
|
||||||
{"sw", RendererType::Software}, {"soft", RendererType::Software}, {"software", RendererType::Software},
|
{"sw", RendererType::Software}, {"soft", RendererType::Software}, {"software", RendererType::Software},
|
||||||
{"softrast", RendererType::Software},
|
{"softrast", RendererType::Software}, {"mtl", RendererType::Metal}, {"metal", RendererType::Metal}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (auto search = map.find(inString); search != map.end()) {
|
if (auto search = map.find(inString); search != map.end()) {
|
||||||
|
@ -34,6 +34,7 @@ const char* Renderer::typeToString(RendererType rendererType) {
|
||||||
case RendererType::OpenGL: return "opengl";
|
case RendererType::OpenGL: return "opengl";
|
||||||
case RendererType::Vulkan: return "vulkan";
|
case RendererType::Vulkan: return "vulkan";
|
||||||
case RendererType::Software: return "software";
|
case RendererType::Software: return "software";
|
||||||
|
case RendererType::Metal: return "metal";
|
||||||
default: return "Invalid";
|
default: return "Invalid";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
47
third_party/metal-cpp/Foundation/Foundation.hpp
vendored
Normal file
47
third_party/metal-cpp/Foundation/Foundation.hpp
vendored
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Foundation/Foundation.hpp
|
||||||
|
//
|
||||||
|
// Copyright 2020-2023 Apple Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "NSArray.hpp"
|
||||||
|
#include "NSAutoreleasePool.hpp"
|
||||||
|
#include "NSBundle.hpp"
|
||||||
|
#include "NSData.hpp"
|
||||||
|
#include "NSDate.hpp"
|
||||||
|
#include "NSDefines.hpp"
|
||||||
|
#include "NSDictionary.hpp"
|
||||||
|
#include "NSEnumerator.hpp"
|
||||||
|
#include "NSError.hpp"
|
||||||
|
#include "NSLock.hpp"
|
||||||
|
#include "NSNotification.hpp"
|
||||||
|
#include "NSNumber.hpp"
|
||||||
|
#include "NSObject.hpp"
|
||||||
|
#include "NSPrivate.hpp"
|
||||||
|
#include "NSProcessInfo.hpp"
|
||||||
|
#include "NSRange.hpp"
|
||||||
|
#include "NSSet.hpp"
|
||||||
|
#include "NSSharedPtr.hpp"
|
||||||
|
#include "NSString.hpp"
|
||||||
|
#include "NSTypes.hpp"
|
||||||
|
#include "NSURL.hpp"
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
115
third_party/metal-cpp/Foundation/NSArray.hpp
vendored
Normal file
115
third_party/metal-cpp/Foundation/NSArray.hpp
vendored
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Foundation/NSArray.hpp
|
||||||
|
//
|
||||||
|
// Copyright 2020-2023 Apple Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "NSObject.hpp"
|
||||||
|
#include "NSTypes.hpp"
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace NS
|
||||||
|
{
|
||||||
|
class Array : public Copying<Array>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static Array* array();
|
||||||
|
static Array* array(const Object* pObject);
|
||||||
|
static Array* array(const Object* const* pObjects, UInteger count);
|
||||||
|
|
||||||
|
static Array* alloc();
|
||||||
|
|
||||||
|
Array* init();
|
||||||
|
Array* init(const Object* const* pObjects, UInteger count);
|
||||||
|
Array* init(const class Coder* pCoder);
|
||||||
|
|
||||||
|
template <class _Object = Object>
|
||||||
|
_Object* object(UInteger index) const;
|
||||||
|
UInteger count() const;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Array* NS::Array::array()
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Array*>(_NS_PRIVATE_CLS(NSArray), _NS_PRIVATE_SEL(array));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Array* NS::Array::array(const Object* pObject)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Array*>(_NS_PRIVATE_CLS(NSArray), _NS_PRIVATE_SEL(arrayWithObject_), pObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Array* NS::Array::array(const Object* const* pObjects, UInteger count)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Array*>(_NS_PRIVATE_CLS(NSArray), _NS_PRIVATE_SEL(arrayWithObjects_count_), pObjects, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Array* NS::Array::alloc()
|
||||||
|
{
|
||||||
|
return NS::Object::alloc<Array>(_NS_PRIVATE_CLS(NSArray));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Array* NS::Array::init()
|
||||||
|
{
|
||||||
|
return NS::Object::init<Array>();
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Array* NS::Array::init(const Object* const* pObjects, UInteger count)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Array*>(this, _NS_PRIVATE_SEL(initWithObjects_count_), pObjects, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Array* NS::Array::init(const class Coder* pCoder)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Array*>(this, _NS_PRIVATE_SEL(initWithCoder_), pCoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::UInteger NS::Array::count() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<UInteger>(this, _NS_PRIVATE_SEL(count));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template <class _Object>
|
||||||
|
_NS_INLINE _Object* NS::Array::object(UInteger index) const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<_Object*>(this, _NS_PRIVATE_SEL(objectAtIndex_), index);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
83
third_party/metal-cpp/Foundation/NSAutoreleasePool.hpp
vendored
Normal file
83
third_party/metal-cpp/Foundation/NSAutoreleasePool.hpp
vendored
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Foundation/NSAutoreleasePool.hpp
|
||||||
|
//
|
||||||
|
// Copyright 2020-2023 Apple Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "NSDefines.hpp"
|
||||||
|
#include "NSObject.hpp"
|
||||||
|
#include "NSPrivate.hpp"
|
||||||
|
#include "NSTypes.hpp"
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace NS
|
||||||
|
{
|
||||||
|
class AutoreleasePool : public Object
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static AutoreleasePool* alloc();
|
||||||
|
AutoreleasePool* init();
|
||||||
|
|
||||||
|
void drain();
|
||||||
|
|
||||||
|
void addObject(Object* pObject);
|
||||||
|
|
||||||
|
static void showPools();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::AutoreleasePool* NS::AutoreleasePool::alloc()
|
||||||
|
{
|
||||||
|
return NS::Object::alloc<AutoreleasePool>(_NS_PRIVATE_CLS(NSAutoreleasePool));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::AutoreleasePool* NS::AutoreleasePool::init()
|
||||||
|
{
|
||||||
|
return NS::Object::init<AutoreleasePool>();
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE void NS::AutoreleasePool::drain()
|
||||||
|
{
|
||||||
|
Object::sendMessage<void>(this, _NS_PRIVATE_SEL(drain));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE void NS::AutoreleasePool::addObject(Object* pObject)
|
||||||
|
{
|
||||||
|
Object::sendMessage<void>(this, _NS_PRIVATE_SEL(addObject_), pObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE void NS::AutoreleasePool::showPools()
|
||||||
|
{
|
||||||
|
Object::sendMessage<void>(_NS_PRIVATE_CLS(NSAutoreleasePool), _NS_PRIVATE_SEL(showPools));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
374
third_party/metal-cpp/Foundation/NSBundle.hpp
vendored
Normal file
374
third_party/metal-cpp/Foundation/NSBundle.hpp
vendored
Normal file
|
@ -0,0 +1,374 @@
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Foundation/NSBundle.hpp
|
||||||
|
//
|
||||||
|
// Copyright 2020-2023 Apple Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "NSDefines.hpp"
|
||||||
|
#include "NSNotification.hpp"
|
||||||
|
#include "NSObject.hpp"
|
||||||
|
#include "NSTypes.hpp"
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace NS
|
||||||
|
{
|
||||||
|
_NS_CONST(NotificationName, BundleDidLoadNotification);
|
||||||
|
_NS_CONST(NotificationName, BundleResourceRequestLowDiskSpaceNotification);
|
||||||
|
|
||||||
|
class String* LocalizedString(const String* pKey, const String*);
|
||||||
|
class String* LocalizedStringFromTable(const String* pKey, const String* pTbl, const String*);
|
||||||
|
class String* LocalizedStringFromTableInBundle(const String* pKey, const String* pTbl, const class Bundle* pBdle, const String*);
|
||||||
|
class String* LocalizedStringWithDefaultValue(const String* pKey, const String* pTbl, const class Bundle* pBdle, const String* pVal, const String*);
|
||||||
|
|
||||||
|
class Bundle : public Referencing<Bundle>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static Bundle* mainBundle();
|
||||||
|
|
||||||
|
static Bundle* bundle(const class String* pPath);
|
||||||
|
static Bundle* bundle(const class URL* pURL);
|
||||||
|
|
||||||
|
static Bundle* alloc();
|
||||||
|
|
||||||
|
Bundle* init(const class String* pPath);
|
||||||
|
Bundle* init(const class URL* pURL);
|
||||||
|
|
||||||
|
class Array* allBundles() const;
|
||||||
|
class Array* allFrameworks() const;
|
||||||
|
|
||||||
|
bool load();
|
||||||
|
bool unload();
|
||||||
|
|
||||||
|
bool isLoaded() const;
|
||||||
|
|
||||||
|
bool preflightAndReturnError(class Error** pError) const;
|
||||||
|
bool loadAndReturnError(class Error** pError);
|
||||||
|
|
||||||
|
class URL* bundleURL() const;
|
||||||
|
class URL* resourceURL() const;
|
||||||
|
class URL* executableURL() const;
|
||||||
|
class URL* URLForAuxiliaryExecutable(const class String* pExecutableName) const;
|
||||||
|
|
||||||
|
class URL* privateFrameworksURL() const;
|
||||||
|
class URL* sharedFrameworksURL() const;
|
||||||
|
class URL* sharedSupportURL() const;
|
||||||
|
class URL* builtInPlugInsURL() const;
|
||||||
|
class URL* appStoreReceiptURL() const;
|
||||||
|
|
||||||
|
class String* bundlePath() const;
|
||||||
|
class String* resourcePath() const;
|
||||||
|
class String* executablePath() const;
|
||||||
|
class String* pathForAuxiliaryExecutable(const class String* pExecutableName) const;
|
||||||
|
|
||||||
|
class String* privateFrameworksPath() const;
|
||||||
|
class String* sharedFrameworksPath() const;
|
||||||
|
class String* sharedSupportPath() const;
|
||||||
|
class String* builtInPlugInsPath() const;
|
||||||
|
|
||||||
|
class String* bundleIdentifier() const;
|
||||||
|
class Dictionary* infoDictionary() const;
|
||||||
|
class Dictionary* localizedInfoDictionary() const;
|
||||||
|
class Object* objectForInfoDictionaryKey(const class String* pKey);
|
||||||
|
|
||||||
|
class String* localizedString(const class String* pKey, const class String* pValue = nullptr, const class String* pTableName = nullptr) const;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_PRIVATE_DEF_CONST(NS::NotificationName, BundleDidLoadNotification);
|
||||||
|
_NS_PRIVATE_DEF_CONST(NS::NotificationName, BundleResourceRequestLowDiskSpaceNotification);
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::LocalizedString(const String* pKey, const String*)
|
||||||
|
{
|
||||||
|
return Bundle::mainBundle()->localizedString(pKey, nullptr, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::LocalizedStringFromTable(const String* pKey, const String* pTbl, const String*)
|
||||||
|
{
|
||||||
|
return Bundle::mainBundle()->localizedString(pKey, nullptr, pTbl);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::LocalizedStringFromTableInBundle(const String* pKey, const String* pTbl, const Bundle* pBdl, const String*)
|
||||||
|
{
|
||||||
|
return pBdl->localizedString(pKey, nullptr, pTbl);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::LocalizedStringWithDefaultValue(const String* pKey, const String* pTbl, const Bundle* pBdl, const String* pVal, const String*)
|
||||||
|
{
|
||||||
|
return pBdl->localizedString(pKey, pVal, pTbl);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Bundle* NS::Bundle::mainBundle()
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Bundle*>(_NS_PRIVATE_CLS(NSBundle), _NS_PRIVATE_SEL(mainBundle));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Bundle* NS::Bundle::bundle(const class String* pPath)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Bundle*>(_NS_PRIVATE_CLS(NSBundle), _NS_PRIVATE_SEL(bundleWithPath_), pPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Bundle* NS::Bundle::bundle(const class URL* pURL)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Bundle*>(_NS_PRIVATE_CLS(NSBundle), _NS_PRIVATE_SEL(bundleWithURL_), pURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Bundle* NS::Bundle::alloc()
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Bundle*>(_NS_PRIVATE_CLS(NSBundle), _NS_PRIVATE_SEL(alloc));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Bundle* NS::Bundle::init(const String* pPath)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Bundle*>(this, _NS_PRIVATE_SEL(initWithPath_), pPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Bundle* NS::Bundle::init(const URL* pURL)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Bundle*>(this, _NS_PRIVATE_SEL(initWithURL_), pURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Array* NS::Bundle::allBundles() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Array*>(this, _NS_PRIVATE_SEL(allBundles));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Array* NS::Bundle::allFrameworks() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Array*>(this, _NS_PRIVATE_SEL(allFrameworks));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE bool NS::Bundle::load()
|
||||||
|
{
|
||||||
|
return Object::sendMessage<bool>(this, _NS_PRIVATE_SEL(load));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE bool NS::Bundle::unload()
|
||||||
|
{
|
||||||
|
return Object::sendMessage<bool>(this, _NS_PRIVATE_SEL(unload));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE bool NS::Bundle::isLoaded() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<bool>(this, _NS_PRIVATE_SEL(isLoaded));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE bool NS::Bundle::preflightAndReturnError(Error** pError) const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<bool>(this, _NS_PRIVATE_SEL(preflightAndReturnError_), pError);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE bool NS::Bundle::loadAndReturnError(Error** pError)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<bool>(this, _NS_PRIVATE_SEL(loadAndReturnError_), pError);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::URL* NS::Bundle::bundleURL() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<URL*>(this, _NS_PRIVATE_SEL(bundleURL));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::URL* NS::Bundle::resourceURL() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<URL*>(this, _NS_PRIVATE_SEL(resourceURL));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::URL* NS::Bundle::executableURL() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<URL*>(this, _NS_PRIVATE_SEL(executableURL));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::URL* NS::Bundle::URLForAuxiliaryExecutable(const String* pExecutableName) const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<URL*>(this, _NS_PRIVATE_SEL(URLForAuxiliaryExecutable_), pExecutableName);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::URL* NS::Bundle::privateFrameworksURL() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<URL*>(this, _NS_PRIVATE_SEL(privateFrameworksURL));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::URL* NS::Bundle::sharedFrameworksURL() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<URL*>(this, _NS_PRIVATE_SEL(sharedFrameworksURL));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::URL* NS::Bundle::sharedSupportURL() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<URL*>(this, _NS_PRIVATE_SEL(sharedSupportURL));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::URL* NS::Bundle::builtInPlugInsURL() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<URL*>(this, _NS_PRIVATE_SEL(builtInPlugInsURL));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::URL* NS::Bundle::appStoreReceiptURL() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<URL*>(this, _NS_PRIVATE_SEL(appStoreReceiptURL));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::Bundle::bundlePath() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<String*>(this, _NS_PRIVATE_SEL(bundlePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::Bundle::resourcePath() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<String*>(this, _NS_PRIVATE_SEL(resourcePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::Bundle::executablePath() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<String*>(this, _NS_PRIVATE_SEL(executablePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::Bundle::pathForAuxiliaryExecutable(const String* pExecutableName) const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<String*>(this, _NS_PRIVATE_SEL(pathForAuxiliaryExecutable_), pExecutableName);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::Bundle::privateFrameworksPath() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<String*>(this, _NS_PRIVATE_SEL(privateFrameworksPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::Bundle::sharedFrameworksPath() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<String*>(this, _NS_PRIVATE_SEL(sharedFrameworksPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::Bundle::sharedSupportPath() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<String*>(this, _NS_PRIVATE_SEL(sharedSupportPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::Bundle::builtInPlugInsPath() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<String*>(this, _NS_PRIVATE_SEL(builtInPlugInsPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::Bundle::bundleIdentifier() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<String*>(this, _NS_PRIVATE_SEL(bundleIdentifier));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Dictionary* NS::Bundle::infoDictionary() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Dictionary*>(this, _NS_PRIVATE_SEL(infoDictionary));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Dictionary* NS::Bundle::localizedInfoDictionary() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Dictionary*>(this, _NS_PRIVATE_SEL(localizedInfoDictionary));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Object* NS::Bundle::objectForInfoDictionaryKey(const String* pKey)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Object*>(this, _NS_PRIVATE_SEL(objectForInfoDictionaryKey_), pKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::Bundle::localizedString(const String* pKey, const String* pValue /* = nullptr */, const String* pTableName /* = nullptr */) const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<String*>(this, _NS_PRIVATE_SEL(localizedStringForKey_value_table_), pKey, pValue, pTableName);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
54
third_party/metal-cpp/Foundation/NSData.hpp
vendored
Normal file
54
third_party/metal-cpp/Foundation/NSData.hpp
vendored
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Foundation/NSData.hpp
|
||||||
|
//
|
||||||
|
// Copyright 2020-2023 Apple Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "NSObject.hpp"
|
||||||
|
#include "NSTypes.hpp"
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace NS
|
||||||
|
{
|
||||||
|
class Data : public Copying<Data>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void* mutableBytes() const;
|
||||||
|
UInteger length() const;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE void* NS::Data::mutableBytes() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<void*>(this, _NS_PRIVATE_SEL(mutableBytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::UInteger NS::Data::length() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<UInteger>(this, _NS_PRIVATE_SEL(length));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
53
third_party/metal-cpp/Foundation/NSDate.hpp
vendored
Normal file
53
third_party/metal-cpp/Foundation/NSDate.hpp
vendored
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Foundation/NSDate.hpp
|
||||||
|
//
|
||||||
|
// Copyright 2020-2023 Apple Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "NSDefines.hpp"
|
||||||
|
#include "NSObject.hpp"
|
||||||
|
#include "NSPrivate.hpp"
|
||||||
|
#include "NSTypes.hpp"
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace NS
|
||||||
|
{
|
||||||
|
|
||||||
|
using TimeInterval = double;
|
||||||
|
|
||||||
|
class Date : public Copying<Date>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static Date* dateWithTimeIntervalSinceNow(TimeInterval secs);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // NS
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Date* NS::Date::dateWithTimeIntervalSinceNow(NS::TimeInterval secs)
|
||||||
|
{
|
||||||
|
return NS::Object::sendMessage<NS::Date*>(_NS_PRIVATE_CLS(NSDate), _NS_PRIVATE_SEL(dateWithTimeIntervalSinceNow_), secs);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
45
third_party/metal-cpp/Foundation/NSDefines.hpp
vendored
Normal file
45
third_party/metal-cpp/Foundation/NSDefines.hpp
vendored
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Foundation/NSDefines.hpp
|
||||||
|
//
|
||||||
|
// Copyright 2020-2023 Apple Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define _NS_WEAK_IMPORT __attribute__((weak_import))
|
||||||
|
#ifdef METALCPP_SYMBOL_VISIBILITY_HIDDEN
|
||||||
|
#define _NS_EXPORT __attribute__((visibility("hidden")))
|
||||||
|
#else
|
||||||
|
#define _NS_EXPORT __attribute__((visibility("default")))
|
||||||
|
#endif // METALCPP_SYMBOL_VISIBILITY_HIDDEN
|
||||||
|
#define _NS_EXTERN extern "C" _NS_EXPORT
|
||||||
|
#define _NS_INLINE inline __attribute__((always_inline))
|
||||||
|
#define _NS_PACKED __attribute__((packed))
|
||||||
|
|
||||||
|
#define _NS_CONST(type, name) _NS_EXTERN type const name
|
||||||
|
#define _NS_ENUM(type, name) enum name : type
|
||||||
|
#define _NS_OPTIONS(type, name) \
|
||||||
|
using name = type; \
|
||||||
|
enum : name
|
||||||
|
|
||||||
|
#define _NS_CAST_TO_UINT(value) static_cast<NS::UInteger>(value)
|
||||||
|
#define _NS_VALIDATE_SIZE(ns, name) static_assert(sizeof(ns::name) == sizeof(ns##name), "size mismatch " #ns "::" #name)
|
||||||
|
#define _NS_VALIDATE_ENUM(ns, name) static_assert(_NS_CAST_TO_UINT(ns::name) == _NS_CAST_TO_UINT(ns##name), "value mismatch " #ns "::" #name)
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
128
third_party/metal-cpp/Foundation/NSDictionary.hpp
vendored
Normal file
128
third_party/metal-cpp/Foundation/NSDictionary.hpp
vendored
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Foundation/NSDictionary.hpp
|
||||||
|
//
|
||||||
|
// Copyright 2020-2023 Apple Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "NSEnumerator.hpp"
|
||||||
|
#include "NSObject.hpp"
|
||||||
|
#include "NSTypes.hpp"
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace NS
|
||||||
|
{
|
||||||
|
class Dictionary : public NS::Copying<Dictionary>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static Dictionary* dictionary();
|
||||||
|
static Dictionary* dictionary(const Object* pObject, const Object* pKey);
|
||||||
|
static Dictionary* dictionary(const Object* const* pObjects, const Object* const* pKeys, UInteger count);
|
||||||
|
|
||||||
|
static Dictionary* alloc();
|
||||||
|
|
||||||
|
Dictionary* init();
|
||||||
|
Dictionary* init(const Object* const* pObjects, const Object* const* pKeys, UInteger count);
|
||||||
|
Dictionary* init(const class Coder* pCoder);
|
||||||
|
|
||||||
|
template <class _KeyType = Object>
|
||||||
|
Enumerator<_KeyType>* keyEnumerator() const;
|
||||||
|
|
||||||
|
template <class _Object = Object>
|
||||||
|
_Object* object(const Object* pKey) const;
|
||||||
|
UInteger count() const;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Dictionary* NS::Dictionary::dictionary()
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Dictionary*>(_NS_PRIVATE_CLS(NSDictionary), _NS_PRIVATE_SEL(dictionary));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Dictionary* NS::Dictionary::dictionary(const Object* pObject, const Object* pKey)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Dictionary*>(_NS_PRIVATE_CLS(NSDictionary), _NS_PRIVATE_SEL(dictionaryWithObject_forKey_), pObject, pKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Dictionary* NS::Dictionary::dictionary(const Object* const* pObjects, const Object* const* pKeys, UInteger count)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Dictionary*>(_NS_PRIVATE_CLS(NSDictionary), _NS_PRIVATE_SEL(dictionaryWithObjects_forKeys_count_),
|
||||||
|
pObjects, pKeys, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Dictionary* NS::Dictionary::alloc()
|
||||||
|
{
|
||||||
|
return NS::Object::alloc<Dictionary>(_NS_PRIVATE_CLS(NSDictionary));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Dictionary* NS::Dictionary::init()
|
||||||
|
{
|
||||||
|
return NS::Object::init<Dictionary>();
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Dictionary* NS::Dictionary::init(const Object* const* pObjects, const Object* const* pKeys, UInteger count)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Dictionary*>(this, _NS_PRIVATE_SEL(initWithObjects_forKeys_count_), pObjects, pKeys, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Dictionary* NS::Dictionary::init(const class Coder* pCoder)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Dictionary*>(this, _NS_PRIVATE_SEL(initWithCoder_), pCoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template <class _KeyType>
|
||||||
|
_NS_INLINE NS::Enumerator<_KeyType>* NS::Dictionary::keyEnumerator() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Enumerator<_KeyType>*>(this, _NS_PRIVATE_SEL(keyEnumerator));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template <class _Object>
|
||||||
|
_NS_INLINE _Object* NS::Dictionary::object(const Object* pKey) const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<_Object*>(this, _NS_PRIVATE_SEL(objectForKey_), pKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::UInteger NS::Dictionary::count() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<UInteger>(this, _NS_PRIVATE_SEL(count));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
78
third_party/metal-cpp/Foundation/NSEnumerator.hpp
vendored
Normal file
78
third_party/metal-cpp/Foundation/NSEnumerator.hpp
vendored
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Foundation/NSEnumerator.hpp
|
||||||
|
//
|
||||||
|
// Copyright 2020-2023 Apple Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "NSObject.hpp"
|
||||||
|
#include "NSTypes.hpp"
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace NS
|
||||||
|
{
|
||||||
|
struct FastEnumerationState
|
||||||
|
{
|
||||||
|
unsigned long state;
|
||||||
|
Object** itemsPtr;
|
||||||
|
unsigned long* mutationsPtr;
|
||||||
|
unsigned long extra[5];
|
||||||
|
} _NS_PACKED;
|
||||||
|
|
||||||
|
class FastEnumeration : public Referencing<FastEnumeration>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NS::UInteger countByEnumerating(FastEnumerationState* pState, Object** pBuffer, NS::UInteger len);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class _ObjectType>
|
||||||
|
class Enumerator : public Referencing<Enumerator<_ObjectType>, FastEnumeration>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
_ObjectType* nextObject();
|
||||||
|
class Array* allObjects();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::UInteger NS::FastEnumeration::countByEnumerating(FastEnumerationState* pState, Object** pBuffer, NS::UInteger len)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<UInteger>(this, _NS_PRIVATE_SEL(countByEnumeratingWithState_objects_count_), pState, pBuffer, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template <class _ObjectType>
|
||||||
|
_NS_INLINE _ObjectType* NS::Enumerator<_ObjectType>::nextObject()
|
||||||
|
{
|
||||||
|
return Object::sendMessage<_ObjectType*>(this, _NS_PRIVATE_SEL(nextObject));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template <class _ObjectType>
|
||||||
|
_NS_INLINE NS::Array* NS::Enumerator<_ObjectType>::allObjects()
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Array*>(this, _NS_PRIVATE_SEL(allObjects));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
173
third_party/metal-cpp/Foundation/NSError.hpp
vendored
Normal file
173
third_party/metal-cpp/Foundation/NSError.hpp
vendored
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Foundation/NSError.hpp
|
||||||
|
//
|
||||||
|
// Copyright 2020-2023 Apple Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "NSDefines.hpp"
|
||||||
|
#include "NSObject.hpp"
|
||||||
|
#include "NSPrivate.hpp"
|
||||||
|
#include "NSTypes.hpp"
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace NS
|
||||||
|
{
|
||||||
|
using ErrorDomain = class String*;
|
||||||
|
|
||||||
|
_NS_CONST(ErrorDomain, CocoaErrorDomain);
|
||||||
|
_NS_CONST(ErrorDomain, POSIXErrorDomain);
|
||||||
|
_NS_CONST(ErrorDomain, OSStatusErrorDomain);
|
||||||
|
_NS_CONST(ErrorDomain, MachErrorDomain);
|
||||||
|
|
||||||
|
using ErrorUserInfoKey = class String*;
|
||||||
|
|
||||||
|
_NS_CONST(ErrorUserInfoKey, UnderlyingErrorKey);
|
||||||
|
_NS_CONST(ErrorUserInfoKey, LocalizedDescriptionKey);
|
||||||
|
_NS_CONST(ErrorUserInfoKey, LocalizedFailureReasonErrorKey);
|
||||||
|
_NS_CONST(ErrorUserInfoKey, LocalizedRecoverySuggestionErrorKey);
|
||||||
|
_NS_CONST(ErrorUserInfoKey, LocalizedRecoveryOptionsErrorKey);
|
||||||
|
_NS_CONST(ErrorUserInfoKey, RecoveryAttempterErrorKey);
|
||||||
|
_NS_CONST(ErrorUserInfoKey, HelpAnchorErrorKey);
|
||||||
|
_NS_CONST(ErrorUserInfoKey, DebugDescriptionErrorKey);
|
||||||
|
_NS_CONST(ErrorUserInfoKey, LocalizedFailureErrorKey);
|
||||||
|
_NS_CONST(ErrorUserInfoKey, StringEncodingErrorKey);
|
||||||
|
_NS_CONST(ErrorUserInfoKey, URLErrorKey);
|
||||||
|
_NS_CONST(ErrorUserInfoKey, FilePathErrorKey);
|
||||||
|
|
||||||
|
class Error : public Copying<Error>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static Error* error(ErrorDomain domain, Integer code, class Dictionary* pDictionary);
|
||||||
|
|
||||||
|
static Error* alloc();
|
||||||
|
Error* init();
|
||||||
|
Error* init(ErrorDomain domain, Integer code, class Dictionary* pDictionary);
|
||||||
|
|
||||||
|
Integer code() const;
|
||||||
|
ErrorDomain domain() const;
|
||||||
|
class Dictionary* userInfo() const;
|
||||||
|
|
||||||
|
class String* localizedDescription() const;
|
||||||
|
class Array* localizedRecoveryOptions() const;
|
||||||
|
class String* localizedRecoverySuggestion() const;
|
||||||
|
class String* localizedFailureReason() const;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_PRIVATE_DEF_CONST(NS::ErrorDomain, CocoaErrorDomain);
|
||||||
|
_NS_PRIVATE_DEF_CONST(NS::ErrorDomain, POSIXErrorDomain);
|
||||||
|
_NS_PRIVATE_DEF_CONST(NS::ErrorDomain, OSStatusErrorDomain);
|
||||||
|
_NS_PRIVATE_DEF_CONST(NS::ErrorDomain, MachErrorDomain);
|
||||||
|
|
||||||
|
_NS_PRIVATE_DEF_CONST(NS::ErrorUserInfoKey, UnderlyingErrorKey);
|
||||||
|
_NS_PRIVATE_DEF_CONST(NS::ErrorUserInfoKey, LocalizedDescriptionKey);
|
||||||
|
_NS_PRIVATE_DEF_CONST(NS::ErrorUserInfoKey, LocalizedFailureReasonErrorKey);
|
||||||
|
_NS_PRIVATE_DEF_CONST(NS::ErrorUserInfoKey, LocalizedRecoverySuggestionErrorKey);
|
||||||
|
_NS_PRIVATE_DEF_CONST(NS::ErrorUserInfoKey, LocalizedRecoveryOptionsErrorKey);
|
||||||
|
_NS_PRIVATE_DEF_CONST(NS::ErrorUserInfoKey, RecoveryAttempterErrorKey);
|
||||||
|
_NS_PRIVATE_DEF_CONST(NS::ErrorUserInfoKey, HelpAnchorErrorKey);
|
||||||
|
_NS_PRIVATE_DEF_CONST(NS::ErrorUserInfoKey, DebugDescriptionErrorKey);
|
||||||
|
_NS_PRIVATE_DEF_CONST(NS::ErrorUserInfoKey, LocalizedFailureErrorKey);
|
||||||
|
_NS_PRIVATE_DEF_CONST(NS::ErrorUserInfoKey, StringEncodingErrorKey);
|
||||||
|
_NS_PRIVATE_DEF_CONST(NS::ErrorUserInfoKey, URLErrorKey);
|
||||||
|
_NS_PRIVATE_DEF_CONST(NS::ErrorUserInfoKey, FilePathErrorKey);
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Error* NS::Error::error(ErrorDomain domain, Integer code, class Dictionary* pDictionary)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Error*>(_NS_PRIVATE_CLS(NSError), _NS_PRIVATE_SEL(errorWithDomain_code_userInfo_), domain, code, pDictionary);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Error* NS::Error::alloc()
|
||||||
|
{
|
||||||
|
return Object::alloc<Error>(_NS_PRIVATE_CLS(NSError));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Error* NS::Error::init()
|
||||||
|
{
|
||||||
|
return Object::init<Error>();
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Error* NS::Error::init(ErrorDomain domain, Integer code, class Dictionary* pDictionary)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Error*>(this, _NS_PRIVATE_SEL(initWithDomain_code_userInfo_), domain, code, pDictionary);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Integer NS::Error::code() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Integer>(this, _NS_PRIVATE_SEL(code));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::ErrorDomain NS::Error::domain() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<ErrorDomain>(this, _NS_PRIVATE_SEL(domain));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Dictionary* NS::Error::userInfo() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Dictionary*>(this, _NS_PRIVATE_SEL(userInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::Error::localizedDescription() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<String*>(this, _NS_PRIVATE_SEL(localizedDescription));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Array* NS::Error::localizedRecoveryOptions() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Array*>(this, _NS_PRIVATE_SEL(localizedRecoveryOptions));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::Error::localizedRecoverySuggestion() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<String*>(this, _NS_PRIVATE_SEL(localizedRecoverySuggestion));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::Error::localizedFailureReason() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<String*>(this, _NS_PRIVATE_SEL(localizedFailureReason));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
118
third_party/metal-cpp/Foundation/NSLock.hpp
vendored
Normal file
118
third_party/metal-cpp/Foundation/NSLock.hpp
vendored
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Foundation/NSLock.hpp
|
||||||
|
//
|
||||||
|
// Copyright 2020-2023 Apple Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "NSDefines.hpp"
|
||||||
|
#include "NSObject.hpp"
|
||||||
|
#include "NSPrivate.hpp"
|
||||||
|
#include "NSTypes.hpp"
|
||||||
|
#include "NSDate.hpp"
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace NS
|
||||||
|
{
|
||||||
|
|
||||||
|
template <class _Class, class _Base = class Object>
|
||||||
|
class Locking : public _Base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void lock();
|
||||||
|
void unlock();
|
||||||
|
};
|
||||||
|
|
||||||
|
class Condition : public Locking<Condition>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static Condition* alloc();
|
||||||
|
|
||||||
|
Condition* init();
|
||||||
|
|
||||||
|
void wait();
|
||||||
|
bool waitUntilDate(Date* pLimit);
|
||||||
|
void signal();
|
||||||
|
void broadcast();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // NS
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<class _Class, class _Base /* = NS::Object */>
|
||||||
|
_NS_INLINE void NS::Locking<_Class, _Base>::lock()
|
||||||
|
{
|
||||||
|
NS::Object::sendMessage<void>(this, _NS_PRIVATE_SEL(lock));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<class _Class, class _Base /* = NS::Object */>
|
||||||
|
_NS_INLINE void NS::Locking<_Class, _Base>::unlock()
|
||||||
|
{
|
||||||
|
NS::Object::sendMessage<void>(this, _NS_PRIVATE_SEL(unlock));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Condition* NS::Condition::alloc()
|
||||||
|
{
|
||||||
|
return NS::Object::alloc<NS::Condition>(_NS_PRIVATE_CLS(NSCondition));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Condition* NS::Condition::init()
|
||||||
|
{
|
||||||
|
return NS::Object::init<NS::Condition>();
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE void NS::Condition::wait()
|
||||||
|
{
|
||||||
|
NS::Object::sendMessage<void>(this, _NS_PRIVATE_SEL(wait));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE bool NS::Condition::waitUntilDate(NS::Date* pLimit)
|
||||||
|
{
|
||||||
|
return NS::Object::sendMessage<bool>(this, _NS_PRIVATE_SEL(waitUntilDate_), pLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE void NS::Condition::signal()
|
||||||
|
{
|
||||||
|
NS::Object::sendMessage<void>(this, _NS_PRIVATE_SEL(signal));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE void NS::Condition::broadcast()
|
||||||
|
{
|
||||||
|
NS::Object::sendMessage<void>(this, _NS_PRIVATE_SEL(broadcast));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
110
third_party/metal-cpp/Foundation/NSNotification.hpp
vendored
Normal file
110
third_party/metal-cpp/Foundation/NSNotification.hpp
vendored
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Foundation/NSNotification.hpp
|
||||||
|
//
|
||||||
|
// Copyright 2020-2023 Apple Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "NSDefines.hpp"
|
||||||
|
#include "NSDictionary.hpp"
|
||||||
|
#include "NSObject.hpp"
|
||||||
|
#include "NSString.hpp"
|
||||||
|
#include "NSTypes.hpp"
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace NS
|
||||||
|
{
|
||||||
|
using NotificationName = class String*;
|
||||||
|
|
||||||
|
class Notification : public NS::Referencing<Notification>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NS::String* name() const;
|
||||||
|
NS::Object* object() const;
|
||||||
|
NS::Dictionary* userInfo() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
using ObserverBlock = void(^)(Notification*);
|
||||||
|
using ObserverFunction = std::function<void(Notification*)>;
|
||||||
|
|
||||||
|
class NotificationCenter : public NS::Referencing<NotificationCenter>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static class NotificationCenter* defaultCenter();
|
||||||
|
Object* addObserver(NotificationName name, Object* pObj, void* pQueue, ObserverBlock block);
|
||||||
|
Object* addObserver(NotificationName name, Object* pObj, void* pQueue, ObserverFunction &handler);
|
||||||
|
void removeObserver(Object* pObserver);
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::Notification::name() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::String*>(this, _NS_PRIVATE_SEL(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Object* NS::Notification::object() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::Object*>(this, _NS_PRIVATE_SEL(object));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Dictionary* NS::Notification::userInfo() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::Dictionary*>(this, _NS_PRIVATE_SEL(userInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::NotificationCenter* NS::NotificationCenter::defaultCenter()
|
||||||
|
{
|
||||||
|
return NS::Object::sendMessage<NS::NotificationCenter*>(_NS_PRIVATE_CLS(NSNotificationCenter), _NS_PRIVATE_SEL(defaultCenter));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Object* NS::NotificationCenter::addObserver(NS::NotificationName name, Object* pObj, void* pQueue, NS::ObserverBlock block)
|
||||||
|
{
|
||||||
|
return NS::Object::sendMessage<Object*>(this, _NS_PRIVATE_SEL(addObserverName_object_queue_block_), name, pObj, pQueue, block);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Object* NS::NotificationCenter::addObserver(NS::NotificationName name, Object* pObj, void* pQueue, NS::ObserverFunction &handler)
|
||||||
|
{
|
||||||
|
__block ObserverFunction blockFunction = handler;
|
||||||
|
|
||||||
|
return addObserver(name, pObj, pQueue, ^(NS::Notification* pNotif) {blockFunction(pNotif);});
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE void NS::NotificationCenter::removeObserver(Object* pObserver)
|
||||||
|
{
|
||||||
|
return NS::Object::sendMessage<void>(this, _NS_PRIVATE_SEL(removeObserver_), pObserver);
|
||||||
|
}
|
||||||
|
|
501
third_party/metal-cpp/Foundation/NSNumber.hpp
vendored
Normal file
501
third_party/metal-cpp/Foundation/NSNumber.hpp
vendored
Normal file
|
@ -0,0 +1,501 @@
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Foundation/NSNumber.hpp
|
||||||
|
//
|
||||||
|
// Copyright 2020-2023 Apple Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "NSObjCRuntime.hpp"
|
||||||
|
#include "NSObject.hpp"
|
||||||
|
#include "NSTypes.hpp"
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace NS
|
||||||
|
{
|
||||||
|
class Value : public Copying<Value>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static Value* value(const void* pValue, const char* pType);
|
||||||
|
static Value* value(const void* pPointer);
|
||||||
|
|
||||||
|
static Value* alloc();
|
||||||
|
|
||||||
|
Value* init(const void* pValue, const char* pType);
|
||||||
|
Value* init(const class Coder* pCoder);
|
||||||
|
|
||||||
|
void getValue(void* pValue, UInteger size) const;
|
||||||
|
const char* objCType() const;
|
||||||
|
|
||||||
|
bool isEqualToValue(Value* pValue) const;
|
||||||
|
void* pointerValue() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Number : public Copying<Number, Value>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static Number* number(char value);
|
||||||
|
static Number* number(unsigned char value);
|
||||||
|
static Number* number(short value);
|
||||||
|
static Number* number(unsigned short value);
|
||||||
|
static Number* number(int value);
|
||||||
|
static Number* number(unsigned int value);
|
||||||
|
static Number* number(long value);
|
||||||
|
static Number* number(unsigned long value);
|
||||||
|
static Number* number(long long value);
|
||||||
|
static Number* number(unsigned long long value);
|
||||||
|
static Number* number(float value);
|
||||||
|
static Number* number(double value);
|
||||||
|
static Number* number(bool value);
|
||||||
|
|
||||||
|
static Number* alloc();
|
||||||
|
|
||||||
|
Number* init(const class Coder* pCoder);
|
||||||
|
Number* init(char value);
|
||||||
|
Number* init(unsigned char value);
|
||||||
|
Number* init(short value);
|
||||||
|
Number* init(unsigned short value);
|
||||||
|
Number* init(int value);
|
||||||
|
Number* init(unsigned int value);
|
||||||
|
Number* init(long value);
|
||||||
|
Number* init(unsigned long value);
|
||||||
|
Number* init(long long value);
|
||||||
|
Number* init(unsigned long long value);
|
||||||
|
Number* init(float value);
|
||||||
|
Number* init(double value);
|
||||||
|
Number* init(bool value);
|
||||||
|
|
||||||
|
char charValue() const;
|
||||||
|
unsigned char unsignedCharValue() const;
|
||||||
|
short shortValue() const;
|
||||||
|
unsigned short unsignedShortValue() const;
|
||||||
|
int intValue() const;
|
||||||
|
unsigned int unsignedIntValue() const;
|
||||||
|
long longValue() const;
|
||||||
|
unsigned long unsignedLongValue() const;
|
||||||
|
long long longLongValue() const;
|
||||||
|
unsigned long long unsignedLongLongValue() const;
|
||||||
|
float floatValue() const;
|
||||||
|
double doubleValue() const;
|
||||||
|
bool boolValue() const;
|
||||||
|
Integer integerValue() const;
|
||||||
|
UInteger unsignedIntegerValue() const;
|
||||||
|
class String* stringValue() const;
|
||||||
|
|
||||||
|
ComparisonResult compare(const Number* pOtherNumber) const;
|
||||||
|
bool isEqualToNumber(const Number* pNumber) const;
|
||||||
|
|
||||||
|
class String* descriptionWithLocale(const Object* pLocale) const;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Value* NS::Value::value(const void* pValue, const char* pType)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Value*>(_NS_PRIVATE_CLS(NSValue), _NS_PRIVATE_SEL(valueWithBytes_objCType_), pValue, pType);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Value* NS::Value::value(const void* pPointer)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Value*>(_NS_PRIVATE_CLS(NSValue), _NS_PRIVATE_SEL(valueWithPointer_), pPointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Value* NS::Value::alloc()
|
||||||
|
{
|
||||||
|
return NS::Object::alloc<Value>(_NS_PRIVATE_CLS(NSValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Value* NS::Value::init(const void* pValue, const char* pType)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Value*>(this, _NS_PRIVATE_SEL(initWithBytes_objCType_), pValue, pType);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Value* NS::Value::init(const class Coder* pCoder)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Value*>(this, _NS_PRIVATE_SEL(initWithCoder_), pCoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE void NS::Value::getValue(void* pValue, UInteger size) const
|
||||||
|
{
|
||||||
|
Object::sendMessage<void>(this, _NS_PRIVATE_SEL(getValue_size_), pValue, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE const char* NS::Value::objCType() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<const char*>(this, _NS_PRIVATE_SEL(objCType));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE bool NS::Value::isEqualToValue(Value* pValue) const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<bool>(this, _NS_PRIVATE_SEL(isEqualToValue_), pValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE void* NS::Value::pointerValue() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<void*>(this, _NS_PRIVATE_SEL(pointerValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Number* NS::Number::number(char value)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Number*>(_NS_PRIVATE_CLS(NSNumber), _NS_PRIVATE_SEL(numberWithChar_), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Number* NS::Number::number(unsigned char value)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Number*>(_NS_PRIVATE_CLS(NSNumber), _NS_PRIVATE_SEL(numberWithUnsignedChar_), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Number* NS::Number::number(short value)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Number*>(_NS_PRIVATE_CLS(NSNumber), _NS_PRIVATE_SEL(numberWithShort_), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Number* NS::Number::number(unsigned short value)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Number*>(_NS_PRIVATE_CLS(NSNumber), _NS_PRIVATE_SEL(numberWithUnsignedShort_), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Number* NS::Number::number(int value)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Number*>(_NS_PRIVATE_CLS(NSNumber), _NS_PRIVATE_SEL(numberWithInt_), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Number* NS::Number::number(unsigned int value)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Number*>(_NS_PRIVATE_CLS(NSNumber), _NS_PRIVATE_SEL(numberWithUnsignedInt_), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Number* NS::Number::number(long value)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Number*>(_NS_PRIVATE_CLS(NSNumber), _NS_PRIVATE_SEL(numberWithLong_), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Number* NS::Number::number(unsigned long value)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Number*>(_NS_PRIVATE_CLS(NSNumber), _NS_PRIVATE_SEL(numberWithUnsignedLong_), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Number* NS::Number::number(long long value)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Number*>(_NS_PRIVATE_CLS(NSNumber), _NS_PRIVATE_SEL(numberWithLongLong_), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Number* NS::Number::number(unsigned long long value)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Number*>(_NS_PRIVATE_CLS(NSNumber), _NS_PRIVATE_SEL(numberWithUnsignedLongLong_), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Number* NS::Number::number(float value)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Number*>(_NS_PRIVATE_CLS(NSNumber), _NS_PRIVATE_SEL(numberWithFloat_), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Number* NS::Number::number(double value)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Number*>(_NS_PRIVATE_CLS(NSNumber), _NS_PRIVATE_SEL(numberWithDouble_), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Number* NS::Number::number(bool value)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Number*>(_NS_PRIVATE_CLS(NSNumber), _NS_PRIVATE_SEL(numberWithBool_), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Number* NS::Number::alloc()
|
||||||
|
{
|
||||||
|
return NS::Object::alloc<Number>(_NS_PRIVATE_CLS(NSNumber));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Number* NS::Number::init(const Coder* pCoder)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Number*>(this, _NS_PRIVATE_SEL(initWithCoder_), pCoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Number* NS::Number::init(char value)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Number*>(this, _NS_PRIVATE_SEL(initWithChar_), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Number* NS::Number::init(unsigned char value)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Number*>(this, _NS_PRIVATE_SEL(initWithUnsignedChar_), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Number* NS::Number::init(short value)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Number*>(this, _NS_PRIVATE_SEL(initWithShort_), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Number* NS::Number::init(unsigned short value)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Number*>(this, _NS_PRIVATE_SEL(initWithUnsignedShort_), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Number* NS::Number::init(int value)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Number*>(this, _NS_PRIVATE_SEL(initWithInt_), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Number* NS::Number::init(unsigned int value)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Number*>(this, _NS_PRIVATE_SEL(initWithUnsignedInt_), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Number* NS::Number::init(long value)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Number*>(this, _NS_PRIVATE_SEL(initWithLong_), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Number* NS::Number::init(unsigned long value)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Number*>(this, _NS_PRIVATE_SEL(initWithUnsignedLong_), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Number* NS::Number::init(long long value)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Number*>(this, _NS_PRIVATE_SEL(initWithLongLong_), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Number* NS::Number::init(unsigned long long value)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Number*>(this, _NS_PRIVATE_SEL(initWithUnsignedLongLong_), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Number* NS::Number::init(float value)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Number*>(this, _NS_PRIVATE_SEL(initWithFloat_), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Number* NS::Number::init(double value)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Number*>(this, _NS_PRIVATE_SEL(initWithDouble_), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Number* NS::Number::init(bool value)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Number*>(this, _NS_PRIVATE_SEL(initWithBool_), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE char NS::Number::charValue() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<char>(this, _NS_PRIVATE_SEL(charValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE unsigned char NS::Number::unsignedCharValue() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<unsigned char>(this, _NS_PRIVATE_SEL(unsignedCharValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE short NS::Number::shortValue() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<short>(this, _NS_PRIVATE_SEL(shortValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE unsigned short NS::Number::unsignedShortValue() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<unsigned short>(this, _NS_PRIVATE_SEL(unsignedShortValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE int NS::Number::intValue() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<int>(this, _NS_PRIVATE_SEL(intValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE unsigned int NS::Number::unsignedIntValue() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<unsigned int>(this, _NS_PRIVATE_SEL(unsignedIntValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE long NS::Number::longValue() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<long>(this, _NS_PRIVATE_SEL(longValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE unsigned long NS::Number::unsignedLongValue() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<unsigned long>(this, _NS_PRIVATE_SEL(unsignedLongValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE long long NS::Number::longLongValue() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<long long>(this, _NS_PRIVATE_SEL(longLongValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE unsigned long long NS::Number::unsignedLongLongValue() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<unsigned long long>(this, _NS_PRIVATE_SEL(unsignedLongLongValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE float NS::Number::floatValue() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<float>(this, _NS_PRIVATE_SEL(floatValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE double NS::Number::doubleValue() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<double>(this, _NS_PRIVATE_SEL(doubleValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE bool NS::Number::boolValue() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<bool>(this, _NS_PRIVATE_SEL(boolValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Integer NS::Number::integerValue() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Integer>(this, _NS_PRIVATE_SEL(integerValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::UInteger NS::Number::unsignedIntegerValue() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<UInteger>(this, _NS_PRIVATE_SEL(unsignedIntegerValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::Number::stringValue() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<String*>(this, _NS_PRIVATE_SEL(stringValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::ComparisonResult NS::Number::compare(const Number* pOtherNumber) const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<ComparisonResult>(this, _NS_PRIVATE_SEL(compare_), pOtherNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE bool NS::Number::isEqualToNumber(const Number* pNumber) const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<bool>(this, _NS_PRIVATE_SEL(isEqualToNumber_), pNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::Number::descriptionWithLocale(const Object* pLocale) const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<String*>(this, _NS_PRIVATE_SEL(descriptionWithLocale_), pLocale);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
43
third_party/metal-cpp/Foundation/NSObjCRuntime.hpp
vendored
Normal file
43
third_party/metal-cpp/Foundation/NSObjCRuntime.hpp
vendored
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Foundation/NSObjCRuntime.hpp
|
||||||
|
//
|
||||||
|
// Copyright 2020-2023 Apple Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "NSDefines.hpp"
|
||||||
|
#include "NSTypes.hpp"
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace NS
|
||||||
|
{
|
||||||
|
|
||||||
|
_NS_ENUM(Integer, ComparisonResult) {
|
||||||
|
OrderedAscending = -1L,
|
||||||
|
OrderedSame,
|
||||||
|
OrderedDescending
|
||||||
|
};
|
||||||
|
|
||||||
|
const Integer NotFound = IntegerMax;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
302
third_party/metal-cpp/Foundation/NSObject.hpp
vendored
Normal file
302
third_party/metal-cpp/Foundation/NSObject.hpp
vendored
Normal file
|
@ -0,0 +1,302 @@
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Foundation/NSObject.hpp
|
||||||
|
//
|
||||||
|
// Copyright 2020-2023 Apple Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "NSDefines.hpp"
|
||||||
|
#include "NSPrivate.hpp"
|
||||||
|
#include "NSTypes.hpp"
|
||||||
|
|
||||||
|
#include <objc/message.h>
|
||||||
|
#include <objc/runtime.h>
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace NS
|
||||||
|
{
|
||||||
|
template <class _Class, class _Base = class Object>
|
||||||
|
class _NS_EXPORT Referencing : public _Base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
_Class* retain();
|
||||||
|
void release();
|
||||||
|
|
||||||
|
_Class* autorelease();
|
||||||
|
|
||||||
|
UInteger retainCount() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class _Class, class _Base = class Object>
|
||||||
|
class Copying : public Referencing<_Class, _Base>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
_Class* copy() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class _Class, class _Base = class Object>
|
||||||
|
class SecureCoding : public Referencing<_Class, _Base>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
class Object : public Referencing<Object, objc_object>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UInteger hash() const;
|
||||||
|
bool isEqual(const Object* pObject) const;
|
||||||
|
|
||||||
|
class String* description() const;
|
||||||
|
class String* debugDescription() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
friend class Referencing<Object, objc_object>;
|
||||||
|
|
||||||
|
template <class _Class>
|
||||||
|
static _Class* alloc(const char* pClassName);
|
||||||
|
template <class _Class>
|
||||||
|
static _Class* alloc(const void* pClass);
|
||||||
|
template <class _Class>
|
||||||
|
_Class* init();
|
||||||
|
|
||||||
|
template <class _Dst>
|
||||||
|
static _Dst bridgingCast(const void* pObj);
|
||||||
|
static class MethodSignature* methodSignatureForSelector(const void* pObj, SEL selector);
|
||||||
|
static bool respondsToSelector(const void* pObj, SEL selector);
|
||||||
|
template <typename _Type>
|
||||||
|
static constexpr bool doesRequireMsgSendStret();
|
||||||
|
template <typename _Ret, typename... _Args>
|
||||||
|
static _Ret sendMessage(const void* pObj, SEL selector, _Args... args);
|
||||||
|
template <typename _Ret, typename... _Args>
|
||||||
|
static _Ret sendMessageSafe(const void* pObj, SEL selector, _Args... args);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Object() = delete;
|
||||||
|
Object(const Object&) = delete;
|
||||||
|
~Object() = delete;
|
||||||
|
|
||||||
|
Object& operator=(const Object&) = delete;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template <class _Class, class _Base /* = Object */>
|
||||||
|
_NS_INLINE _Class* NS::Referencing<_Class, _Base>::retain()
|
||||||
|
{
|
||||||
|
return Object::sendMessage<_Class*>(this, _NS_PRIVATE_SEL(retain));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template <class _Class, class _Base /* = Object */>
|
||||||
|
_NS_INLINE void NS::Referencing<_Class, _Base>::release()
|
||||||
|
{
|
||||||
|
Object::sendMessage<void>(this, _NS_PRIVATE_SEL(release));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template <class _Class, class _Base /* = Object */>
|
||||||
|
_NS_INLINE _Class* NS::Referencing<_Class, _Base>::autorelease()
|
||||||
|
{
|
||||||
|
return Object::sendMessage<_Class*>(this, _NS_PRIVATE_SEL(autorelease));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template <class _Class, class _Base /* = Object */>
|
||||||
|
_NS_INLINE NS::UInteger NS::Referencing<_Class, _Base>::retainCount() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<UInteger>(this, _NS_PRIVATE_SEL(retainCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template <class _Class, class _Base /* = Object */>
|
||||||
|
_NS_INLINE _Class* NS::Copying<_Class, _Base>::copy() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<_Class*>(this, _NS_PRIVATE_SEL(copy));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template <class _Dst>
|
||||||
|
_NS_INLINE _Dst NS::Object::bridgingCast(const void* pObj)
|
||||||
|
{
|
||||||
|
#ifdef __OBJC__
|
||||||
|
return (__bridge _Dst)pObj;
|
||||||
|
#else
|
||||||
|
return (_Dst)pObj;
|
||||||
|
#endif // __OBJC__
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template <typename _Type>
|
||||||
|
_NS_INLINE constexpr bool NS::Object::doesRequireMsgSendStret()
|
||||||
|
{
|
||||||
|
#if (defined(__i386__) || defined(__x86_64__))
|
||||||
|
constexpr size_t kStructLimit = (sizeof(std::uintptr_t) << 1);
|
||||||
|
|
||||||
|
return sizeof(_Type) > kStructLimit;
|
||||||
|
#elif defined(__arm64__)
|
||||||
|
return false;
|
||||||
|
#elif defined(__arm__)
|
||||||
|
constexpr size_t kStructLimit = sizeof(std::uintptr_t);
|
||||||
|
|
||||||
|
return std::is_class(_Type) && (sizeof(_Type) > kStructLimit);
|
||||||
|
#else
|
||||||
|
#error "Unsupported architecture!"
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template <>
|
||||||
|
_NS_INLINE constexpr bool NS::Object::doesRequireMsgSendStret<void>()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template <typename _Ret, typename... _Args>
|
||||||
|
_NS_INLINE _Ret NS::Object::sendMessage(const void* pObj, SEL selector, _Args... args)
|
||||||
|
{
|
||||||
|
#if (defined(__i386__) || defined(__x86_64__))
|
||||||
|
if constexpr (std::is_floating_point<_Ret>())
|
||||||
|
{
|
||||||
|
using SendMessageProcFpret = _Ret (*)(const void*, SEL, _Args...);
|
||||||
|
|
||||||
|
const SendMessageProcFpret pProc = reinterpret_cast<SendMessageProcFpret>(&objc_msgSend_fpret);
|
||||||
|
|
||||||
|
return (*pProc)(pObj, selector, args...);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif // ( defined( __i386__ ) || defined( __x86_64__ ) )
|
||||||
|
#if !defined(__arm64__)
|
||||||
|
if constexpr (doesRequireMsgSendStret<_Ret>())
|
||||||
|
{
|
||||||
|
using SendMessageProcStret = void (*)(_Ret*, const void*, SEL, _Args...);
|
||||||
|
|
||||||
|
const SendMessageProcStret pProc = reinterpret_cast<SendMessageProcStret>(&objc_msgSend_stret);
|
||||||
|
_Ret ret;
|
||||||
|
|
||||||
|
(*pProc)(&ret, pObj, selector, args...);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif // !defined( __arm64__ )
|
||||||
|
{
|
||||||
|
using SendMessageProc = _Ret (*)(const void*, SEL, _Args...);
|
||||||
|
|
||||||
|
const SendMessageProc pProc = reinterpret_cast<SendMessageProc>(&objc_msgSend);
|
||||||
|
|
||||||
|
return (*pProc)(pObj, selector, args...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::MethodSignature* NS::Object::methodSignatureForSelector(const void* pObj, SEL selector)
|
||||||
|
{
|
||||||
|
return sendMessage<MethodSignature*>(pObj, _NS_PRIVATE_SEL(methodSignatureForSelector_), selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE bool NS::Object::respondsToSelector(const void* pObj, SEL selector)
|
||||||
|
{
|
||||||
|
return sendMessage<bool>(pObj, _NS_PRIVATE_SEL(respondsToSelector_), selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template <typename _Ret, typename... _Args>
|
||||||
|
_NS_INLINE _Ret NS::Object::sendMessageSafe(const void* pObj, SEL selector, _Args... args)
|
||||||
|
{
|
||||||
|
if ((respondsToSelector(pObj, selector)) || (nullptr != methodSignatureForSelector(pObj, selector)))
|
||||||
|
{
|
||||||
|
return sendMessage<_Ret>(pObj, selector, args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (!std::is_void<_Ret>::value)
|
||||||
|
{
|
||||||
|
return _Ret(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template <class _Class>
|
||||||
|
_NS_INLINE _Class* NS::Object::alloc(const char* pClassName)
|
||||||
|
{
|
||||||
|
return sendMessage<_Class*>(objc_lookUpClass(pClassName), _NS_PRIVATE_SEL(alloc));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template <class _Class>
|
||||||
|
_NS_INLINE _Class* NS::Object::alloc(const void* pClass)
|
||||||
|
{
|
||||||
|
return sendMessage<_Class*>(pClass, _NS_PRIVATE_SEL(alloc));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template <class _Class>
|
||||||
|
_NS_INLINE _Class* NS::Object::init()
|
||||||
|
{
|
||||||
|
return sendMessage<_Class*>(this, _NS_PRIVATE_SEL(init));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::UInteger NS::Object::hash() const
|
||||||
|
{
|
||||||
|
return sendMessage<UInteger>(this, _NS_PRIVATE_SEL(hash));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE bool NS::Object::isEqual(const Object* pObject) const
|
||||||
|
{
|
||||||
|
return sendMessage<bool>(this, _NS_PRIVATE_SEL(isEqual_), pObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::Object::description() const
|
||||||
|
{
|
||||||
|
return sendMessage<String*>(this, _NS_PRIVATE_SEL(description));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::Object::debugDescription() const
|
||||||
|
{
|
||||||
|
return sendMessageSafe<String*>(this, _NS_PRIVATE_SEL(debugDescription));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
507
third_party/metal-cpp/Foundation/NSPrivate.hpp
vendored
Normal file
507
third_party/metal-cpp/Foundation/NSPrivate.hpp
vendored
Normal file
|
@ -0,0 +1,507 @@
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Foundation/NSPrivate.hpp
|
||||||
|
//
|
||||||
|
// Copyright 2020-2023 Apple Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include <objc/runtime.h>
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define _NS_PRIVATE_CLS(symbol) (Private::Class::s_k##symbol)
|
||||||
|
#define _NS_PRIVATE_SEL(accessor) (Private::Selector::s_k##accessor)
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#if defined(NS_PRIVATE_IMPLEMENTATION)
|
||||||
|
|
||||||
|
#ifdef METALCPP_SYMBOL_VISIBILITY_HIDDEN
|
||||||
|
#define _NS_PRIVATE_VISIBILITY __attribute__((visibility("hidden")))
|
||||||
|
#else
|
||||||
|
#define _NS_PRIVATE_VISIBILITY __attribute__((visibility("default")))
|
||||||
|
#endif // METALCPP_SYMBOL_VISIBILITY_HIDDEN
|
||||||
|
|
||||||
|
#define _NS_PRIVATE_IMPORT __attribute__((weak_import))
|
||||||
|
|
||||||
|
#ifdef __OBJC__
|
||||||
|
#define _NS_PRIVATE_OBJC_LOOKUP_CLASS(symbol) ((__bridge void*)objc_lookUpClass(#symbol))
|
||||||
|
#define _NS_PRIVATE_OBJC_GET_PROTOCOL(symbol) ((__bridge void*)objc_getProtocol(#symbol))
|
||||||
|
#else
|
||||||
|
#define _NS_PRIVATE_OBJC_LOOKUP_CLASS(symbol) objc_lookUpClass(#symbol)
|
||||||
|
#define _NS_PRIVATE_OBJC_GET_PROTOCOL(symbol) objc_getProtocol(#symbol)
|
||||||
|
#endif // __OBJC__
|
||||||
|
|
||||||
|
#define _NS_PRIVATE_DEF_CLS(symbol) void* s_k##symbol _NS_PRIVATE_VISIBILITY = _NS_PRIVATE_OBJC_LOOKUP_CLASS(symbol)
|
||||||
|
#define _NS_PRIVATE_DEF_PRO(symbol) void* s_k##symbol _NS_PRIVATE_VISIBILITY = _NS_PRIVATE_OBJC_GET_PROTOCOL(symbol)
|
||||||
|
#define _NS_PRIVATE_DEF_SEL(accessor, symbol) SEL s_k##accessor _NS_PRIVATE_VISIBILITY = sel_registerName(symbol)
|
||||||
|
#define _NS_PRIVATE_DEF_CONST(type, symbol) \
|
||||||
|
_NS_EXTERN type const NS##symbol _NS_PRIVATE_IMPORT; \
|
||||||
|
type const NS::symbol = (nullptr != &NS##symbol) ? NS##symbol : nullptr
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define _NS_PRIVATE_DEF_CLS(symbol) extern void* s_k##symbol
|
||||||
|
#define _NS_PRIVATE_DEF_PRO(symbol) extern void* s_k##symbol
|
||||||
|
#define _NS_PRIVATE_DEF_SEL(accessor, symbol) extern SEL s_k##accessor
|
||||||
|
#define _NS_PRIVATE_DEF_CONST(type, symbol) extern type const NS::symbol
|
||||||
|
|
||||||
|
#endif // NS_PRIVATE_IMPLEMENTATION
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace NS
|
||||||
|
{
|
||||||
|
namespace Private
|
||||||
|
{
|
||||||
|
namespace Class
|
||||||
|
{
|
||||||
|
|
||||||
|
_NS_PRIVATE_DEF_CLS(NSArray);
|
||||||
|
_NS_PRIVATE_DEF_CLS(NSAutoreleasePool);
|
||||||
|
_NS_PRIVATE_DEF_CLS(NSBundle);
|
||||||
|
_NS_PRIVATE_DEF_CLS(NSCondition);
|
||||||
|
_NS_PRIVATE_DEF_CLS(NSDate);
|
||||||
|
_NS_PRIVATE_DEF_CLS(NSDictionary);
|
||||||
|
_NS_PRIVATE_DEF_CLS(NSError);
|
||||||
|
_NS_PRIVATE_DEF_CLS(NSNotificationCenter);
|
||||||
|
_NS_PRIVATE_DEF_CLS(NSNumber);
|
||||||
|
_NS_PRIVATE_DEF_CLS(NSObject);
|
||||||
|
_NS_PRIVATE_DEF_CLS(NSProcessInfo);
|
||||||
|
_NS_PRIVATE_DEF_CLS(NSSet);
|
||||||
|
_NS_PRIVATE_DEF_CLS(NSString);
|
||||||
|
_NS_PRIVATE_DEF_CLS(NSURL);
|
||||||
|
_NS_PRIVATE_DEF_CLS(NSValue);
|
||||||
|
|
||||||
|
} // Class
|
||||||
|
} // Private
|
||||||
|
} // MTL
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace NS
|
||||||
|
{
|
||||||
|
namespace Private
|
||||||
|
{
|
||||||
|
namespace Protocol
|
||||||
|
{
|
||||||
|
|
||||||
|
} // Protocol
|
||||||
|
} // Private
|
||||||
|
} // NS
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace NS
|
||||||
|
{
|
||||||
|
namespace Private
|
||||||
|
{
|
||||||
|
namespace Selector
|
||||||
|
{
|
||||||
|
|
||||||
|
_NS_PRIVATE_DEF_SEL(addObject_,
|
||||||
|
"addObject:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(addObserverName_object_queue_block_,
|
||||||
|
"addObserverForName:object:queue:usingBlock:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(activeProcessorCount,
|
||||||
|
"activeProcessorCount");
|
||||||
|
_NS_PRIVATE_DEF_SEL(allBundles,
|
||||||
|
"allBundles");
|
||||||
|
_NS_PRIVATE_DEF_SEL(allFrameworks,
|
||||||
|
"allFrameworks");
|
||||||
|
_NS_PRIVATE_DEF_SEL(allObjects,
|
||||||
|
"allObjects");
|
||||||
|
_NS_PRIVATE_DEF_SEL(alloc,
|
||||||
|
"alloc");
|
||||||
|
_NS_PRIVATE_DEF_SEL(appStoreReceiptURL,
|
||||||
|
"appStoreReceiptURL");
|
||||||
|
_NS_PRIVATE_DEF_SEL(arguments,
|
||||||
|
"arguments");
|
||||||
|
_NS_PRIVATE_DEF_SEL(array,
|
||||||
|
"array");
|
||||||
|
_NS_PRIVATE_DEF_SEL(arrayWithObject_,
|
||||||
|
"arrayWithObject:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(arrayWithObjects_count_,
|
||||||
|
"arrayWithObjects:count:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(automaticTerminationSupportEnabled,
|
||||||
|
"automaticTerminationSupportEnabled");
|
||||||
|
_NS_PRIVATE_DEF_SEL(autorelease,
|
||||||
|
"autorelease");
|
||||||
|
_NS_PRIVATE_DEF_SEL(beginActivityWithOptions_reason_,
|
||||||
|
"beginActivityWithOptions:reason:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(boolValue,
|
||||||
|
"boolValue");
|
||||||
|
_NS_PRIVATE_DEF_SEL(broadcast,
|
||||||
|
"broadcast");
|
||||||
|
_NS_PRIVATE_DEF_SEL(builtInPlugInsPath,
|
||||||
|
"builtInPlugInsPath");
|
||||||
|
_NS_PRIVATE_DEF_SEL(builtInPlugInsURL,
|
||||||
|
"builtInPlugInsURL");
|
||||||
|
_NS_PRIVATE_DEF_SEL(bundleIdentifier,
|
||||||
|
"bundleIdentifier");
|
||||||
|
_NS_PRIVATE_DEF_SEL(bundlePath,
|
||||||
|
"bundlePath");
|
||||||
|
_NS_PRIVATE_DEF_SEL(bundleURL,
|
||||||
|
"bundleURL");
|
||||||
|
_NS_PRIVATE_DEF_SEL(bundleWithPath_,
|
||||||
|
"bundleWithPath:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(bundleWithURL_,
|
||||||
|
"bundleWithURL:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(caseInsensitiveCompare_,
|
||||||
|
"caseInsensitiveCompare:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(characterAtIndex_,
|
||||||
|
"characterAtIndex:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(charValue,
|
||||||
|
"charValue");
|
||||||
|
_NS_PRIVATE_DEF_SEL(countByEnumeratingWithState_objects_count_,
|
||||||
|
"countByEnumeratingWithState:objects:count:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(cStringUsingEncoding_,
|
||||||
|
"cStringUsingEncoding:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(code,
|
||||||
|
"code");
|
||||||
|
_NS_PRIVATE_DEF_SEL(compare_,
|
||||||
|
"compare:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(copy,
|
||||||
|
"copy");
|
||||||
|
_NS_PRIVATE_DEF_SEL(count,
|
||||||
|
"count");
|
||||||
|
_NS_PRIVATE_DEF_SEL(dateWithTimeIntervalSinceNow_,
|
||||||
|
"dateWithTimeIntervalSinceNow:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(defaultCenter,
|
||||||
|
"defaultCenter");
|
||||||
|
_NS_PRIVATE_DEF_SEL(descriptionWithLocale_,
|
||||||
|
"descriptionWithLocale:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(disableAutomaticTermination_,
|
||||||
|
"disableAutomaticTermination:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(disableSuddenTermination,
|
||||||
|
"disableSuddenTermination");
|
||||||
|
_NS_PRIVATE_DEF_SEL(debugDescription,
|
||||||
|
"debugDescription");
|
||||||
|
_NS_PRIVATE_DEF_SEL(description,
|
||||||
|
"description");
|
||||||
|
_NS_PRIVATE_DEF_SEL(dictionary,
|
||||||
|
"dictionary");
|
||||||
|
_NS_PRIVATE_DEF_SEL(dictionaryWithObject_forKey_,
|
||||||
|
"dictionaryWithObject:forKey:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(dictionaryWithObjects_forKeys_count_,
|
||||||
|
"dictionaryWithObjects:forKeys:count:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(domain,
|
||||||
|
"domain");
|
||||||
|
_NS_PRIVATE_DEF_SEL(doubleValue,
|
||||||
|
"doubleValue");
|
||||||
|
_NS_PRIVATE_DEF_SEL(drain,
|
||||||
|
"drain");
|
||||||
|
_NS_PRIVATE_DEF_SEL(enableAutomaticTermination_,
|
||||||
|
"enableAutomaticTermination:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(enableSuddenTermination,
|
||||||
|
"enableSuddenTermination");
|
||||||
|
_NS_PRIVATE_DEF_SEL(endActivity_,
|
||||||
|
"endActivity:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(environment,
|
||||||
|
"environment");
|
||||||
|
_NS_PRIVATE_DEF_SEL(errorWithDomain_code_userInfo_,
|
||||||
|
"errorWithDomain:code:userInfo:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(executablePath,
|
||||||
|
"executablePath");
|
||||||
|
_NS_PRIVATE_DEF_SEL(executableURL,
|
||||||
|
"executableURL");
|
||||||
|
_NS_PRIVATE_DEF_SEL(fileSystemRepresentation,
|
||||||
|
"fileSystemRepresentation");
|
||||||
|
_NS_PRIVATE_DEF_SEL(fileURLWithPath_,
|
||||||
|
"fileURLWithPath:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(floatValue,
|
||||||
|
"floatValue");
|
||||||
|
_NS_PRIVATE_DEF_SEL(fullUserName,
|
||||||
|
"fullUserName");
|
||||||
|
_NS_PRIVATE_DEF_SEL(getValue_size_,
|
||||||
|
"getValue:size:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(globallyUniqueString,
|
||||||
|
"globallyUniqueString");
|
||||||
|
_NS_PRIVATE_DEF_SEL(hash,
|
||||||
|
"hash");
|
||||||
|
_NS_PRIVATE_DEF_SEL(hostName,
|
||||||
|
"hostName");
|
||||||
|
_NS_PRIVATE_DEF_SEL(infoDictionary,
|
||||||
|
"infoDictionary");
|
||||||
|
_NS_PRIVATE_DEF_SEL(init,
|
||||||
|
"init");
|
||||||
|
_NS_PRIVATE_DEF_SEL(initFileURLWithPath_,
|
||||||
|
"initFileURLWithPath:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(initWithBool_,
|
||||||
|
"initWithBool:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(initWithBytes_objCType_,
|
||||||
|
"initWithBytes:objCType:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(initWithBytesNoCopy_length_encoding_freeWhenDone_,
|
||||||
|
"initWithBytesNoCopy:length:encoding:freeWhenDone:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(initWithChar_,
|
||||||
|
"initWithChar:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(initWithCoder_,
|
||||||
|
"initWithCoder:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(initWithCString_encoding_,
|
||||||
|
"initWithCString:encoding:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(initWithDomain_code_userInfo_,
|
||||||
|
"initWithDomain:code:userInfo:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(initWithDouble_,
|
||||||
|
"initWithDouble:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(initWithFloat_,
|
||||||
|
"initWithFloat:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(initWithInt_,
|
||||||
|
"initWithInt:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(initWithLong_,
|
||||||
|
"initWithLong:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(initWithLongLong_,
|
||||||
|
"initWithLongLong:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(initWithObjects_count_,
|
||||||
|
"initWithObjects:count:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(initWithObjects_forKeys_count_,
|
||||||
|
"initWithObjects:forKeys:count:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(initWithPath_,
|
||||||
|
"initWithPath:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(initWithShort_,
|
||||||
|
"initWithShort:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(initWithString_,
|
||||||
|
"initWithString:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(initWithUnsignedChar_,
|
||||||
|
"initWithUnsignedChar:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(initWithUnsignedInt_,
|
||||||
|
"initWithUnsignedInt:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(initWithUnsignedLong_,
|
||||||
|
"initWithUnsignedLong:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(initWithUnsignedLongLong_,
|
||||||
|
"initWithUnsignedLongLong:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(initWithUnsignedShort_,
|
||||||
|
"initWithUnsignedShort:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(initWithURL_,
|
||||||
|
"initWithURL:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(integerValue,
|
||||||
|
"integerValue");
|
||||||
|
_NS_PRIVATE_DEF_SEL(intValue,
|
||||||
|
"intValue");
|
||||||
|
_NS_PRIVATE_DEF_SEL(isEqual_,
|
||||||
|
"isEqual:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(isEqualToNumber_,
|
||||||
|
"isEqualToNumber:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(isEqualToString_,
|
||||||
|
"isEqualToString:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(isEqualToValue_,
|
||||||
|
"isEqualToValue:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(isiOSAppOnMac,
|
||||||
|
"isiOSAppOnMac");
|
||||||
|
_NS_PRIVATE_DEF_SEL(isLoaded,
|
||||||
|
"isLoaded");
|
||||||
|
_NS_PRIVATE_DEF_SEL(isLowPowerModeEnabled,
|
||||||
|
"isLowPowerModeEnabled");
|
||||||
|
_NS_PRIVATE_DEF_SEL(isMacCatalystApp,
|
||||||
|
"isMacCatalystApp");
|
||||||
|
_NS_PRIVATE_DEF_SEL(isOperatingSystemAtLeastVersion_,
|
||||||
|
"isOperatingSystemAtLeastVersion:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(keyEnumerator,
|
||||||
|
"keyEnumerator");
|
||||||
|
_NS_PRIVATE_DEF_SEL(length,
|
||||||
|
"length");
|
||||||
|
_NS_PRIVATE_DEF_SEL(lengthOfBytesUsingEncoding_,
|
||||||
|
"lengthOfBytesUsingEncoding:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(load,
|
||||||
|
"load");
|
||||||
|
_NS_PRIVATE_DEF_SEL(loadAndReturnError_,
|
||||||
|
"loadAndReturnError:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(localizedDescription,
|
||||||
|
"localizedDescription");
|
||||||
|
_NS_PRIVATE_DEF_SEL(localizedFailureReason,
|
||||||
|
"localizedFailureReason");
|
||||||
|
_NS_PRIVATE_DEF_SEL(localizedInfoDictionary,
|
||||||
|
"localizedInfoDictionary");
|
||||||
|
_NS_PRIVATE_DEF_SEL(localizedRecoveryOptions,
|
||||||
|
"localizedRecoveryOptions");
|
||||||
|
_NS_PRIVATE_DEF_SEL(localizedRecoverySuggestion,
|
||||||
|
"localizedRecoverySuggestion");
|
||||||
|
_NS_PRIVATE_DEF_SEL(localizedStringForKey_value_table_,
|
||||||
|
"localizedStringForKey:value:table:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(lock,
|
||||||
|
"lock");
|
||||||
|
_NS_PRIVATE_DEF_SEL(longValue,
|
||||||
|
"longValue");
|
||||||
|
_NS_PRIVATE_DEF_SEL(longLongValue,
|
||||||
|
"longLongValue");
|
||||||
|
_NS_PRIVATE_DEF_SEL(mainBundle,
|
||||||
|
"mainBundle");
|
||||||
|
_NS_PRIVATE_DEF_SEL(maximumLengthOfBytesUsingEncoding_,
|
||||||
|
"maximumLengthOfBytesUsingEncoding:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(methodSignatureForSelector_,
|
||||||
|
"methodSignatureForSelector:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(mutableBytes,
|
||||||
|
"mutableBytes");
|
||||||
|
_NS_PRIVATE_DEF_SEL(name,
|
||||||
|
"name");
|
||||||
|
_NS_PRIVATE_DEF_SEL(nextObject,
|
||||||
|
"nextObject");
|
||||||
|
_NS_PRIVATE_DEF_SEL(numberWithBool_,
|
||||||
|
"numberWithBool:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(numberWithChar_,
|
||||||
|
"numberWithChar:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(numberWithDouble_,
|
||||||
|
"numberWithDouble:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(numberWithFloat_,
|
||||||
|
"numberWithFloat:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(numberWithInt_,
|
||||||
|
"numberWithInt:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(numberWithLong_,
|
||||||
|
"numberWithLong:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(numberWithLongLong_,
|
||||||
|
"numberWithLongLong:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(numberWithShort_,
|
||||||
|
"numberWithShort:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(numberWithUnsignedChar_,
|
||||||
|
"numberWithUnsignedChar:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(numberWithUnsignedInt_,
|
||||||
|
"numberWithUnsignedInt:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(numberWithUnsignedLong_,
|
||||||
|
"numberWithUnsignedLong:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(numberWithUnsignedLongLong_,
|
||||||
|
"numberWithUnsignedLongLong:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(numberWithUnsignedShort_,
|
||||||
|
"numberWithUnsignedShort:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(objCType,
|
||||||
|
"objCType");
|
||||||
|
_NS_PRIVATE_DEF_SEL(object,
|
||||||
|
"object");
|
||||||
|
_NS_PRIVATE_DEF_SEL(objectAtIndex_,
|
||||||
|
"objectAtIndex:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(objectEnumerator,
|
||||||
|
"objectEnumerator");
|
||||||
|
_NS_PRIVATE_DEF_SEL(objectForInfoDictionaryKey_,
|
||||||
|
"objectForInfoDictionaryKey:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(objectForKey_,
|
||||||
|
"objectForKey:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(operatingSystem,
|
||||||
|
"operatingSystem");
|
||||||
|
_NS_PRIVATE_DEF_SEL(operatingSystemVersion,
|
||||||
|
"operatingSystemVersion");
|
||||||
|
_NS_PRIVATE_DEF_SEL(operatingSystemVersionString,
|
||||||
|
"operatingSystemVersionString");
|
||||||
|
_NS_PRIVATE_DEF_SEL(pathForAuxiliaryExecutable_,
|
||||||
|
"pathForAuxiliaryExecutable:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(performActivityWithOptions_reason_usingBlock_,
|
||||||
|
"performActivityWithOptions:reason:usingBlock:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(performExpiringActivityWithReason_usingBlock_,
|
||||||
|
"performExpiringActivityWithReason:usingBlock:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(physicalMemory,
|
||||||
|
"physicalMemory");
|
||||||
|
_NS_PRIVATE_DEF_SEL(pointerValue,
|
||||||
|
"pointerValue");
|
||||||
|
_NS_PRIVATE_DEF_SEL(preflightAndReturnError_,
|
||||||
|
"preflightAndReturnError:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(privateFrameworksPath,
|
||||||
|
"privateFrameworksPath");
|
||||||
|
_NS_PRIVATE_DEF_SEL(privateFrameworksURL,
|
||||||
|
"privateFrameworksURL");
|
||||||
|
_NS_PRIVATE_DEF_SEL(processIdentifier,
|
||||||
|
"processIdentifier");
|
||||||
|
_NS_PRIVATE_DEF_SEL(processInfo,
|
||||||
|
"processInfo");
|
||||||
|
_NS_PRIVATE_DEF_SEL(processName,
|
||||||
|
"processName");
|
||||||
|
_NS_PRIVATE_DEF_SEL(processorCount,
|
||||||
|
"processorCount");
|
||||||
|
_NS_PRIVATE_DEF_SEL(rangeOfString_options_,
|
||||||
|
"rangeOfString:options:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(release,
|
||||||
|
"release");
|
||||||
|
_NS_PRIVATE_DEF_SEL(removeObserver_,
|
||||||
|
"removeObserver:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(resourcePath,
|
||||||
|
"resourcePath");
|
||||||
|
_NS_PRIVATE_DEF_SEL(resourceURL,
|
||||||
|
"resourceURL");
|
||||||
|
_NS_PRIVATE_DEF_SEL(respondsToSelector_,
|
||||||
|
"respondsToSelector:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(retain,
|
||||||
|
"retain");
|
||||||
|
_NS_PRIVATE_DEF_SEL(retainCount,
|
||||||
|
"retainCount");
|
||||||
|
_NS_PRIVATE_DEF_SEL(setAutomaticTerminationSupportEnabled_,
|
||||||
|
"setAutomaticTerminationSupportEnabled:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(setProcessName_,
|
||||||
|
"setProcessName:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(sharedFrameworksPath,
|
||||||
|
"sharedFrameworksPath");
|
||||||
|
_NS_PRIVATE_DEF_SEL(sharedFrameworksURL,
|
||||||
|
"sharedFrameworksURL");
|
||||||
|
_NS_PRIVATE_DEF_SEL(sharedSupportPath,
|
||||||
|
"sharedSupportPath");
|
||||||
|
_NS_PRIVATE_DEF_SEL(sharedSupportURL,
|
||||||
|
"sharedSupportURL");
|
||||||
|
_NS_PRIVATE_DEF_SEL(shortValue,
|
||||||
|
"shortValue");
|
||||||
|
_NS_PRIVATE_DEF_SEL(showPools,
|
||||||
|
"showPools");
|
||||||
|
_NS_PRIVATE_DEF_SEL(signal,
|
||||||
|
"signal");
|
||||||
|
_NS_PRIVATE_DEF_SEL(string,
|
||||||
|
"string");
|
||||||
|
_NS_PRIVATE_DEF_SEL(stringValue,
|
||||||
|
"stringValue");
|
||||||
|
_NS_PRIVATE_DEF_SEL(stringWithString_,
|
||||||
|
"stringWithString:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(stringWithCString_encoding_,
|
||||||
|
"stringWithCString:encoding:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(stringByAppendingString_,
|
||||||
|
"stringByAppendingString:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(systemUptime,
|
||||||
|
"systemUptime");
|
||||||
|
_NS_PRIVATE_DEF_SEL(thermalState,
|
||||||
|
"thermalState");
|
||||||
|
_NS_PRIVATE_DEF_SEL(unload,
|
||||||
|
"unload");
|
||||||
|
_NS_PRIVATE_DEF_SEL(unlock,
|
||||||
|
"unlock");
|
||||||
|
_NS_PRIVATE_DEF_SEL(unsignedCharValue,
|
||||||
|
"unsignedCharValue");
|
||||||
|
_NS_PRIVATE_DEF_SEL(unsignedIntegerValue,
|
||||||
|
"unsignedIntegerValue");
|
||||||
|
_NS_PRIVATE_DEF_SEL(unsignedIntValue,
|
||||||
|
"unsignedIntValue");
|
||||||
|
_NS_PRIVATE_DEF_SEL(unsignedLongValue,
|
||||||
|
"unsignedLongValue");
|
||||||
|
_NS_PRIVATE_DEF_SEL(unsignedLongLongValue,
|
||||||
|
"unsignedLongLongValue");
|
||||||
|
_NS_PRIVATE_DEF_SEL(unsignedShortValue,
|
||||||
|
"unsignedShortValue");
|
||||||
|
_NS_PRIVATE_DEF_SEL(URLForAuxiliaryExecutable_,
|
||||||
|
"URLForAuxiliaryExecutable:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(userInfo,
|
||||||
|
"userInfo");
|
||||||
|
_NS_PRIVATE_DEF_SEL(userName,
|
||||||
|
"userName");
|
||||||
|
_NS_PRIVATE_DEF_SEL(UTF8String,
|
||||||
|
"UTF8String");
|
||||||
|
_NS_PRIVATE_DEF_SEL(valueWithBytes_objCType_,
|
||||||
|
"valueWithBytes:objCType:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(valueWithPointer_,
|
||||||
|
"valueWithPointer:");
|
||||||
|
_NS_PRIVATE_DEF_SEL(wait,
|
||||||
|
"wait");
|
||||||
|
_NS_PRIVATE_DEF_SEL(waitUntilDate_,
|
||||||
|
"waitUntilDate:");
|
||||||
|
} // Class
|
||||||
|
} // Private
|
||||||
|
} // MTL
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
354
third_party/metal-cpp/Foundation/NSProcessInfo.hpp
vendored
Normal file
354
third_party/metal-cpp/Foundation/NSProcessInfo.hpp
vendored
Normal file
|
@ -0,0 +1,354 @@
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Foundation/NSProcessInfo.hpp
|
||||||
|
//
|
||||||
|
// Copyright 2020-2023 Apple Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "NSDefines.hpp"
|
||||||
|
#include "NSNotification.hpp"
|
||||||
|
#include "NSObject.hpp"
|
||||||
|
#include "NSPrivate.hpp"
|
||||||
|
#include "NSTypes.hpp"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace NS
|
||||||
|
{
|
||||||
|
_NS_CONST(NotificationName, ProcessInfoThermalStateDidChangeNotification);
|
||||||
|
_NS_CONST(NotificationName, ProcessInfoPowerStateDidChangeNotification);
|
||||||
|
|
||||||
|
_NS_ENUM(NS::Integer, ProcessInfoThermalState) {
|
||||||
|
ProcessInfoThermalStateNominal = 0,
|
||||||
|
ProcessInfoThermalStateFair = 1,
|
||||||
|
ProcessInfoThermalStateSerious = 2,
|
||||||
|
ProcessInfoThermalStateCritical = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
_NS_OPTIONS(std::uint64_t, ActivityOptions) {
|
||||||
|
ActivityIdleDisplaySleepDisabled = (1ULL << 40),
|
||||||
|
ActivityIdleSystemSleepDisabled = (1ULL << 20),
|
||||||
|
ActivitySuddenTerminationDisabled = (1ULL << 14),
|
||||||
|
ActivityAutomaticTerminationDisabled = (1ULL << 15),
|
||||||
|
ActivityUserInitiated = (0x00FFFFFFULL | ActivityIdleSystemSleepDisabled),
|
||||||
|
ActivityUserInitiatedAllowingIdleSystemSleep = (ActivityUserInitiated & ~ActivityIdleSystemSleepDisabled),
|
||||||
|
ActivityBackground = 0x000000FFULL,
|
||||||
|
ActivityLatencyCritical = 0xFF00000000ULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
class ProcessInfo : public Referencing<ProcessInfo>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static ProcessInfo* processInfo();
|
||||||
|
|
||||||
|
class Array* arguments() const;
|
||||||
|
class Dictionary* environment() const;
|
||||||
|
class String* hostName() const;
|
||||||
|
class String* processName() const;
|
||||||
|
void setProcessName(const String* pString);
|
||||||
|
int processIdentifier() const;
|
||||||
|
class String* globallyUniqueString() const;
|
||||||
|
|
||||||
|
class String* userName() const;
|
||||||
|
class String* fullUserName() const;
|
||||||
|
|
||||||
|
UInteger operatingSystem() const;
|
||||||
|
OperatingSystemVersion operatingSystemVersion() const;
|
||||||
|
class String* operatingSystemVersionString() const;
|
||||||
|
bool isOperatingSystemAtLeastVersion(OperatingSystemVersion version) const;
|
||||||
|
|
||||||
|
UInteger processorCount() const;
|
||||||
|
UInteger activeProcessorCount() const;
|
||||||
|
unsigned long long physicalMemory() const;
|
||||||
|
TimeInterval systemUptime() const;
|
||||||
|
|
||||||
|
void disableSuddenTermination();
|
||||||
|
void enableSuddenTermination();
|
||||||
|
|
||||||
|
void disableAutomaticTermination(const class String* pReason);
|
||||||
|
void enableAutomaticTermination(const class String* pReason);
|
||||||
|
bool automaticTerminationSupportEnabled() const;
|
||||||
|
void setAutomaticTerminationSupportEnabled(bool enabled);
|
||||||
|
|
||||||
|
class Object* beginActivity(ActivityOptions options, const class String* pReason);
|
||||||
|
void endActivity(class Object* pActivity);
|
||||||
|
void performActivity(ActivityOptions options, const class String* pReason, void (^block)(void));
|
||||||
|
void performActivity(ActivityOptions options, const class String* pReason, const std::function<void()>& func);
|
||||||
|
void performExpiringActivity(const class String* pReason, void (^block)(bool expired));
|
||||||
|
void performExpiringActivity(const class String* pReason, const std::function<void(bool expired)>& func);
|
||||||
|
|
||||||
|
ProcessInfoThermalState thermalState() const;
|
||||||
|
bool isLowPowerModeEnabled() const;
|
||||||
|
|
||||||
|
bool isiOSAppOnMac() const;
|
||||||
|
bool isMacCatalystApp() const;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_PRIVATE_DEF_CONST(NS::NotificationName, ProcessInfoThermalStateDidChangeNotification);
|
||||||
|
_NS_PRIVATE_DEF_CONST(NS::NotificationName, ProcessInfoPowerStateDidChangeNotification);
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::ProcessInfo* NS::ProcessInfo::processInfo()
|
||||||
|
{
|
||||||
|
return Object::sendMessage<ProcessInfo*>(_NS_PRIVATE_CLS(NSProcessInfo), _NS_PRIVATE_SEL(processInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Array* NS::ProcessInfo::arguments() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Array*>(this, _NS_PRIVATE_SEL(arguments));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Dictionary* NS::ProcessInfo::environment() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Dictionary*>(this, _NS_PRIVATE_SEL(environment));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::ProcessInfo::hostName() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<String*>(this, _NS_PRIVATE_SEL(hostName));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::ProcessInfo::processName() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<String*>(this, _NS_PRIVATE_SEL(processName));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE void NS::ProcessInfo::setProcessName(const String* pString)
|
||||||
|
{
|
||||||
|
Object::sendMessage<void>(this, _NS_PRIVATE_SEL(setProcessName_), pString);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE int NS::ProcessInfo::processIdentifier() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<int>(this, _NS_PRIVATE_SEL(processIdentifier));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::ProcessInfo::globallyUniqueString() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<String*>(this, _NS_PRIVATE_SEL(globallyUniqueString));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::ProcessInfo::userName() const
|
||||||
|
{
|
||||||
|
return Object::sendMessageSafe<String*>(this, _NS_PRIVATE_SEL(userName));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::ProcessInfo::fullUserName() const
|
||||||
|
{
|
||||||
|
return Object::sendMessageSafe<String*>(this, _NS_PRIVATE_SEL(fullUserName));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::UInteger NS::ProcessInfo::operatingSystem() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<UInteger>(this, _NS_PRIVATE_SEL(operatingSystem));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::OperatingSystemVersion NS::ProcessInfo::operatingSystemVersion() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<OperatingSystemVersion>(this, _NS_PRIVATE_SEL(operatingSystemVersion));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::ProcessInfo::operatingSystemVersionString() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<String*>(this, _NS_PRIVATE_SEL(operatingSystemVersionString));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE bool NS::ProcessInfo::isOperatingSystemAtLeastVersion(OperatingSystemVersion version) const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<bool>(this, _NS_PRIVATE_SEL(isOperatingSystemAtLeastVersion_), version);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::UInteger NS::ProcessInfo::processorCount() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<UInteger>(this, _NS_PRIVATE_SEL(processorCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::UInteger NS::ProcessInfo::activeProcessorCount() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<UInteger>(this, _NS_PRIVATE_SEL(activeProcessorCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE unsigned long long NS::ProcessInfo::physicalMemory() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<unsigned long long>(this, _NS_PRIVATE_SEL(physicalMemory));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::TimeInterval NS::ProcessInfo::systemUptime() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<TimeInterval>(this, _NS_PRIVATE_SEL(systemUptime));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE void NS::ProcessInfo::disableSuddenTermination()
|
||||||
|
{
|
||||||
|
Object::sendMessageSafe<void>(this, _NS_PRIVATE_SEL(disableSuddenTermination));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE void NS::ProcessInfo::enableSuddenTermination()
|
||||||
|
{
|
||||||
|
Object::sendMessageSafe<void>(this, _NS_PRIVATE_SEL(enableSuddenTermination));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE void NS::ProcessInfo::disableAutomaticTermination(const String* pReason)
|
||||||
|
{
|
||||||
|
Object::sendMessageSafe<void>(this, _NS_PRIVATE_SEL(disableAutomaticTermination_), pReason);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE void NS::ProcessInfo::enableAutomaticTermination(const String* pReason)
|
||||||
|
{
|
||||||
|
Object::sendMessageSafe<void>(this, _NS_PRIVATE_SEL(enableAutomaticTermination_), pReason);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE bool NS::ProcessInfo::automaticTerminationSupportEnabled() const
|
||||||
|
{
|
||||||
|
return Object::sendMessageSafe<bool>(this, _NS_PRIVATE_SEL(automaticTerminationSupportEnabled));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE void NS::ProcessInfo::setAutomaticTerminationSupportEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
Object::sendMessageSafe<void>(this, _NS_PRIVATE_SEL(setAutomaticTerminationSupportEnabled_), enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Object* NS::ProcessInfo::beginActivity(ActivityOptions options, const String* pReason)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Object*>(this, _NS_PRIVATE_SEL(beginActivityWithOptions_reason_), options, pReason);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE void NS::ProcessInfo::endActivity(Object* pActivity)
|
||||||
|
{
|
||||||
|
Object::sendMessage<void>(this, _NS_PRIVATE_SEL(endActivity_), pActivity);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE void NS::ProcessInfo::performActivity(ActivityOptions options, const String* pReason, void (^block)(void))
|
||||||
|
{
|
||||||
|
Object::sendMessage<void>(this, _NS_PRIVATE_SEL(performActivityWithOptions_reason_usingBlock_), options, pReason, block);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE void NS::ProcessInfo::performActivity(ActivityOptions options, const String* pReason, const std::function<void()>& function)
|
||||||
|
{
|
||||||
|
__block std::function<void()> blockFunction = function;
|
||||||
|
|
||||||
|
performActivity(options, pReason, ^() { blockFunction(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE void NS::ProcessInfo::performExpiringActivity(const String* pReason, void (^block)(bool expired))
|
||||||
|
{
|
||||||
|
Object::sendMessageSafe<void>(this, _NS_PRIVATE_SEL(performExpiringActivityWithReason_usingBlock_), pReason, block);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE void NS::ProcessInfo::performExpiringActivity(const String* pReason, const std::function<void(bool expired)>& function)
|
||||||
|
{
|
||||||
|
__block std::function<void(bool expired)> blockFunction = function;
|
||||||
|
|
||||||
|
performExpiringActivity(pReason, ^(bool expired) { blockFunction(expired); });
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::ProcessInfoThermalState NS::ProcessInfo::thermalState() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<ProcessInfoThermalState>(this, _NS_PRIVATE_SEL(thermalState));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE bool NS::ProcessInfo::isLowPowerModeEnabled() const
|
||||||
|
{
|
||||||
|
return Object::sendMessageSafe<bool>(this, _NS_PRIVATE_SEL(isLowPowerModeEnabled));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE bool NS::ProcessInfo::isiOSAppOnMac() const
|
||||||
|
{
|
||||||
|
return Object::sendMessageSafe<bool>(this, _NS_PRIVATE_SEL(isiOSAppOnMac));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE bool NS::ProcessInfo::isMacCatalystApp() const
|
||||||
|
{
|
||||||
|
return Object::sendMessageSafe<bool>(this, _NS_PRIVATE_SEL(isMacCatalystApp));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
83
third_party/metal-cpp/Foundation/NSRange.hpp
vendored
Normal file
83
third_party/metal-cpp/Foundation/NSRange.hpp
vendored
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Foundation/NSRange.hpp
|
||||||
|
//
|
||||||
|
// Copyright 2020-2023 Apple Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "NSDefines.hpp"
|
||||||
|
#include "NSTypes.hpp"
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace NS
|
||||||
|
{
|
||||||
|
struct Range
|
||||||
|
{
|
||||||
|
static Range Make(UInteger loc, UInteger len);
|
||||||
|
|
||||||
|
Range(UInteger loc, UInteger len);
|
||||||
|
|
||||||
|
bool Equal(const Range& range) const;
|
||||||
|
bool LocationInRange(UInteger loc) const;
|
||||||
|
UInteger Max() const;
|
||||||
|
|
||||||
|
UInteger location;
|
||||||
|
UInteger length;
|
||||||
|
} _NS_PACKED;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Range::Range(UInteger loc, UInteger len)
|
||||||
|
: location(loc)
|
||||||
|
, length(len)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Range NS::Range::Make(UInteger loc, UInteger len)
|
||||||
|
{
|
||||||
|
return Range(loc, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE bool NS::Range::Equal(const Range& range) const
|
||||||
|
{
|
||||||
|
return (location == range.location) && (length == range.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE bool NS::Range::LocationInRange(UInteger loc) const
|
||||||
|
{
|
||||||
|
return (!(loc < location)) && ((loc - location) < length);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::UInteger NS::Range::Max() const
|
||||||
|
{
|
||||||
|
return location + length;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
87
third_party/metal-cpp/Foundation/NSSet.hpp
vendored
Normal file
87
third_party/metal-cpp/Foundation/NSSet.hpp
vendored
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Foundation/NSSet.hpp
|
||||||
|
//
|
||||||
|
// Copyright 2020-2023 Apple Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "NSObject.hpp"
|
||||||
|
#include "NSEnumerator.hpp"
|
||||||
|
|
||||||
|
/*****Immutable Set*******/
|
||||||
|
|
||||||
|
namespace NS
|
||||||
|
{
|
||||||
|
class Set : public NS::Copying <Set>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UInteger count() const;
|
||||||
|
Enumerator<Object>* objectEnumerator() const;
|
||||||
|
|
||||||
|
static Set* alloc();
|
||||||
|
|
||||||
|
Set* init();
|
||||||
|
Set* init(const Object* const* pObjects, UInteger count);
|
||||||
|
Set* init(const class Coder* pCoder);
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::UInteger NS::Set::count() const
|
||||||
|
{
|
||||||
|
return NS::Object::sendMessage<NS::UInteger>(this, _NS_PRIVATE_SEL(count));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Enumerator<NS::Object>* NS::Set::objectEnumerator() const
|
||||||
|
{
|
||||||
|
return NS::Object::sendMessage<Enumerator<NS::Object>*>(this, _NS_PRIVATE_SEL(objectEnumerator));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Set* NS::Set::alloc()
|
||||||
|
{
|
||||||
|
return NS::Object::alloc<Set>(_NS_PRIVATE_CLS(NSSet));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Set* NS::Set::init()
|
||||||
|
{
|
||||||
|
return NS::Object::init<Set>();
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Set* NS::Set::init(const Object* const* pObjects, NS::UInteger count)
|
||||||
|
{
|
||||||
|
return NS::Object::sendMessage<Set*>(this, _NS_PRIVATE_SEL(initWithObjects_count_), pObjects, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Set* NS::Set::init(const class Coder* pCoder)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Set*>(this, _NS_PRIVATE_SEL(initWithCoder_), pCoder);
|
||||||
|
}
|
311
third_party/metal-cpp/Foundation/NSSharedPtr.hpp
vendored
Normal file
311
third_party/metal-cpp/Foundation/NSSharedPtr.hpp
vendored
Normal file
|
@ -0,0 +1,311 @@
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Foundation/NSSharedPtr.hpp
|
||||||
|
//
|
||||||
|
// Copyright 2020-2023 Apple Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "NSDefines.hpp"
|
||||||
|
|
||||||
|
namespace NS
|
||||||
|
{
|
||||||
|
template <class _Class>
|
||||||
|
class SharedPtr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Create a new null pointer.
|
||||||
|
*/
|
||||||
|
SharedPtr();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy this SharedPtr, decreasing the reference count.
|
||||||
|
*/
|
||||||
|
~SharedPtr();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SharedPtr copy constructor.
|
||||||
|
*/
|
||||||
|
SharedPtr(const SharedPtr<_Class>& other) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construction from another pointee type.
|
||||||
|
*/
|
||||||
|
template <class _OtherClass>
|
||||||
|
SharedPtr(const SharedPtr<_OtherClass>& other, typename std::enable_if_t<std::is_convertible_v<_OtherClass *, _Class *>> * = nullptr) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SharedPtr move constructor.
|
||||||
|
*/
|
||||||
|
SharedPtr(SharedPtr<_Class>&& other) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move from another pointee type.
|
||||||
|
*/
|
||||||
|
template <class _OtherClass>
|
||||||
|
SharedPtr(SharedPtr<_OtherClass>&& other, typename std::enable_if_t<std::is_convertible_v<_OtherClass *, _Class *>> * = nullptr) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy assignment operator.
|
||||||
|
* Copying increases reference count. Only releases previous pointee if objects are different.
|
||||||
|
*/
|
||||||
|
SharedPtr& operator=(const SharedPtr<_Class>& other);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy-assignment from different pointee.
|
||||||
|
* Copying increases reference count. Only releases previous pointee if objects are different.
|
||||||
|
*/
|
||||||
|
template <class _OtherClass>
|
||||||
|
typename std::enable_if_t<std::is_convertible_v<_OtherClass *, _Class *>, SharedPtr &>
|
||||||
|
operator=(const SharedPtr<_OtherClass>& other);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move assignment operator.
|
||||||
|
* Move without affecting reference counts, unless pointees are equal. Moved-from object is reset to nullptr.
|
||||||
|
*/
|
||||||
|
SharedPtr& operator=(SharedPtr<_Class>&& other);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move-asignment from different pointee.
|
||||||
|
* Move without affecting reference counts, unless pointees are equal. Moved-from object is reset to nullptr.
|
||||||
|
*/
|
||||||
|
template <class _OtherClass>
|
||||||
|
typename std::enable_if_t<std::is_convertible_v<_OtherClass *, _Class *>, SharedPtr &>
|
||||||
|
operator=(SharedPtr<_OtherClass>&& other);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Access raw pointee.
|
||||||
|
* @warning Avoid wrapping the returned value again, as it may lead double frees unless this object becomes detached.
|
||||||
|
*/
|
||||||
|
_Class* get() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call operations directly on the pointee.
|
||||||
|
*/
|
||||||
|
_Class* operator->() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implicit cast to bool.
|
||||||
|
*/
|
||||||
|
explicit operator bool() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset this SharedPtr to null, decreasing the reference count.
|
||||||
|
*/
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detach the SharedPtr from the pointee, without decreasing the reference count.
|
||||||
|
*/
|
||||||
|
void detach();
|
||||||
|
|
||||||
|
template <class _OtherClass>
|
||||||
|
friend SharedPtr<_OtherClass> RetainPtr(_OtherClass* ptr);
|
||||||
|
|
||||||
|
template <class _OtherClass>
|
||||||
|
friend SharedPtr<_OtherClass> TransferPtr(_OtherClass* ptr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
_Class* m_pObject;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a SharedPtr by retaining an existing raw pointer.
|
||||||
|
* Increases the reference count of the passed-in object.
|
||||||
|
* If the passed-in object was in an AutoreleasePool, it will be removed from it.
|
||||||
|
*/
|
||||||
|
template <class _Class>
|
||||||
|
_NS_INLINE NS::SharedPtr<_Class> RetainPtr(_Class* pObject)
|
||||||
|
{
|
||||||
|
NS::SharedPtr<_Class> ret;
|
||||||
|
ret.m_pObject = pObject->retain();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a SharedPtr by transfering the ownership of an existing raw pointer to SharedPtr.
|
||||||
|
* Does not increase the reference count of the passed-in pointer, it is assumed to be >= 1.
|
||||||
|
* This method does not remove objects from an AutoreleasePool.
|
||||||
|
*/
|
||||||
|
template <class _Class>
|
||||||
|
_NS_INLINE NS::SharedPtr<_Class> TransferPtr(_Class* pObject)
|
||||||
|
{
|
||||||
|
NS::SharedPtr<_Class> ret;
|
||||||
|
ret.m_pObject = pObject;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class _Class>
|
||||||
|
_NS_INLINE NS::SharedPtr<_Class>::SharedPtr()
|
||||||
|
: m_pObject(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class _Class>
|
||||||
|
_NS_INLINE NS::SharedPtr<_Class>::~SharedPtr<_Class>()
|
||||||
|
{
|
||||||
|
if (m_pObject)
|
||||||
|
{
|
||||||
|
m_pObject->release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class _Class>
|
||||||
|
_NS_INLINE NS::SharedPtr<_Class>::SharedPtr(const NS::SharedPtr<_Class>& other) noexcept
|
||||||
|
: m_pObject(other.m_pObject->retain())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class _Class>
|
||||||
|
template <class _OtherClass>
|
||||||
|
_NS_INLINE NS::SharedPtr<_Class>::SharedPtr(const NS::SharedPtr<_OtherClass>& other, typename std::enable_if_t<std::is_convertible_v<_OtherClass *, _Class *>> *) noexcept
|
||||||
|
: m_pObject(reinterpret_cast<_Class*>(other.get()->retain()))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class _Class>
|
||||||
|
_NS_INLINE NS::SharedPtr<_Class>::SharedPtr(NS::SharedPtr<_Class>&& other) noexcept
|
||||||
|
: m_pObject(other.m_pObject)
|
||||||
|
{
|
||||||
|
other.m_pObject = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class _Class>
|
||||||
|
template <class _OtherClass>
|
||||||
|
_NS_INLINE NS::SharedPtr<_Class>::SharedPtr(NS::SharedPtr<_OtherClass>&& other, typename std::enable_if_t<std::is_convertible_v<_OtherClass *, _Class *>> *) noexcept
|
||||||
|
: m_pObject(reinterpret_cast<_Class*>(other.get()))
|
||||||
|
{
|
||||||
|
other.detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class _Class>
|
||||||
|
_NS_INLINE _Class* NS::SharedPtr<_Class>::get() const
|
||||||
|
{
|
||||||
|
return m_pObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class _Class>
|
||||||
|
_NS_INLINE _Class* NS::SharedPtr<_Class>::operator->() const
|
||||||
|
{
|
||||||
|
return m_pObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class _Class>
|
||||||
|
_NS_INLINE NS::SharedPtr<_Class>::operator bool() const
|
||||||
|
{
|
||||||
|
return nullptr != m_pObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class _Class>
|
||||||
|
_NS_INLINE void NS::SharedPtr<_Class>::reset()
|
||||||
|
{
|
||||||
|
m_pObject->release();
|
||||||
|
m_pObject = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class _Class>
|
||||||
|
_NS_INLINE void NS::SharedPtr<_Class>::detach()
|
||||||
|
{
|
||||||
|
m_pObject = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class _Class>
|
||||||
|
_NS_INLINE NS::SharedPtr<_Class>& NS::SharedPtr<_Class>::operator=(const SharedPtr<_Class>& other)
|
||||||
|
{
|
||||||
|
if (m_pObject != other.m_pObject)
|
||||||
|
{
|
||||||
|
if (m_pObject)
|
||||||
|
{
|
||||||
|
m_pObject->release();
|
||||||
|
}
|
||||||
|
m_pObject = other.m_pObject->retain();
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class _Class>
|
||||||
|
template <class _OtherClass>
|
||||||
|
typename std::enable_if_t<std::is_convertible_v<_OtherClass *, _Class *>, NS::SharedPtr<_Class> &>
|
||||||
|
_NS_INLINE NS::SharedPtr<_Class>::operator=(const SharedPtr<_OtherClass>& other)
|
||||||
|
{
|
||||||
|
if (m_pObject != other.get())
|
||||||
|
{
|
||||||
|
if (m_pObject)
|
||||||
|
{
|
||||||
|
m_pObject->release();
|
||||||
|
}
|
||||||
|
m_pObject = reinterpret_cast<_Class*>(other.get()->retain());
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class _Class>
|
||||||
|
_NS_INLINE NS::SharedPtr<_Class>& NS::SharedPtr<_Class>::operator=(SharedPtr<_Class>&& other)
|
||||||
|
{
|
||||||
|
if (m_pObject != other.m_pObject)
|
||||||
|
{
|
||||||
|
if (m_pObject)
|
||||||
|
{
|
||||||
|
m_pObject->release();
|
||||||
|
}
|
||||||
|
m_pObject = other.m_pObject;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_pObject = other.m_pObject;
|
||||||
|
other.m_pObject->release();
|
||||||
|
}
|
||||||
|
other.m_pObject = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class _Class>
|
||||||
|
template <class _OtherClass>
|
||||||
|
typename std::enable_if_t<std::is_convertible_v<_OtherClass *, _Class *>, NS::SharedPtr<_Class> &>
|
||||||
|
_NS_INLINE NS::SharedPtr<_Class>::operator=(SharedPtr<_OtherClass>&& other)
|
||||||
|
{
|
||||||
|
if (m_pObject != other.get())
|
||||||
|
{
|
||||||
|
if (m_pObject)
|
||||||
|
{
|
||||||
|
m_pObject->release();
|
||||||
|
}
|
||||||
|
m_pObject = reinterpret_cast<_Class*>(other.get());
|
||||||
|
other.detach();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_pObject = other.get();
|
||||||
|
other.reset();
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class _ClassLhs, class _ClassRhs>
|
||||||
|
_NS_INLINE bool operator==(const NS::SharedPtr<_ClassLhs>& lhs, const NS::SharedPtr<_ClassRhs>& rhs)
|
||||||
|
{
|
||||||
|
return lhs.get() == rhs.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class _ClassLhs, class _ClassRhs>
|
||||||
|
_NS_INLINE bool operator!=(const NS::SharedPtr<_ClassLhs>& lhs, const NS::SharedPtr<_ClassRhs>& rhs)
|
||||||
|
{
|
||||||
|
return lhs.get() != rhs.get();
|
||||||
|
}
|
255
third_party/metal-cpp/Foundation/NSString.hpp
vendored
Normal file
255
third_party/metal-cpp/Foundation/NSString.hpp
vendored
Normal file
|
@ -0,0 +1,255 @@
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Foundation/NSString.hpp
|
||||||
|
//
|
||||||
|
// Copyright 2020-2023 Apple Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "NSDefines.hpp"
|
||||||
|
#include "NSObjCRuntime.hpp"
|
||||||
|
#include "NSObject.hpp"
|
||||||
|
#include "NSPrivate.hpp"
|
||||||
|
#include "NSRange.hpp"
|
||||||
|
#include "NSTypes.hpp"
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace NS
|
||||||
|
{
|
||||||
|
_NS_ENUM(NS::UInteger, StringEncoding) {
|
||||||
|
ASCIIStringEncoding = 1,
|
||||||
|
NEXTSTEPStringEncoding = 2,
|
||||||
|
JapaneseEUCStringEncoding = 3,
|
||||||
|
UTF8StringEncoding = 4,
|
||||||
|
ISOLatin1StringEncoding = 5,
|
||||||
|
SymbolStringEncoding = 6,
|
||||||
|
NonLossyASCIIStringEncoding = 7,
|
||||||
|
ShiftJISStringEncoding = 8,
|
||||||
|
ISOLatin2StringEncoding = 9,
|
||||||
|
UnicodeStringEncoding = 10,
|
||||||
|
WindowsCP1251StringEncoding = 11,
|
||||||
|
WindowsCP1252StringEncoding = 12,
|
||||||
|
WindowsCP1253StringEncoding = 13,
|
||||||
|
WindowsCP1254StringEncoding = 14,
|
||||||
|
WindowsCP1250StringEncoding = 15,
|
||||||
|
ISO2022JPStringEncoding = 21,
|
||||||
|
MacOSRomanStringEncoding = 30,
|
||||||
|
|
||||||
|
UTF16StringEncoding = UnicodeStringEncoding,
|
||||||
|
|
||||||
|
UTF16BigEndianStringEncoding = 0x90000100,
|
||||||
|
UTF16LittleEndianStringEncoding = 0x94000100,
|
||||||
|
|
||||||
|
UTF32StringEncoding = 0x8c000100,
|
||||||
|
UTF32BigEndianStringEncoding = 0x98000100,
|
||||||
|
UTF32LittleEndianStringEncoding = 0x9c000100
|
||||||
|
};
|
||||||
|
|
||||||
|
_NS_OPTIONS(NS::UInteger, StringCompareOptions) {
|
||||||
|
CaseInsensitiveSearch = 1,
|
||||||
|
LiteralSearch = 2,
|
||||||
|
BackwardsSearch = 4,
|
||||||
|
AnchoredSearch = 8,
|
||||||
|
NumericSearch = 64,
|
||||||
|
DiacriticInsensitiveSearch = 128,
|
||||||
|
WidthInsensitiveSearch = 256,
|
||||||
|
ForcedOrderingSearch = 512,
|
||||||
|
RegularExpressionSearch = 1024
|
||||||
|
};
|
||||||
|
|
||||||
|
using unichar = unsigned short;
|
||||||
|
|
||||||
|
class String : public Copying<String>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static String* string();
|
||||||
|
static String* string(const String* pString);
|
||||||
|
static String* string(const char* pString, StringEncoding encoding);
|
||||||
|
|
||||||
|
static String* alloc();
|
||||||
|
String* init();
|
||||||
|
String* init(const String* pString);
|
||||||
|
String* init(const char* pString, StringEncoding encoding);
|
||||||
|
String* init(void* pBytes, UInteger len, StringEncoding encoding, bool freeBuffer);
|
||||||
|
|
||||||
|
unichar character(UInteger index) const;
|
||||||
|
UInteger length() const;
|
||||||
|
|
||||||
|
const char* cString(StringEncoding encoding) const;
|
||||||
|
const char* utf8String() const;
|
||||||
|
UInteger maximumLengthOfBytes(StringEncoding encoding) const;
|
||||||
|
UInteger lengthOfBytes(StringEncoding encoding) const;
|
||||||
|
|
||||||
|
bool isEqualToString(const String* pString) const;
|
||||||
|
Range rangeOfString(const String* pString, StringCompareOptions options) const;
|
||||||
|
|
||||||
|
const char* fileSystemRepresentation() const;
|
||||||
|
|
||||||
|
String* stringByAppendingString(const String* pString) const;
|
||||||
|
ComparisonResult caseInsensitiveCompare(const String* pString) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Create an NS::String* from a string literal.
|
||||||
|
#define MTLSTR(literal) (NS::String*)__builtin___CFStringMakeConstantString("" literal "")
|
||||||
|
|
||||||
|
template <std::size_t _StringLen>
|
||||||
|
[[deprecated("please use MTLSTR(str)")]] constexpr const String* MakeConstantString(const char (&str)[_StringLen])
|
||||||
|
{
|
||||||
|
return reinterpret_cast<const String*>(__CFStringMakeConstantString(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::String::string()
|
||||||
|
{
|
||||||
|
return Object::sendMessage<String*>(_NS_PRIVATE_CLS(NSString), _NS_PRIVATE_SEL(string));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::String::string(const String* pString)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<String*>(_NS_PRIVATE_CLS(NSString), _NS_PRIVATE_SEL(stringWithString_), pString);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::String::string(const char* pString, StringEncoding encoding)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<String*>(_NS_PRIVATE_CLS(NSString), _NS_PRIVATE_SEL(stringWithCString_encoding_), pString, encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::String::alloc()
|
||||||
|
{
|
||||||
|
return Object::alloc<String>(_NS_PRIVATE_CLS(NSString));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::String::init()
|
||||||
|
{
|
||||||
|
return Object::init<String>();
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::String::init(const String* pString)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<String*>(this, _NS_PRIVATE_SEL(initWithString_), pString);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::String::init(const char* pString, StringEncoding encoding)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<String*>(this, _NS_PRIVATE_SEL(initWithCString_encoding_), pString, encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::String::init(void* pBytes, UInteger len, StringEncoding encoding, bool freeBuffer)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<String*>(this, _NS_PRIVATE_SEL(initWithBytesNoCopy_length_encoding_freeWhenDone_), pBytes, len, encoding, freeBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::unichar NS::String::character(UInteger index) const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<unichar>(this, _NS_PRIVATE_SEL(characterAtIndex_), index);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::UInteger NS::String::length() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<UInteger>(this, _NS_PRIVATE_SEL(length));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE const char* NS::String::cString(StringEncoding encoding) const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<const char*>(this, _NS_PRIVATE_SEL(cStringUsingEncoding_), encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE const char* NS::String::utf8String() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<const char*>(this, _NS_PRIVATE_SEL(UTF8String));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::UInteger NS::String::maximumLengthOfBytes(StringEncoding encoding) const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<UInteger>(this, _NS_PRIVATE_SEL(maximumLengthOfBytesUsingEncoding_), encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::UInteger NS::String::lengthOfBytes(StringEncoding encoding) const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<UInteger>(this, _NS_PRIVATE_SEL(lengthOfBytesUsingEncoding_), encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE bool NS::String::isEqualToString(const NS::String* pString) const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<bool>(this, _NS_PRIVATE_SEL(isEqualToString_), pString);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::Range NS::String::rangeOfString(const NS::String* pString, NS::StringCompareOptions options) const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<Range>(this, _NS_PRIVATE_SEL(rangeOfString_options_), pString, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE const char* NS::String::fileSystemRepresentation() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<const char*>(this, _NS_PRIVATE_SEL(fileSystemRepresentation));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::String* NS::String::stringByAppendingString(const String* pString) const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::String*>(this, _NS_PRIVATE_SEL(stringByAppendingString_), pString);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::ComparisonResult NS::String::caseInsensitiveCompare(const String* pString) const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::ComparisonResult>(this, _NS_PRIVATE_SEL(caseInsensitiveCompare_), pString);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
51
third_party/metal-cpp/Foundation/NSTypes.hpp
vendored
Normal file
51
third_party/metal-cpp/Foundation/NSTypes.hpp
vendored
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Foundation/NSTypes.hpp
|
||||||
|
//
|
||||||
|
// Copyright 2020-2023 Apple Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "NSDefines.hpp"
|
||||||
|
|
||||||
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace NS
|
||||||
|
{
|
||||||
|
using TimeInterval = double;
|
||||||
|
|
||||||
|
using Integer = std::intptr_t;
|
||||||
|
using UInteger = std::uintptr_t;
|
||||||
|
|
||||||
|
const Integer IntegerMax = INTPTR_MAX;
|
||||||
|
const Integer IntegerMin = INTPTR_MIN;
|
||||||
|
const UInteger UIntegerMax = UINTPTR_MAX;
|
||||||
|
|
||||||
|
struct OperatingSystemVersion
|
||||||
|
{
|
||||||
|
Integer majorVersion;
|
||||||
|
Integer minorVersion;
|
||||||
|
Integer patchVersion;
|
||||||
|
} _NS_PACKED;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
90
third_party/metal-cpp/Foundation/NSURL.hpp
vendored
Normal file
90
third_party/metal-cpp/Foundation/NSURL.hpp
vendored
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Foundation/NSURL.hpp
|
||||||
|
//
|
||||||
|
// Copyright 2020-2023 Apple Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "NSDefines.hpp"
|
||||||
|
#include "NSObject.hpp"
|
||||||
|
#include "NSPrivate.hpp"
|
||||||
|
#include "NSTypes.hpp"
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace NS
|
||||||
|
{
|
||||||
|
class URL : public Copying<URL>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static URL* fileURLWithPath(const class String* pPath);
|
||||||
|
|
||||||
|
static URL* alloc();
|
||||||
|
URL* init();
|
||||||
|
URL* init(const class String* pString);
|
||||||
|
URL* initFileURLWithPath(const class String* pPath);
|
||||||
|
|
||||||
|
const char* fileSystemRepresentation() const;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::URL* NS::URL::fileURLWithPath(const String* pPath)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<URL*>(_NS_PRIVATE_CLS(NSURL), _NS_PRIVATE_SEL(fileURLWithPath_), pPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::URL* NS::URL::alloc()
|
||||||
|
{
|
||||||
|
return Object::alloc<URL>(_NS_PRIVATE_CLS(NSURL));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::URL* NS::URL::init()
|
||||||
|
{
|
||||||
|
return Object::init<URL>();
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::URL* NS::URL::init(const String* pString)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<URL*>(this, _NS_PRIVATE_SEL(initWithString_), pString);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE NS::URL* NS::URL::initFileURLWithPath(const String* pPath)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<URL*>(this, _NS_PRIVATE_SEL(initFileURLWithPath_), pPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_NS_INLINE const char* NS::URL::fileSystemRepresentation() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<const char*>(this, _NS_PRIVATE_SEL(fileSystemRepresentation));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
202
third_party/metal-cpp/LICENSE.txt
vendored
Normal file
202
third_party/metal-cpp/LICENSE.txt
vendored
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright © 2023 Apple Inc.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
1826
third_party/metal-cpp/Metal/MTLAccelerationStructure.hpp
vendored
Normal file
1826
third_party/metal-cpp/Metal/MTLAccelerationStructure.hpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
290
third_party/metal-cpp/Metal/MTLAccelerationStructureCommandEncoder.hpp
vendored
Normal file
290
third_party/metal-cpp/Metal/MTLAccelerationStructureCommandEncoder.hpp
vendored
Normal file
|
@ -0,0 +1,290 @@
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Metal/MTLAccelerationStructureCommandEncoder.hpp
|
||||||
|
//
|
||||||
|
// Copyright 2020-2023 Apple Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "MTLDefines.hpp"
|
||||||
|
#include "MTLHeaderBridge.hpp"
|
||||||
|
#include "MTLPrivate.hpp"
|
||||||
|
|
||||||
|
#include <Foundation/Foundation.hpp>
|
||||||
|
|
||||||
|
#include "MTLAccelerationStructureCommandEncoder.hpp"
|
||||||
|
#include "MTLArgument.hpp"
|
||||||
|
#include "MTLCommandEncoder.hpp"
|
||||||
|
|
||||||
|
namespace MTL
|
||||||
|
{
|
||||||
|
_MTL_OPTIONS(NS::UInteger, AccelerationStructureRefitOptions) {
|
||||||
|
AccelerationStructureRefitOptionVertexData = 1,
|
||||||
|
AccelerationStructureRefitOptionPerPrimitiveData = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
class AccelerationStructureCommandEncoder : public NS::Referencing<AccelerationStructureCommandEncoder, CommandEncoder>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void buildAccelerationStructure(const class AccelerationStructure* accelerationStructure, const class AccelerationStructureDescriptor* descriptor, const class Buffer* scratchBuffer, NS::UInteger scratchBufferOffset);
|
||||||
|
|
||||||
|
void refitAccelerationStructure(const class AccelerationStructure* sourceAccelerationStructure, const class AccelerationStructureDescriptor* descriptor, const class AccelerationStructure* destinationAccelerationStructure, const class Buffer* scratchBuffer, NS::UInteger scratchBufferOffset);
|
||||||
|
|
||||||
|
void refitAccelerationStructure(const class AccelerationStructure* sourceAccelerationStructure, const class AccelerationStructureDescriptor* descriptor, const class AccelerationStructure* destinationAccelerationStructure, const class Buffer* scratchBuffer, NS::UInteger scratchBufferOffset, MTL::AccelerationStructureRefitOptions options);
|
||||||
|
|
||||||
|
void copyAccelerationStructure(const class AccelerationStructure* sourceAccelerationStructure, const class AccelerationStructure* destinationAccelerationStructure);
|
||||||
|
|
||||||
|
void writeCompactedAccelerationStructureSize(const class AccelerationStructure* accelerationStructure, const class Buffer* buffer, NS::UInteger offset);
|
||||||
|
|
||||||
|
void writeCompactedAccelerationStructureSize(const class AccelerationStructure* accelerationStructure, const class Buffer* buffer, NS::UInteger offset, MTL::DataType sizeDataType);
|
||||||
|
|
||||||
|
void copyAndCompactAccelerationStructure(const class AccelerationStructure* sourceAccelerationStructure, const class AccelerationStructure* destinationAccelerationStructure);
|
||||||
|
|
||||||
|
void updateFence(const class Fence* fence);
|
||||||
|
|
||||||
|
void waitForFence(const class Fence* fence);
|
||||||
|
|
||||||
|
void useResource(const class Resource* resource, MTL::ResourceUsage usage);
|
||||||
|
|
||||||
|
void useResources(const class Resource* const resources[], NS::UInteger count, MTL::ResourceUsage usage);
|
||||||
|
|
||||||
|
void useHeap(const class Heap* heap);
|
||||||
|
|
||||||
|
void useHeaps(const class Heap* const heaps[], NS::UInteger count);
|
||||||
|
|
||||||
|
void sampleCountersInBuffer(const class CounterSampleBuffer* sampleBuffer, NS::UInteger sampleIndex, bool barrier);
|
||||||
|
};
|
||||||
|
|
||||||
|
class AccelerationStructurePassSampleBufferAttachmentDescriptor : public NS::Copying<AccelerationStructurePassSampleBufferAttachmentDescriptor>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static class AccelerationStructurePassSampleBufferAttachmentDescriptor* alloc();
|
||||||
|
|
||||||
|
class AccelerationStructurePassSampleBufferAttachmentDescriptor* init();
|
||||||
|
|
||||||
|
class CounterSampleBuffer* sampleBuffer() const;
|
||||||
|
void setSampleBuffer(const class CounterSampleBuffer* sampleBuffer);
|
||||||
|
|
||||||
|
NS::UInteger startOfEncoderSampleIndex() const;
|
||||||
|
void setStartOfEncoderSampleIndex(NS::UInteger startOfEncoderSampleIndex);
|
||||||
|
|
||||||
|
NS::UInteger endOfEncoderSampleIndex() const;
|
||||||
|
void setEndOfEncoderSampleIndex(NS::UInteger endOfEncoderSampleIndex);
|
||||||
|
};
|
||||||
|
|
||||||
|
class AccelerationStructurePassSampleBufferAttachmentDescriptorArray : public NS::Referencing<AccelerationStructurePassSampleBufferAttachmentDescriptorArray>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static class AccelerationStructurePassSampleBufferAttachmentDescriptorArray* alloc();
|
||||||
|
|
||||||
|
class AccelerationStructurePassSampleBufferAttachmentDescriptorArray* init();
|
||||||
|
|
||||||
|
class AccelerationStructurePassSampleBufferAttachmentDescriptor* object(NS::UInteger attachmentIndex);
|
||||||
|
|
||||||
|
void setObject(const class AccelerationStructurePassSampleBufferAttachmentDescriptor* attachment, NS::UInteger attachmentIndex);
|
||||||
|
};
|
||||||
|
|
||||||
|
class AccelerationStructurePassDescriptor : public NS::Copying<AccelerationStructurePassDescriptor>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static class AccelerationStructurePassDescriptor* alloc();
|
||||||
|
|
||||||
|
class AccelerationStructurePassDescriptor* init();
|
||||||
|
|
||||||
|
static class AccelerationStructurePassDescriptor* accelerationStructurePassDescriptor();
|
||||||
|
|
||||||
|
class AccelerationStructurePassSampleBufferAttachmentDescriptorArray* sampleBufferAttachments() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: buildAccelerationStructure:descriptor:scratchBuffer:scratchBufferOffset:
|
||||||
|
_MTL_INLINE void MTL::AccelerationStructureCommandEncoder::buildAccelerationStructure(const MTL::AccelerationStructure* accelerationStructure, const MTL::AccelerationStructureDescriptor* descriptor, const MTL::Buffer* scratchBuffer, NS::UInteger scratchBufferOffset)
|
||||||
|
{
|
||||||
|
Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(buildAccelerationStructure_descriptor_scratchBuffer_scratchBufferOffset_), accelerationStructure, descriptor, scratchBuffer, scratchBufferOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: refitAccelerationStructure:descriptor:destination:scratchBuffer:scratchBufferOffset:
|
||||||
|
_MTL_INLINE void MTL::AccelerationStructureCommandEncoder::refitAccelerationStructure(const MTL::AccelerationStructure* sourceAccelerationStructure, const MTL::AccelerationStructureDescriptor* descriptor, const MTL::AccelerationStructure* destinationAccelerationStructure, const MTL::Buffer* scratchBuffer, NS::UInteger scratchBufferOffset)
|
||||||
|
{
|
||||||
|
Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(refitAccelerationStructure_descriptor_destination_scratchBuffer_scratchBufferOffset_), sourceAccelerationStructure, descriptor, destinationAccelerationStructure, scratchBuffer, scratchBufferOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: refitAccelerationStructure:descriptor:destination:scratchBuffer:scratchBufferOffset:options:
|
||||||
|
_MTL_INLINE void MTL::AccelerationStructureCommandEncoder::refitAccelerationStructure(const MTL::AccelerationStructure* sourceAccelerationStructure, const MTL::AccelerationStructureDescriptor* descriptor, const MTL::AccelerationStructure* destinationAccelerationStructure, const MTL::Buffer* scratchBuffer, NS::UInteger scratchBufferOffset, MTL::AccelerationStructureRefitOptions options)
|
||||||
|
{
|
||||||
|
Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(refitAccelerationStructure_descriptor_destination_scratchBuffer_scratchBufferOffset_options_), sourceAccelerationStructure, descriptor, destinationAccelerationStructure, scratchBuffer, scratchBufferOffset, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: copyAccelerationStructure:toAccelerationStructure:
|
||||||
|
_MTL_INLINE void MTL::AccelerationStructureCommandEncoder::copyAccelerationStructure(const MTL::AccelerationStructure* sourceAccelerationStructure, const MTL::AccelerationStructure* destinationAccelerationStructure)
|
||||||
|
{
|
||||||
|
Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(copyAccelerationStructure_toAccelerationStructure_), sourceAccelerationStructure, destinationAccelerationStructure);
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: writeCompactedAccelerationStructureSize:toBuffer:offset:
|
||||||
|
_MTL_INLINE void MTL::AccelerationStructureCommandEncoder::writeCompactedAccelerationStructureSize(const MTL::AccelerationStructure* accelerationStructure, const MTL::Buffer* buffer, NS::UInteger offset)
|
||||||
|
{
|
||||||
|
Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(writeCompactedAccelerationStructureSize_toBuffer_offset_), accelerationStructure, buffer, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: writeCompactedAccelerationStructureSize:toBuffer:offset:sizeDataType:
|
||||||
|
_MTL_INLINE void MTL::AccelerationStructureCommandEncoder::writeCompactedAccelerationStructureSize(const MTL::AccelerationStructure* accelerationStructure, const MTL::Buffer* buffer, NS::UInteger offset, MTL::DataType sizeDataType)
|
||||||
|
{
|
||||||
|
Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(writeCompactedAccelerationStructureSize_toBuffer_offset_sizeDataType_), accelerationStructure, buffer, offset, sizeDataType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: copyAndCompactAccelerationStructure:toAccelerationStructure:
|
||||||
|
_MTL_INLINE void MTL::AccelerationStructureCommandEncoder::copyAndCompactAccelerationStructure(const MTL::AccelerationStructure* sourceAccelerationStructure, const MTL::AccelerationStructure* destinationAccelerationStructure)
|
||||||
|
{
|
||||||
|
Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(copyAndCompactAccelerationStructure_toAccelerationStructure_), sourceAccelerationStructure, destinationAccelerationStructure);
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: updateFence:
|
||||||
|
_MTL_INLINE void MTL::AccelerationStructureCommandEncoder::updateFence(const MTL::Fence* fence)
|
||||||
|
{
|
||||||
|
Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(updateFence_), fence);
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: waitForFence:
|
||||||
|
_MTL_INLINE void MTL::AccelerationStructureCommandEncoder::waitForFence(const MTL::Fence* fence)
|
||||||
|
{
|
||||||
|
Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(waitForFence_), fence);
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: useResource:usage:
|
||||||
|
_MTL_INLINE void MTL::AccelerationStructureCommandEncoder::useResource(const MTL::Resource* resource, MTL::ResourceUsage usage)
|
||||||
|
{
|
||||||
|
Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(useResource_usage_), resource, usage);
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: useResources:count:usage:
|
||||||
|
_MTL_INLINE void MTL::AccelerationStructureCommandEncoder::useResources(const MTL::Resource* const resources[], NS::UInteger count, MTL::ResourceUsage usage)
|
||||||
|
{
|
||||||
|
Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(useResources_count_usage_), resources, count, usage);
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: useHeap:
|
||||||
|
_MTL_INLINE void MTL::AccelerationStructureCommandEncoder::useHeap(const MTL::Heap* heap)
|
||||||
|
{
|
||||||
|
Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(useHeap_), heap);
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: useHeaps:count:
|
||||||
|
_MTL_INLINE void MTL::AccelerationStructureCommandEncoder::useHeaps(const MTL::Heap* const heaps[], NS::UInteger count)
|
||||||
|
{
|
||||||
|
Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(useHeaps_count_), heaps, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: sampleCountersInBuffer:atSampleIndex:withBarrier:
|
||||||
|
_MTL_INLINE void MTL::AccelerationStructureCommandEncoder::sampleCountersInBuffer(const MTL::CounterSampleBuffer* sampleBuffer, NS::UInteger sampleIndex, bool barrier)
|
||||||
|
{
|
||||||
|
Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(sampleCountersInBuffer_atSampleIndex_withBarrier_), sampleBuffer, sampleIndex, barrier);
|
||||||
|
}
|
||||||
|
|
||||||
|
// static method: alloc
|
||||||
|
_MTL_INLINE MTL::AccelerationStructurePassSampleBufferAttachmentDescriptor* MTL::AccelerationStructurePassSampleBufferAttachmentDescriptor::alloc()
|
||||||
|
{
|
||||||
|
return NS::Object::alloc<MTL::AccelerationStructurePassSampleBufferAttachmentDescriptor>(_MTL_PRIVATE_CLS(MTLAccelerationStructurePassSampleBufferAttachmentDescriptor));
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: init
|
||||||
|
_MTL_INLINE MTL::AccelerationStructurePassSampleBufferAttachmentDescriptor* MTL::AccelerationStructurePassSampleBufferAttachmentDescriptor::init()
|
||||||
|
{
|
||||||
|
return NS::Object::init<MTL::AccelerationStructurePassSampleBufferAttachmentDescriptor>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: sampleBuffer
|
||||||
|
_MTL_INLINE MTL::CounterSampleBuffer* MTL::AccelerationStructurePassSampleBufferAttachmentDescriptor::sampleBuffer() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::CounterSampleBuffer*>(this, _MTL_PRIVATE_SEL(sampleBuffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
_MTL_INLINE void MTL::AccelerationStructurePassSampleBufferAttachmentDescriptor::setSampleBuffer(const MTL::CounterSampleBuffer* sampleBuffer)
|
||||||
|
{
|
||||||
|
Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(setSampleBuffer_), sampleBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: startOfEncoderSampleIndex
|
||||||
|
_MTL_INLINE NS::UInteger MTL::AccelerationStructurePassSampleBufferAttachmentDescriptor::startOfEncoderSampleIndex() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::UInteger>(this, _MTL_PRIVATE_SEL(startOfEncoderSampleIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
_MTL_INLINE void MTL::AccelerationStructurePassSampleBufferAttachmentDescriptor::setStartOfEncoderSampleIndex(NS::UInteger startOfEncoderSampleIndex)
|
||||||
|
{
|
||||||
|
Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(setStartOfEncoderSampleIndex_), startOfEncoderSampleIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: endOfEncoderSampleIndex
|
||||||
|
_MTL_INLINE NS::UInteger MTL::AccelerationStructurePassSampleBufferAttachmentDescriptor::endOfEncoderSampleIndex() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::UInteger>(this, _MTL_PRIVATE_SEL(endOfEncoderSampleIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
_MTL_INLINE void MTL::AccelerationStructurePassSampleBufferAttachmentDescriptor::setEndOfEncoderSampleIndex(NS::UInteger endOfEncoderSampleIndex)
|
||||||
|
{
|
||||||
|
Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(setEndOfEncoderSampleIndex_), endOfEncoderSampleIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// static method: alloc
|
||||||
|
_MTL_INLINE MTL::AccelerationStructurePassSampleBufferAttachmentDescriptorArray* MTL::AccelerationStructurePassSampleBufferAttachmentDescriptorArray::alloc()
|
||||||
|
{
|
||||||
|
return NS::Object::alloc<MTL::AccelerationStructurePassSampleBufferAttachmentDescriptorArray>(_MTL_PRIVATE_CLS(MTLAccelerationStructurePassSampleBufferAttachmentDescriptorArray));
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: init
|
||||||
|
_MTL_INLINE MTL::AccelerationStructurePassSampleBufferAttachmentDescriptorArray* MTL::AccelerationStructurePassSampleBufferAttachmentDescriptorArray::init()
|
||||||
|
{
|
||||||
|
return NS::Object::init<MTL::AccelerationStructurePassSampleBufferAttachmentDescriptorArray>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: objectAtIndexedSubscript:
|
||||||
|
_MTL_INLINE MTL::AccelerationStructurePassSampleBufferAttachmentDescriptor* MTL::AccelerationStructurePassSampleBufferAttachmentDescriptorArray::object(NS::UInteger attachmentIndex)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::AccelerationStructurePassSampleBufferAttachmentDescriptor*>(this, _MTL_PRIVATE_SEL(objectAtIndexedSubscript_), attachmentIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: setObject:atIndexedSubscript:
|
||||||
|
_MTL_INLINE void MTL::AccelerationStructurePassSampleBufferAttachmentDescriptorArray::setObject(const MTL::AccelerationStructurePassSampleBufferAttachmentDescriptor* attachment, NS::UInteger attachmentIndex)
|
||||||
|
{
|
||||||
|
Object::sendMessage<void>(this, _MTL_PRIVATE_SEL(setObject_atIndexedSubscript_), attachment, attachmentIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// static method: alloc
|
||||||
|
_MTL_INLINE MTL::AccelerationStructurePassDescriptor* MTL::AccelerationStructurePassDescriptor::alloc()
|
||||||
|
{
|
||||||
|
return NS::Object::alloc<MTL::AccelerationStructurePassDescriptor>(_MTL_PRIVATE_CLS(MTLAccelerationStructurePassDescriptor));
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: init
|
||||||
|
_MTL_INLINE MTL::AccelerationStructurePassDescriptor* MTL::AccelerationStructurePassDescriptor::init()
|
||||||
|
{
|
||||||
|
return NS::Object::init<MTL::AccelerationStructurePassDescriptor>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// static method: accelerationStructurePassDescriptor
|
||||||
|
_MTL_INLINE MTL::AccelerationStructurePassDescriptor* MTL::AccelerationStructurePassDescriptor::accelerationStructurePassDescriptor()
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::AccelerationStructurePassDescriptor*>(_MTL_PRIVATE_CLS(MTLAccelerationStructurePassDescriptor), _MTL_PRIVATE_SEL(accelerationStructurePassDescriptor));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: sampleBufferAttachments
|
||||||
|
_MTL_INLINE MTL::AccelerationStructurePassSampleBufferAttachmentDescriptorArray* MTL::AccelerationStructurePassDescriptor::sampleBufferAttachments() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::AccelerationStructurePassSampleBufferAttachmentDescriptorArray*>(this, _MTL_PRIVATE_SEL(sampleBufferAttachments));
|
||||||
|
}
|
169
third_party/metal-cpp/Metal/MTLAccelerationStructureTypes.hpp
vendored
Normal file
169
third_party/metal-cpp/Metal/MTLAccelerationStructureTypes.hpp
vendored
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Metal/MTLAccelerationStructureTypes.hpp
|
||||||
|
//
|
||||||
|
// Copyright 2020-2023 Apple Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "MTLDefines.hpp"
|
||||||
|
#include "MTLPrivate.hpp"
|
||||||
|
#include "MTLResource.hpp"
|
||||||
|
#include "MTLStageInputOutputDescriptor.hpp"
|
||||||
|
|
||||||
|
#include "../Foundation/NSRange.hpp"
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace MTL
|
||||||
|
{
|
||||||
|
struct PackedFloat3
|
||||||
|
{
|
||||||
|
PackedFloat3();
|
||||||
|
PackedFloat3(float x, float y, float z);
|
||||||
|
|
||||||
|
float& operator[](int idx);
|
||||||
|
float operator[](int idx) const;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
float z;
|
||||||
|
};
|
||||||
|
|
||||||
|
float elements[3];
|
||||||
|
};
|
||||||
|
} _MTL_PACKED;
|
||||||
|
|
||||||
|
struct PackedFloat4x3
|
||||||
|
{
|
||||||
|
PackedFloat4x3();
|
||||||
|
PackedFloat4x3(const PackedFloat3& col0, const PackedFloat3& col1, const PackedFloat3& col2, const PackedFloat3& col3);
|
||||||
|
|
||||||
|
PackedFloat3& operator[](int idx);
|
||||||
|
const PackedFloat3& operator[](int idx) const;
|
||||||
|
|
||||||
|
PackedFloat3 columns[4];
|
||||||
|
} _MTL_PACKED;
|
||||||
|
|
||||||
|
struct AxisAlignedBoundingBox
|
||||||
|
{
|
||||||
|
AxisAlignedBoundingBox();
|
||||||
|
AxisAlignedBoundingBox(PackedFloat3 p);
|
||||||
|
AxisAlignedBoundingBox(PackedFloat3 min, PackedFloat3 max);
|
||||||
|
|
||||||
|
PackedFloat3 min;
|
||||||
|
PackedFloat3 max;
|
||||||
|
} _MTL_PACKED;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_MTL_INLINE MTL::PackedFloat3::PackedFloat3()
|
||||||
|
: x(0.0f)
|
||||||
|
, y(0.0f)
|
||||||
|
, z(0.0f)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_MTL_INLINE MTL::PackedFloat3::PackedFloat3(float _x, float _y, float _z)
|
||||||
|
: x(_x)
|
||||||
|
, y(_y)
|
||||||
|
, z(_z)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_MTL_INLINE float& MTL::PackedFloat3::operator[](int idx)
|
||||||
|
{
|
||||||
|
return elements[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_MTL_INLINE float MTL::PackedFloat3::operator[](int idx) const
|
||||||
|
{
|
||||||
|
return elements[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_MTL_INLINE MTL::PackedFloat4x3::PackedFloat4x3()
|
||||||
|
{
|
||||||
|
columns[0] = PackedFloat3(0.0f, 0.0f, 0.0f);
|
||||||
|
columns[1] = PackedFloat3(0.0f, 0.0f, 0.0f);
|
||||||
|
columns[2] = PackedFloat3(0.0f, 0.0f, 0.0f);
|
||||||
|
columns[3] = PackedFloat3(0.0f, 0.0f, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_MTL_INLINE MTL::PackedFloat4x3::PackedFloat4x3(const PackedFloat3& col0, const PackedFloat3& col1, const PackedFloat3& col2, const PackedFloat3& col3)
|
||||||
|
{
|
||||||
|
columns[0] = col0;
|
||||||
|
columns[1] = col1;
|
||||||
|
columns[2] = col2;
|
||||||
|
columns[3] = col3;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_MTL_INLINE MTL::PackedFloat3& MTL::PackedFloat4x3::operator[](int idx)
|
||||||
|
{
|
||||||
|
return columns[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_MTL_INLINE const MTL::PackedFloat3& MTL::PackedFloat4x3::operator[](int idx) const
|
||||||
|
{
|
||||||
|
return columns[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_MTL_INLINE MTL::AxisAlignedBoundingBox::AxisAlignedBoundingBox()
|
||||||
|
: min(INFINITY, INFINITY, INFINITY)
|
||||||
|
, max(-INFINITY, -INFINITY, -INFINITY)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_MTL_INLINE MTL::AxisAlignedBoundingBox::AxisAlignedBoundingBox(PackedFloat3 p)
|
||||||
|
: min(p)
|
||||||
|
, max(p)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_MTL_INLINE MTL::AxisAlignedBoundingBox::AxisAlignedBoundingBox(PackedFloat3 _min, PackedFloat3 _max)
|
||||||
|
: min(_min)
|
||||||
|
, max(_max)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
848
third_party/metal-cpp/Metal/MTLArgument.hpp
vendored
Normal file
848
third_party/metal-cpp/Metal/MTLArgument.hpp
vendored
Normal file
|
@ -0,0 +1,848 @@
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Metal/MTLArgument.hpp
|
||||||
|
//
|
||||||
|
// Copyright 2020-2023 Apple Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "MTLDefines.hpp"
|
||||||
|
#include "MTLHeaderBridge.hpp"
|
||||||
|
#include "MTLPrivate.hpp"
|
||||||
|
|
||||||
|
#include <Foundation/Foundation.hpp>
|
||||||
|
|
||||||
|
#include "MTLArgument.hpp"
|
||||||
|
#include "MTLTexture.hpp"
|
||||||
|
|
||||||
|
namespace MTL
|
||||||
|
{
|
||||||
|
_MTL_ENUM(NS::UInteger, DataType) {
|
||||||
|
DataTypeNone = 0,
|
||||||
|
DataTypeStruct = 1,
|
||||||
|
DataTypeArray = 2,
|
||||||
|
DataTypeFloat = 3,
|
||||||
|
DataTypeFloat2 = 4,
|
||||||
|
DataTypeFloat3 = 5,
|
||||||
|
DataTypeFloat4 = 6,
|
||||||
|
DataTypeFloat2x2 = 7,
|
||||||
|
DataTypeFloat2x3 = 8,
|
||||||
|
DataTypeFloat2x4 = 9,
|
||||||
|
DataTypeFloat3x2 = 10,
|
||||||
|
DataTypeFloat3x3 = 11,
|
||||||
|
DataTypeFloat3x4 = 12,
|
||||||
|
DataTypeFloat4x2 = 13,
|
||||||
|
DataTypeFloat4x3 = 14,
|
||||||
|
DataTypeFloat4x4 = 15,
|
||||||
|
DataTypeHalf = 16,
|
||||||
|
DataTypeHalf2 = 17,
|
||||||
|
DataTypeHalf3 = 18,
|
||||||
|
DataTypeHalf4 = 19,
|
||||||
|
DataTypeHalf2x2 = 20,
|
||||||
|
DataTypeHalf2x3 = 21,
|
||||||
|
DataTypeHalf2x4 = 22,
|
||||||
|
DataTypeHalf3x2 = 23,
|
||||||
|
DataTypeHalf3x3 = 24,
|
||||||
|
DataTypeHalf3x4 = 25,
|
||||||
|
DataTypeHalf4x2 = 26,
|
||||||
|
DataTypeHalf4x3 = 27,
|
||||||
|
DataTypeHalf4x4 = 28,
|
||||||
|
DataTypeInt = 29,
|
||||||
|
DataTypeInt2 = 30,
|
||||||
|
DataTypeInt3 = 31,
|
||||||
|
DataTypeInt4 = 32,
|
||||||
|
DataTypeUInt = 33,
|
||||||
|
DataTypeUInt2 = 34,
|
||||||
|
DataTypeUInt3 = 35,
|
||||||
|
DataTypeUInt4 = 36,
|
||||||
|
DataTypeShort = 37,
|
||||||
|
DataTypeShort2 = 38,
|
||||||
|
DataTypeShort3 = 39,
|
||||||
|
DataTypeShort4 = 40,
|
||||||
|
DataTypeUShort = 41,
|
||||||
|
DataTypeUShort2 = 42,
|
||||||
|
DataTypeUShort3 = 43,
|
||||||
|
DataTypeUShort4 = 44,
|
||||||
|
DataTypeChar = 45,
|
||||||
|
DataTypeChar2 = 46,
|
||||||
|
DataTypeChar3 = 47,
|
||||||
|
DataTypeChar4 = 48,
|
||||||
|
DataTypeUChar = 49,
|
||||||
|
DataTypeUChar2 = 50,
|
||||||
|
DataTypeUChar3 = 51,
|
||||||
|
DataTypeUChar4 = 52,
|
||||||
|
DataTypeBool = 53,
|
||||||
|
DataTypeBool2 = 54,
|
||||||
|
DataTypeBool3 = 55,
|
||||||
|
DataTypeBool4 = 56,
|
||||||
|
DataTypeTexture = 58,
|
||||||
|
DataTypeSampler = 59,
|
||||||
|
DataTypePointer = 60,
|
||||||
|
DataTypeR8Unorm = 62,
|
||||||
|
DataTypeR8Snorm = 63,
|
||||||
|
DataTypeR16Unorm = 64,
|
||||||
|
DataTypeR16Snorm = 65,
|
||||||
|
DataTypeRG8Unorm = 66,
|
||||||
|
DataTypeRG8Snorm = 67,
|
||||||
|
DataTypeRG16Unorm = 68,
|
||||||
|
DataTypeRG16Snorm = 69,
|
||||||
|
DataTypeRGBA8Unorm = 70,
|
||||||
|
DataTypeRGBA8Unorm_sRGB = 71,
|
||||||
|
DataTypeRGBA8Snorm = 72,
|
||||||
|
DataTypeRGBA16Unorm = 73,
|
||||||
|
DataTypeRGBA16Snorm = 74,
|
||||||
|
DataTypeRGB10A2Unorm = 75,
|
||||||
|
DataTypeRG11B10Float = 76,
|
||||||
|
DataTypeRGB9E5Float = 77,
|
||||||
|
DataTypeRenderPipeline = 78,
|
||||||
|
DataTypeComputePipeline = 79,
|
||||||
|
DataTypeIndirectCommandBuffer = 80,
|
||||||
|
DataTypeLong = 81,
|
||||||
|
DataTypeLong2 = 82,
|
||||||
|
DataTypeLong3 = 83,
|
||||||
|
DataTypeLong4 = 84,
|
||||||
|
DataTypeULong = 85,
|
||||||
|
DataTypeULong2 = 86,
|
||||||
|
DataTypeULong3 = 87,
|
||||||
|
DataTypeULong4 = 88,
|
||||||
|
DataTypeVisibleFunctionTable = 115,
|
||||||
|
DataTypeIntersectionFunctionTable = 116,
|
||||||
|
DataTypePrimitiveAccelerationStructure = 117,
|
||||||
|
DataTypeInstanceAccelerationStructure = 118,
|
||||||
|
DataTypeBFloat = 121,
|
||||||
|
DataTypeBFloat2 = 122,
|
||||||
|
DataTypeBFloat3 = 123,
|
||||||
|
DataTypeBFloat4 = 124,
|
||||||
|
};
|
||||||
|
|
||||||
|
_MTL_ENUM(NS::Integer, BindingType) {
|
||||||
|
BindingTypeBuffer = 0,
|
||||||
|
BindingTypeThreadgroupMemory = 1,
|
||||||
|
BindingTypeTexture = 2,
|
||||||
|
BindingTypeSampler = 3,
|
||||||
|
BindingTypeImageblockData = 16,
|
||||||
|
BindingTypeImageblock = 17,
|
||||||
|
BindingTypeVisibleFunctionTable = 24,
|
||||||
|
BindingTypePrimitiveAccelerationStructure = 25,
|
||||||
|
BindingTypeInstanceAccelerationStructure = 26,
|
||||||
|
BindingTypeIntersectionFunctionTable = 27,
|
||||||
|
BindingTypeObjectPayload = 34,
|
||||||
|
};
|
||||||
|
|
||||||
|
_MTL_ENUM(NS::UInteger, ArgumentType) {
|
||||||
|
ArgumentTypeBuffer = 0,
|
||||||
|
ArgumentTypeThreadgroupMemory = 1,
|
||||||
|
ArgumentTypeTexture = 2,
|
||||||
|
ArgumentTypeSampler = 3,
|
||||||
|
ArgumentTypeImageblockData = 16,
|
||||||
|
ArgumentTypeImageblock = 17,
|
||||||
|
ArgumentTypeVisibleFunctionTable = 24,
|
||||||
|
ArgumentTypePrimitiveAccelerationStructure = 25,
|
||||||
|
ArgumentTypeInstanceAccelerationStructure = 26,
|
||||||
|
ArgumentTypeIntersectionFunctionTable = 27,
|
||||||
|
};
|
||||||
|
|
||||||
|
_MTL_ENUM(NS::UInteger, BindingAccess) {
|
||||||
|
BindingAccessReadOnly = 0,
|
||||||
|
BindingAccessReadWrite = 1,
|
||||||
|
BindingAccessWriteOnly = 2,
|
||||||
|
ArgumentAccessReadOnly = 0,
|
||||||
|
ArgumentAccessReadWrite = 1,
|
||||||
|
ArgumentAccessWriteOnly = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
class Type : public NS::Referencing<Type>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static class Type* alloc();
|
||||||
|
|
||||||
|
class Type* init();
|
||||||
|
|
||||||
|
MTL::DataType dataType() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StructMember : public NS::Referencing<StructMember>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static class StructMember* alloc();
|
||||||
|
|
||||||
|
class StructMember* init();
|
||||||
|
|
||||||
|
NS::String* name() const;
|
||||||
|
|
||||||
|
NS::UInteger offset() const;
|
||||||
|
|
||||||
|
MTL::DataType dataType() const;
|
||||||
|
|
||||||
|
class StructType* structType();
|
||||||
|
|
||||||
|
class ArrayType* arrayType();
|
||||||
|
|
||||||
|
class TextureReferenceType* textureReferenceType();
|
||||||
|
|
||||||
|
class PointerType* pointerType();
|
||||||
|
|
||||||
|
NS::UInteger argumentIndex() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StructType : public NS::Referencing<StructType, Type>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static class StructType* alloc();
|
||||||
|
|
||||||
|
class StructType* init();
|
||||||
|
|
||||||
|
NS::Array* members() const;
|
||||||
|
|
||||||
|
class StructMember* memberByName(const NS::String* name);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ArrayType : public NS::Referencing<ArrayType, Type>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static class ArrayType* alloc();
|
||||||
|
|
||||||
|
class ArrayType* init();
|
||||||
|
|
||||||
|
MTL::DataType elementType() const;
|
||||||
|
|
||||||
|
NS::UInteger arrayLength() const;
|
||||||
|
|
||||||
|
NS::UInteger stride() const;
|
||||||
|
|
||||||
|
NS::UInteger argumentIndexStride() const;
|
||||||
|
|
||||||
|
class StructType* elementStructType();
|
||||||
|
|
||||||
|
class ArrayType* elementArrayType();
|
||||||
|
|
||||||
|
class TextureReferenceType* elementTextureReferenceType();
|
||||||
|
|
||||||
|
class PointerType* elementPointerType();
|
||||||
|
};
|
||||||
|
|
||||||
|
class PointerType : public NS::Referencing<PointerType, Type>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static class PointerType* alloc();
|
||||||
|
|
||||||
|
class PointerType* init();
|
||||||
|
|
||||||
|
MTL::DataType elementType() const;
|
||||||
|
|
||||||
|
MTL::BindingAccess access() const;
|
||||||
|
|
||||||
|
NS::UInteger alignment() const;
|
||||||
|
|
||||||
|
NS::UInteger dataSize() const;
|
||||||
|
|
||||||
|
bool elementIsArgumentBuffer() const;
|
||||||
|
|
||||||
|
class StructType* elementStructType();
|
||||||
|
|
||||||
|
class ArrayType* elementArrayType();
|
||||||
|
};
|
||||||
|
|
||||||
|
class TextureReferenceType : public NS::Referencing<TextureReferenceType, Type>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static class TextureReferenceType* alloc();
|
||||||
|
|
||||||
|
class TextureReferenceType* init();
|
||||||
|
|
||||||
|
MTL::DataType textureDataType() const;
|
||||||
|
|
||||||
|
MTL::TextureType textureType() const;
|
||||||
|
|
||||||
|
MTL::BindingAccess access() const;
|
||||||
|
|
||||||
|
bool isDepthTexture() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Argument : public NS::Referencing<Argument>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static class Argument* alloc();
|
||||||
|
|
||||||
|
class Argument* init();
|
||||||
|
|
||||||
|
NS::String* name() const;
|
||||||
|
|
||||||
|
MTL::ArgumentType type() const;
|
||||||
|
|
||||||
|
MTL::BindingAccess access() const;
|
||||||
|
|
||||||
|
NS::UInteger index() const;
|
||||||
|
|
||||||
|
bool active() const;
|
||||||
|
|
||||||
|
NS::UInteger bufferAlignment() const;
|
||||||
|
|
||||||
|
NS::UInteger bufferDataSize() const;
|
||||||
|
|
||||||
|
MTL::DataType bufferDataType() const;
|
||||||
|
|
||||||
|
class StructType* bufferStructType() const;
|
||||||
|
|
||||||
|
class PointerType* bufferPointerType() const;
|
||||||
|
|
||||||
|
NS::UInteger threadgroupMemoryAlignment() const;
|
||||||
|
|
||||||
|
NS::UInteger threadgroupMemoryDataSize() const;
|
||||||
|
|
||||||
|
MTL::TextureType textureType() const;
|
||||||
|
|
||||||
|
MTL::DataType textureDataType() const;
|
||||||
|
|
||||||
|
bool isDepthTexture() const;
|
||||||
|
|
||||||
|
NS::UInteger arrayLength() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Binding : public NS::Referencing<Binding>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NS::String* name() const;
|
||||||
|
|
||||||
|
MTL::BindingType type() const;
|
||||||
|
|
||||||
|
MTL::BindingAccess access() const;
|
||||||
|
|
||||||
|
NS::UInteger index() const;
|
||||||
|
|
||||||
|
bool used() const;
|
||||||
|
|
||||||
|
bool argument() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BufferBinding : public NS::Referencing<BufferBinding, Binding>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NS::UInteger bufferAlignment() const;
|
||||||
|
|
||||||
|
NS::UInteger bufferDataSize() const;
|
||||||
|
|
||||||
|
MTL::DataType bufferDataType() const;
|
||||||
|
|
||||||
|
class StructType* bufferStructType() const;
|
||||||
|
|
||||||
|
class PointerType* bufferPointerType() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ThreadgroupBinding : public NS::Referencing<ThreadgroupBinding, Binding>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NS::UInteger threadgroupMemoryAlignment() const;
|
||||||
|
|
||||||
|
NS::UInteger threadgroupMemoryDataSize() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TextureBinding : public NS::Referencing<TextureBinding, Binding>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MTL::TextureType textureType() const;
|
||||||
|
|
||||||
|
MTL::DataType textureDataType() const;
|
||||||
|
|
||||||
|
bool depthTexture() const;
|
||||||
|
|
||||||
|
NS::UInteger arrayLength() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ObjectPayloadBinding : public NS::Referencing<ObjectPayloadBinding, Binding>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NS::UInteger objectPayloadAlignment() const;
|
||||||
|
|
||||||
|
NS::UInteger objectPayloadDataSize() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// static method: alloc
|
||||||
|
_MTL_INLINE MTL::Type* MTL::Type::alloc()
|
||||||
|
{
|
||||||
|
return NS::Object::alloc<MTL::Type>(_MTL_PRIVATE_CLS(MTLType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: init
|
||||||
|
_MTL_INLINE MTL::Type* MTL::Type::init()
|
||||||
|
{
|
||||||
|
return NS::Object::init<MTL::Type>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: dataType
|
||||||
|
_MTL_INLINE MTL::DataType MTL::Type::dataType() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::DataType>(this, _MTL_PRIVATE_SEL(dataType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// static method: alloc
|
||||||
|
_MTL_INLINE MTL::StructMember* MTL::StructMember::alloc()
|
||||||
|
{
|
||||||
|
return NS::Object::alloc<MTL::StructMember>(_MTL_PRIVATE_CLS(MTLStructMember));
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: init
|
||||||
|
_MTL_INLINE MTL::StructMember* MTL::StructMember::init()
|
||||||
|
{
|
||||||
|
return NS::Object::init<MTL::StructMember>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: name
|
||||||
|
_MTL_INLINE NS::String* MTL::StructMember::name() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::String*>(this, _MTL_PRIVATE_SEL(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: offset
|
||||||
|
_MTL_INLINE NS::UInteger MTL::StructMember::offset() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::UInteger>(this, _MTL_PRIVATE_SEL(offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: dataType
|
||||||
|
_MTL_INLINE MTL::DataType MTL::StructMember::dataType() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::DataType>(this, _MTL_PRIVATE_SEL(dataType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: structType
|
||||||
|
_MTL_INLINE MTL::StructType* MTL::StructMember::structType()
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::StructType*>(this, _MTL_PRIVATE_SEL(structType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: arrayType
|
||||||
|
_MTL_INLINE MTL::ArrayType* MTL::StructMember::arrayType()
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::ArrayType*>(this, _MTL_PRIVATE_SEL(arrayType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: textureReferenceType
|
||||||
|
_MTL_INLINE MTL::TextureReferenceType* MTL::StructMember::textureReferenceType()
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::TextureReferenceType*>(this, _MTL_PRIVATE_SEL(textureReferenceType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: pointerType
|
||||||
|
_MTL_INLINE MTL::PointerType* MTL::StructMember::pointerType()
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::PointerType*>(this, _MTL_PRIVATE_SEL(pointerType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: argumentIndex
|
||||||
|
_MTL_INLINE NS::UInteger MTL::StructMember::argumentIndex() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::UInteger>(this, _MTL_PRIVATE_SEL(argumentIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
// static method: alloc
|
||||||
|
_MTL_INLINE MTL::StructType* MTL::StructType::alloc()
|
||||||
|
{
|
||||||
|
return NS::Object::alloc<MTL::StructType>(_MTL_PRIVATE_CLS(MTLStructType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: init
|
||||||
|
_MTL_INLINE MTL::StructType* MTL::StructType::init()
|
||||||
|
{
|
||||||
|
return NS::Object::init<MTL::StructType>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: members
|
||||||
|
_MTL_INLINE NS::Array* MTL::StructType::members() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::Array*>(this, _MTL_PRIVATE_SEL(members));
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: memberByName:
|
||||||
|
_MTL_INLINE MTL::StructMember* MTL::StructType::memberByName(const NS::String* name)
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::StructMember*>(this, _MTL_PRIVATE_SEL(memberByName_), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// static method: alloc
|
||||||
|
_MTL_INLINE MTL::ArrayType* MTL::ArrayType::alloc()
|
||||||
|
{
|
||||||
|
return NS::Object::alloc<MTL::ArrayType>(_MTL_PRIVATE_CLS(MTLArrayType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: init
|
||||||
|
_MTL_INLINE MTL::ArrayType* MTL::ArrayType::init()
|
||||||
|
{
|
||||||
|
return NS::Object::init<MTL::ArrayType>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: elementType
|
||||||
|
_MTL_INLINE MTL::DataType MTL::ArrayType::elementType() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::DataType>(this, _MTL_PRIVATE_SEL(elementType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: arrayLength
|
||||||
|
_MTL_INLINE NS::UInteger MTL::ArrayType::arrayLength() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::UInteger>(this, _MTL_PRIVATE_SEL(arrayLength));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: stride
|
||||||
|
_MTL_INLINE NS::UInteger MTL::ArrayType::stride() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::UInteger>(this, _MTL_PRIVATE_SEL(stride));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: argumentIndexStride
|
||||||
|
_MTL_INLINE NS::UInteger MTL::ArrayType::argumentIndexStride() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::UInteger>(this, _MTL_PRIVATE_SEL(argumentIndexStride));
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: elementStructType
|
||||||
|
_MTL_INLINE MTL::StructType* MTL::ArrayType::elementStructType()
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::StructType*>(this, _MTL_PRIVATE_SEL(elementStructType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: elementArrayType
|
||||||
|
_MTL_INLINE MTL::ArrayType* MTL::ArrayType::elementArrayType()
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::ArrayType*>(this, _MTL_PRIVATE_SEL(elementArrayType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: elementTextureReferenceType
|
||||||
|
_MTL_INLINE MTL::TextureReferenceType* MTL::ArrayType::elementTextureReferenceType()
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::TextureReferenceType*>(this, _MTL_PRIVATE_SEL(elementTextureReferenceType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: elementPointerType
|
||||||
|
_MTL_INLINE MTL::PointerType* MTL::ArrayType::elementPointerType()
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::PointerType*>(this, _MTL_PRIVATE_SEL(elementPointerType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// static method: alloc
|
||||||
|
_MTL_INLINE MTL::PointerType* MTL::PointerType::alloc()
|
||||||
|
{
|
||||||
|
return NS::Object::alloc<MTL::PointerType>(_MTL_PRIVATE_CLS(MTLPointerType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: init
|
||||||
|
_MTL_INLINE MTL::PointerType* MTL::PointerType::init()
|
||||||
|
{
|
||||||
|
return NS::Object::init<MTL::PointerType>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: elementType
|
||||||
|
_MTL_INLINE MTL::DataType MTL::PointerType::elementType() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::DataType>(this, _MTL_PRIVATE_SEL(elementType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: access
|
||||||
|
_MTL_INLINE MTL::BindingAccess MTL::PointerType::access() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::BindingAccess>(this, _MTL_PRIVATE_SEL(access));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: alignment
|
||||||
|
_MTL_INLINE NS::UInteger MTL::PointerType::alignment() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::UInteger>(this, _MTL_PRIVATE_SEL(alignment));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: dataSize
|
||||||
|
_MTL_INLINE NS::UInteger MTL::PointerType::dataSize() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::UInteger>(this, _MTL_PRIVATE_SEL(dataSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: elementIsArgumentBuffer
|
||||||
|
_MTL_INLINE bool MTL::PointerType::elementIsArgumentBuffer() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<bool>(this, _MTL_PRIVATE_SEL(elementIsArgumentBuffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: elementStructType
|
||||||
|
_MTL_INLINE MTL::StructType* MTL::PointerType::elementStructType()
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::StructType*>(this, _MTL_PRIVATE_SEL(elementStructType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: elementArrayType
|
||||||
|
_MTL_INLINE MTL::ArrayType* MTL::PointerType::elementArrayType()
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::ArrayType*>(this, _MTL_PRIVATE_SEL(elementArrayType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// static method: alloc
|
||||||
|
_MTL_INLINE MTL::TextureReferenceType* MTL::TextureReferenceType::alloc()
|
||||||
|
{
|
||||||
|
return NS::Object::alloc<MTL::TextureReferenceType>(_MTL_PRIVATE_CLS(MTLTextureReferenceType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: init
|
||||||
|
_MTL_INLINE MTL::TextureReferenceType* MTL::TextureReferenceType::init()
|
||||||
|
{
|
||||||
|
return NS::Object::init<MTL::TextureReferenceType>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: textureDataType
|
||||||
|
_MTL_INLINE MTL::DataType MTL::TextureReferenceType::textureDataType() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::DataType>(this, _MTL_PRIVATE_SEL(textureDataType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: textureType
|
||||||
|
_MTL_INLINE MTL::TextureType MTL::TextureReferenceType::textureType() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::TextureType>(this, _MTL_PRIVATE_SEL(textureType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: access
|
||||||
|
_MTL_INLINE MTL::BindingAccess MTL::TextureReferenceType::access() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::BindingAccess>(this, _MTL_PRIVATE_SEL(access));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: isDepthTexture
|
||||||
|
_MTL_INLINE bool MTL::TextureReferenceType::isDepthTexture() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<bool>(this, _MTL_PRIVATE_SEL(isDepthTexture));
|
||||||
|
}
|
||||||
|
|
||||||
|
// static method: alloc
|
||||||
|
_MTL_INLINE MTL::Argument* MTL::Argument::alloc()
|
||||||
|
{
|
||||||
|
return NS::Object::alloc<MTL::Argument>(_MTL_PRIVATE_CLS(MTLArgument));
|
||||||
|
}
|
||||||
|
|
||||||
|
// method: init
|
||||||
|
_MTL_INLINE MTL::Argument* MTL::Argument::init()
|
||||||
|
{
|
||||||
|
return NS::Object::init<MTL::Argument>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: name
|
||||||
|
_MTL_INLINE NS::String* MTL::Argument::name() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::String*>(this, _MTL_PRIVATE_SEL(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: type
|
||||||
|
_MTL_INLINE MTL::ArgumentType MTL::Argument::type() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::ArgumentType>(this, _MTL_PRIVATE_SEL(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: access
|
||||||
|
_MTL_INLINE MTL::BindingAccess MTL::Argument::access() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::BindingAccess>(this, _MTL_PRIVATE_SEL(access));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: index
|
||||||
|
_MTL_INLINE NS::UInteger MTL::Argument::index() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::UInteger>(this, _MTL_PRIVATE_SEL(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: active
|
||||||
|
_MTL_INLINE bool MTL::Argument::active() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<bool>(this, _MTL_PRIVATE_SEL(isActive));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: bufferAlignment
|
||||||
|
_MTL_INLINE NS::UInteger MTL::Argument::bufferAlignment() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::UInteger>(this, _MTL_PRIVATE_SEL(bufferAlignment));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: bufferDataSize
|
||||||
|
_MTL_INLINE NS::UInteger MTL::Argument::bufferDataSize() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::UInteger>(this, _MTL_PRIVATE_SEL(bufferDataSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: bufferDataType
|
||||||
|
_MTL_INLINE MTL::DataType MTL::Argument::bufferDataType() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::DataType>(this, _MTL_PRIVATE_SEL(bufferDataType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: bufferStructType
|
||||||
|
_MTL_INLINE MTL::StructType* MTL::Argument::bufferStructType() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::StructType*>(this, _MTL_PRIVATE_SEL(bufferStructType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: bufferPointerType
|
||||||
|
_MTL_INLINE MTL::PointerType* MTL::Argument::bufferPointerType() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::PointerType*>(this, _MTL_PRIVATE_SEL(bufferPointerType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: threadgroupMemoryAlignment
|
||||||
|
_MTL_INLINE NS::UInteger MTL::Argument::threadgroupMemoryAlignment() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::UInteger>(this, _MTL_PRIVATE_SEL(threadgroupMemoryAlignment));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: threadgroupMemoryDataSize
|
||||||
|
_MTL_INLINE NS::UInteger MTL::Argument::threadgroupMemoryDataSize() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::UInteger>(this, _MTL_PRIVATE_SEL(threadgroupMemoryDataSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: textureType
|
||||||
|
_MTL_INLINE MTL::TextureType MTL::Argument::textureType() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::TextureType>(this, _MTL_PRIVATE_SEL(textureType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: textureDataType
|
||||||
|
_MTL_INLINE MTL::DataType MTL::Argument::textureDataType() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::DataType>(this, _MTL_PRIVATE_SEL(textureDataType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: isDepthTexture
|
||||||
|
_MTL_INLINE bool MTL::Argument::isDepthTexture() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<bool>(this, _MTL_PRIVATE_SEL(isDepthTexture));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: arrayLength
|
||||||
|
_MTL_INLINE NS::UInteger MTL::Argument::arrayLength() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::UInteger>(this, _MTL_PRIVATE_SEL(arrayLength));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: name
|
||||||
|
_MTL_INLINE NS::String* MTL::Binding::name() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::String*>(this, _MTL_PRIVATE_SEL(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: type
|
||||||
|
_MTL_INLINE MTL::BindingType MTL::Binding::type() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::BindingType>(this, _MTL_PRIVATE_SEL(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: access
|
||||||
|
_MTL_INLINE MTL::BindingAccess MTL::Binding::access() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::BindingAccess>(this, _MTL_PRIVATE_SEL(access));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: index
|
||||||
|
_MTL_INLINE NS::UInteger MTL::Binding::index() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::UInteger>(this, _MTL_PRIVATE_SEL(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: used
|
||||||
|
_MTL_INLINE bool MTL::Binding::used() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<bool>(this, _MTL_PRIVATE_SEL(isUsed));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: argument
|
||||||
|
_MTL_INLINE bool MTL::Binding::argument() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<bool>(this, _MTL_PRIVATE_SEL(isArgument));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: bufferAlignment
|
||||||
|
_MTL_INLINE NS::UInteger MTL::BufferBinding::bufferAlignment() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::UInteger>(this, _MTL_PRIVATE_SEL(bufferAlignment));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: bufferDataSize
|
||||||
|
_MTL_INLINE NS::UInteger MTL::BufferBinding::bufferDataSize() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::UInteger>(this, _MTL_PRIVATE_SEL(bufferDataSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: bufferDataType
|
||||||
|
_MTL_INLINE MTL::DataType MTL::BufferBinding::bufferDataType() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::DataType>(this, _MTL_PRIVATE_SEL(bufferDataType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: bufferStructType
|
||||||
|
_MTL_INLINE MTL::StructType* MTL::BufferBinding::bufferStructType() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::StructType*>(this, _MTL_PRIVATE_SEL(bufferStructType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: bufferPointerType
|
||||||
|
_MTL_INLINE MTL::PointerType* MTL::BufferBinding::bufferPointerType() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::PointerType*>(this, _MTL_PRIVATE_SEL(bufferPointerType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: threadgroupMemoryAlignment
|
||||||
|
_MTL_INLINE NS::UInteger MTL::ThreadgroupBinding::threadgroupMemoryAlignment() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::UInteger>(this, _MTL_PRIVATE_SEL(threadgroupMemoryAlignment));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: threadgroupMemoryDataSize
|
||||||
|
_MTL_INLINE NS::UInteger MTL::ThreadgroupBinding::threadgroupMemoryDataSize() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::UInteger>(this, _MTL_PRIVATE_SEL(threadgroupMemoryDataSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: textureType
|
||||||
|
_MTL_INLINE MTL::TextureType MTL::TextureBinding::textureType() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::TextureType>(this, _MTL_PRIVATE_SEL(textureType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: textureDataType
|
||||||
|
_MTL_INLINE MTL::DataType MTL::TextureBinding::textureDataType() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<MTL::DataType>(this, _MTL_PRIVATE_SEL(textureDataType));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: depthTexture
|
||||||
|
_MTL_INLINE bool MTL::TextureBinding::depthTexture() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<bool>(this, _MTL_PRIVATE_SEL(isDepthTexture));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: arrayLength
|
||||||
|
_MTL_INLINE NS::UInteger MTL::TextureBinding::arrayLength() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::UInteger>(this, _MTL_PRIVATE_SEL(arrayLength));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: objectPayloadAlignment
|
||||||
|
_MTL_INLINE NS::UInteger MTL::ObjectPayloadBinding::objectPayloadAlignment() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::UInteger>(this, _MTL_PRIVATE_SEL(objectPayloadAlignment));
|
||||||
|
}
|
||||||
|
|
||||||
|
// property: objectPayloadDataSize
|
||||||
|
_MTL_INLINE NS::UInteger MTL::ObjectPayloadBinding::objectPayloadDataSize() const
|
||||||
|
{
|
||||||
|
return Object::sendMessage<NS::UInteger>(this, _MTL_PRIVATE_SEL(objectPayloadDataSize));
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue