metal: initial support

This commit is contained in:
Samuliak 2024-07-02 08:28:41 +02:00
parent 29d9ed7224
commit f0547d1a71
167 changed files with 28839 additions and 1271 deletions

View file

@ -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})

View file

@ -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) {

View file

@ -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;

View file

@ -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;
}; };

View file

@ -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

View file

@ -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();
}; };

View file

@ -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());
} }
} }
}; };

View file

@ -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.

View file

@ -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

View file

@ -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;

View 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;
};

View file

@ -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);
}; };

View file

@ -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);
}; };

View file

@ -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);
}; };

View file

@ -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);
}; };

View file

@ -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);
}; };

View file

@ -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);
}; };

View file

@ -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);
}; };

View file

@ -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; };
}
};

View file

@ -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);
}; };

View file

@ -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);
}; };

View file

@ -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();
}; };

View file

@ -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);
} }
} }

View file

@ -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);
}; };

View file

@ -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; }
}; };

View file

@ -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);
}; };

View file

@ -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);
}; };

View file

@ -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);
}; };

View file

@ -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

View file

@ -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);
}; };

View file

@ -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);
}; };

View file

@ -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);
}; };

View file

@ -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);
}; };

View file

@ -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);
}; };

View file

@ -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);
}; };

View file

@ -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); }

View file

@ -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);
}; };

View file

@ -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);
}; };

View file

@ -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);
}; };

View file

@ -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

View file

@ -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

View file

@ -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++) {

View file

@ -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);

View file

@ -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;
} }

View file

@ -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;
} }
} }
} }

View file

@ -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) {

View file

@ -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");
} }

View file

@ -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;
} }
} }

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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 {

View file

@ -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);

View file

@ -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;
} }
} }

View file

@ -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;
} }
} }

View file

@ -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;
} }

View 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>

View 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
}

View file

@ -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);
} }

View file

@ -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
} }
} }

View file

@ -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
} }

View file

@ -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);

View file

@ -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);
} }
} }

View file

@ -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);
} }

View file

@ -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());
} }
} }
} }

View file

@ -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);
} }

View file

@ -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));
} }
} }

View file

@ -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);
} }

View 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);
}

View file

@ -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() {
} }
} }
} }
} }

View file

@ -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;

View file

@ -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";
} }
} }

View 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"
//-------------------------------------------------------------------------------------------------------------------------------------------------------------

View 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);
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------

View 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));
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------

View 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);
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------

View 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));
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------

View 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);
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------

View 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)
//-------------------------------------------------------------------------------------------------------------------------------------------------------------

View 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));
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------

View 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));
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------

View 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));
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------

View 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));
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------

View 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);
}

View 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);
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------

View 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;
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------

View 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));
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------

View 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
//-------------------------------------------------------------------------------------------------------------------------------------------------------------

View 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));
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------

View 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;
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------

View 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);
}

View 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();
}

View 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);
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------

View 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;
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------

View 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
View 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.

File diff suppressed because it is too large Load diff

View 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));
}

View 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)
{
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------

View 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