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")
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(GPU_DEBUG_INFO "Enable additional GPU debugging info" OFF)
option(ENABLE_OPENGL "Enable OpenGL 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_TESTS "Compile unit-tests" 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/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/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/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
@ -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/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/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/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
@ -400,8 +401,36 @@ if(ENABLE_VULKAN)
target_link_libraries(AlberCore PRIVATE Vulkan::Vulkan resources_renderer_vk)
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})
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}
${AUDIO_SOURCE_FILES} ${HEADER_FILES} ${FRONTEND_HEADER_FILES})
target_sources(AlberCore PRIVATE ${ALL_SOURCES})

View file

@ -33,8 +33,8 @@ namespace Audio {
SampleFormat format;
SourceType sourceType;
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 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 operator<(const Buffer& other) const {
// Lower ID = Higher priority
@ -136,7 +136,7 @@ namespace Audio {
const auto counter0 = dspRam.region0.frameCounter;
const auto counter1 = dspRam.region1.frameCounter;
// Handle wraparound cases first
// HandleType wraparound cases first
if (counter0 == 0xffff && counter1 != 0xfffe) {
return 1;
} else if (counter1 == 0xffff && counter0 != 0xfffe) {

View file

@ -8,7 +8,7 @@
namespace Common {
class CapstoneDisassembler {
csh handle; // Handle to our disassembler object
csh handle; // HandleType to our disassembler object
cs_insn* instructions = nullptr; // Pointer to instruction object
bool initialized = false;

View file

@ -7,6 +7,7 @@
#include <string>
#include <type_traits>
#include <vector>
#include "helpers.hpp"
#include "memory.hpp"
#include "result.hpp"
@ -15,13 +16,13 @@
using Result::HorizonResult;
namespace PathType {
enum : u32 {
Invalid = 0,
Empty = 1,
Binary = 2,
ASCII = 3,
UTF16 = 4,
};
enum : u32 {
Invalid = 0,
Empty = 1,
Binary = 2,
ASCII = 3,
UTF16 = 4,
};
}
namespace ArchiveID {
@ -42,83 +43,81 @@ namespace ArchiveID {
UserSaveData2 = 0x567890B4,
};
static std::string toString(u32 id) {
switch (id) {
case SelfNCCH: return "SelfNCCH";
case SaveData: return "SaveData";
case ExtSaveData: return "ExtSaveData";
case SharedExtSaveData: return "SharedExtSaveData";
case SystemSaveData: return "SystemSaveData";
case SDMC: return "SDMC";
case SDMCWriteOnly: return "SDMC (Write-only)";
case SavedataAndNcch: return "Savedata & NCCH (archive 0x2345678A)";
default: return "Unknown archive";
}
}
}
static std::string toString(u32 id) {
switch (id) {
case SelfNCCH: return "SelfNCCH";
case SaveData: return "SaveData";
case ExtSaveData: return "ExtSaveData";
case SharedExtSaveData: return "SharedExtSaveData";
case SystemSaveData: return "SystemSaveData";
case SDMC: return "SDMC";
case SDMCWriteOnly: return "SDMC (Write-only)";
case SavedataAndNcch: return "Savedata & NCCH (archive 0x2345678A)";
default: return "Unknown archive";
}
}
} // namespace ArchiveID
struct FSPath {
u32 type = PathType::Invalid;
u32 type = PathType::Invalid;
std::vector<u8> binary; // Path data for binary paths
std::string string; // Path data for ASCII paths
std::u16string utf16_string;
std::vector<u8> binary; // Path data for binary paths
std::string string; // Path data for ASCII paths
std::u16string utf16_string;
FSPath() {}
FSPath() {}
FSPath(u32 type, const std::vector<u8>& vec) : type(type) {
switch (type) {
case PathType::Binary:
binary = std::move(vec);
break;
FSPath(u32 type, const std::vector<u8>& vec) : type(type) {
switch (type) {
case PathType::Binary: binary = std::move(vec); break;
case PathType::ASCII:
string.resize(vec.size() - 1); // -1 because of the null terminator
std::memcpy(string.data(), vec.data(), vec.size() - 1); // Copy string data
break;
case PathType::ASCII:
string.resize(vec.size() - 1); // -1 because of the null terminator
std::memcpy(string.data(), vec.data(), vec.size() - 1); // Copy string data
break;
case PathType::UTF16: {
const size_t size = vec.size() / sizeof(u16) - 1; // Character count. -1 because null terminator here too
utf16_string.resize(size);
std::memcpy(utf16_string.data(), vec.data(), size * sizeof(u16));
break;
}
; }
}
case PathType::UTF16: {
const size_t size = vec.size() / sizeof(u16) - 1; // Character count. -1 because null terminator here too
utf16_string.resize(size);
std::memcpy(utf16_string.data(), vec.data(), size * sizeof(u16));
break;
};
}
}
};
struct FilePerms {
u32 raw;
u32 raw;
FilePerms(u32 val) : raw(val) {}
bool read() const { return (raw & 1) != 0; }
bool write() const { return (raw & 2) != 0; }
bool create() const { return (raw & 4) != 0; }
FilePerms(u32 val) : raw(val) {}
bool read() const { return (raw & 1) != 0; }
bool write() const { return (raw & 2) != 0; }
bool create() const { return (raw & 4) != 0; }
};
class ArchiveBase;
struct FileSession {
ArchiveBase* archive = nullptr;
FILE* fd = nullptr; // File descriptor for file sessions that require them.
FSPath path;
FSPath archivePath;
u32 priority = 0; // TODO: What does this even do
bool isOpen;
ArchiveBase* archive = nullptr;
FILE* fd = nullptr; // File descriptor for file sessions that require them.
FSPath path;
FSPath archivePath;
u32 priority = 0; // TODO: What does this even do
bool isOpen;
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) {}
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) {}
// For cloning a file session
FileSession(const FileSession& other) : archive(other.archive), path(other.path),
archivePath(other.archivePath), fd(other.fd), isOpen(other.isOpen), priority(other.priority) {}
// For cloning a file session
FileSession(const FileSession& other)
: archive(other.archive), path(other.path), archivePath(other.archivePath), fd(other.fd), isOpen(other.isOpen), priority(other.priority) {}
};
struct ArchiveSession {
ArchiveBase* archive = nullptr;
FSPath path;
bool isOpen;
ArchiveBase* archive = nullptr;
FSPath path;
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 {
@ -156,106 +155,104 @@ struct DirectorySession {
using FileDescriptor = std::optional<FILE*>;
class ArchiveBase {
public:
struct FormatInfo {
u32 size; // Archive size
u32 numOfDirectories; // Number of directories
u32 numOfFiles; // Number of files
bool duplicateData; // Whether to duplicate data or not
};
public:
struct FormatInfo {
u32 size; // Archive size
u32 numOfDirectories; // Number of directories
u32 numOfFiles; // Number of files
bool duplicateData; // Whether to duplicate data or not
};
protected:
using Handle = u32;
protected:
using HandleType = u32;
static constexpr FileDescriptor NoFile = nullptr;
static constexpr FileDescriptor FileError = std::nullopt;
Memory& mem;
static constexpr FileDescriptor NoFile = nullptr;
static constexpr FileDescriptor FileError = std::nullopt;
Memory& mem;
// 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
// 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 access files outside of the emulator's app data folder
template <u32 format>
bool isPathSafe(const FSPath& path) {
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 Char = typename String::value_type; // Char type for the path
// 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
// 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 access files outside of the emulator's app data folder
template <u32 format>
bool isPathSafe(const FSPath& path) {
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 Char = typename String::value_type; // Char type for the path
String pathString, dots;
if constexpr (std::is_same<String, std::u16string>()) {
pathString = path.utf16_string;
dots = u"..";
} else {
pathString = path.string;
dots = "..";
}
String pathString, dots;
if constexpr (std::is_same<String, std::u16string>()) {
pathString = path.utf16_string;
dots = u"..";
} else {
pathString = path.string;
dots = "..";
}
// 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 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;
// 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 then this is the FS root.
// If it's > 0 then we're in a subdirectory of the root.
int level = 0;
// 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 then this is the FS root.
// If it's > 0 then we're in a subdirectory of the root.
int level = 0;
// Split the string on / characters and see how many of the substrings are ".."
size_t pos = 0;
while ((pos = pathString.find(Char('/'))) != String::npos) {
String token = pathString.substr(0, pos);
pathString.erase(0, pos + 1);
// Split the string on / characters and see how many of the substrings are ".."
size_t pos = 0;
while ((pos = pathString.find(Char('/'))) != String::npos) {
String token = pathString.substr(0, pos);
pathString.erase(0, pos + 1);
if (token == dots) {
level--;
if (level < 0) return false;
} else {
level++;
}
}
if (token == dots) {
level--;
if (level < 0) return false;
} else {
level++;
}
}
return true;
}
return true;
}
public:
virtual std::string name() = 0;
virtual u64 getFreeBytes() = 0;
virtual HorizonResult createFile(const FSPath& path, u64 size) = 0;
virtual HorizonResult deleteFile(const FSPath& path) = 0;
public:
virtual std::string name() = 0;
virtual u64 getFreeBytes() = 0;
virtual HorizonResult createFile(const FSPath& path, u64 size) = 0;
virtual HorizonResult deleteFile(const FSPath& path) = 0;
virtual Rust::Result<FormatInfo, HorizonResult> getFormatInfo(const FSPath& path) {
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 Ok(FormatInfo{ .size = 0, .numOfDirectories = 0, .numOfFiles = 0, .duplicateData = false });
}
virtual Rust::Result<FormatInfo, HorizonResult> getFormatInfo(const FSPath& path) {
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 Ok(FormatInfo{.size = 0, .numOfDirectories = 0, .numOfFiles = 0, .duplicateData = false});
}
virtual HorizonResult createDirectory(const FSPath& path) {
Helpers::panic("Unimplemented CreateDirectory for %s archive", name().c_str());
return Result::FS::AlreadyExists;
}
virtual HorizonResult createDirectory(const FSPath& path) {
Helpers::panic("Unimplemented CreateDirectory for %s archive", name().c_str());
return Result::FS::AlreadyExists;
}
// 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 Rust::Result<ArchiveBase*, HorizonResult> openArchive(const FSPath& path) = 0;
// 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 Rust::Result<ArchiveBase*, HorizonResult> openArchive(const FSPath& path) = 0;
virtual Rust::Result<DirectorySession, HorizonResult> openDirectory(const FSPath& path) {
Helpers::panic("Unimplemented OpenDirectory for %s archive", name().c_str());
return Err(Result::FS::FileNotFoundAlt);
}
virtual Rust::Result<DirectorySession, HorizonResult> openDirectory(const FSPath& path) {
Helpers::panic("Unimplemented OpenDirectory for %s archive", name().c_str());
return Err(Result::FS::FileNotFoundAlt);
}
virtual void format(const FSPath& path, const FormatInfo& info) {
Helpers::panic("Unimplemented Format for %s archive", name().c_str());
}
virtual void format(const FSPath& path, const FormatInfo& info) { 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());
return Result::Success;
}
}
// 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
virtual std::optional<u32> readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) = 0;
// 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
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 {
@ -263,4 +260,4 @@ struct ArchiveResource {
u32 clusterSize; // Size of a cluster in bytes
u32 partitionCapacityInClusters;
u32 freeSpaceInClusters;
};
};

View file

@ -1,23 +1,23 @@
#pragma once
#include "helpers.hpp"
using Handle = u32;
using HandleType = u32;
namespace KernelHandles {
enum : u32 {
Max = 0xFFFF7FFF, // Max handle the kernel can automagically allocate
Max = 0xFFFF7FFF, // Max handle the kernel can automagically allocate
// Hardcoded handles
CurrentThread = 0xFFFF8000, // Used by the original kernel
CurrentProcess = 0xFFFF8001, // Used by the original kernel
AC, // Something network related
ACT, // Handles NNID accounts
AM, // Application manager
APT, // App Title something service?
BOSS, // Streetpass stuff?
CAM, // Camera service
CECD, // More Streetpass stuff?
CFG_U, // CFG service (Console & region info)
CurrentThread = 0xFFFF8000, // Used by the original kernel
CurrentProcess = 0xFFFF8001, // Used by the original kernel
AC, // Something network related
ACT, // Handles NNID accounts
AM, // Application manager
APT, // App Title something service?
BOSS, // Streetpass stuff?
CAM, // Camera service
CECD, // More Streetpass stuff?
CFG_U, // CFG service (Console & region info)
CFG_I,
CFG_S, // Used by most system apps in lieu of cfg:u
CSND, // Plays audio directly from PCM samples
@ -50,10 +50,10 @@ namespace KernelHandles {
MinServiceHandle = AC,
MaxServiceHandle = Y2R,
GSPSharedMemHandle = MaxServiceHandle + 1, // Handle for the GSP shared memory
GSPSharedMemHandle = MaxServiceHandle + 1, // HandleType for the GSP shared memory
FontSharedMemHandle,
CSNDSharedMemHandle,
APTCaptureSharedMemHandle, // Shared memory for display capture info,
APTCaptureSharedMemHandle, // Shared memory for display capture info,
HIDSharedMemHandle,
MinSharedMemHandle = GSPSharedMemHandle,
@ -61,17 +61,13 @@ namespace KernelHandles {
};
// Returns whether "handle" belongs to one of the OS services
static constexpr bool isServiceHandle(Handle handle) {
return handle >= MinServiceHandle && handle <= MaxServiceHandle;
}
static constexpr bool isServiceHandle(HandleType handle) { return handle >= MinServiceHandle && handle <= MaxServiceHandle; }
// Returns whether "handle" belongs to one of the OS services' shared memory areas
static constexpr bool isSharedMemHandle(Handle handle) {
return handle >= MinSharedMemHandle && handle <= MaxSharedMemHandle;
}
static constexpr bool isSharedMemHandle(HandleType handle) { return handle >= MinSharedMemHandle && handle <= MaxSharedMemHandle; }
// 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) {
case AC: return "AC";
case ACT: return "ACT";
@ -110,4 +106,4 @@ namespace KernelHandles {
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");
std::vector<KernelObject> objects;
std::vector<Handle> portHandles;
std::vector<Handle> mutexHandles;
std::vector<Handle> timerHandles;
std::vector<HandleType> portHandles;
std::vector<HandleType> mutexHandles;
std::vector<HandleType> timerHandles;
// Thread indices, sorted by priority
std::vector<int> threadIndices;
Handle currentProcess;
Handle mainThread;
HandleType currentProcess;
HandleType mainThread;
int currentThreadIndex;
Handle srvHandle; // Handle for the special service manager port "srv:"
Handle errorPortHandle; // Handle for the err:f port used for displaying errors
HandleType srvHandle; // HandleType for the special service manager port "srv:"
HandleType errorPortHandle; // HandleType for the err:f port used for displaying errors
u32 arbiterCount;
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 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?
ServiceManager serviceManager;
// 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
bool needReschedule = false;
Handle makeArbiter();
Handle makeProcess(u32 id);
Handle makePort(const char* name);
Handle makeSession(Handle port);
Handle 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 makeArbiter();
HandleType makeProcess(u32 id);
HandleType makePort(const char* name);
HandleType makeSession(HandleType port);
HandleType makeThread(u32 entrypoint, u32 initialSP, u32 priority, ProcessorID id, u32 arg, ThreadStatus status = ThreadStatus::Dormant);
HandleType makeMemoryBlock(u32 addr, u32 size, u32 myPermission, u32 otherPermission);
public:
public:
// 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
Handle makeMutex(bool locked = false);
HandleType makeMutex(bool locked = false);
// Needs to be public to be accessible to the service manager port
Handle makeSemaphore(u32 initialCount, u32 maximumCount);
Handle makeTimer(ResetType resetType);
HandleType makeSemaphore(u32 initialCount, u32 maximumCount);
HandleType makeTimer(ResetType resetType);
void pollTimers();
// 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
void runEventCallback(Event::CallbackType callback);
void clearEvent(Handle e) {
void clearEvent(HandleType e) {
KernelObject* object = getObject(e, KernelObjectType::Event);
if (object != nullptr) {
object->getData<Event>()->fired = false;
@ -99,19 +99,19 @@ public:
bool shouldWaitOnObject(KernelObject* object);
void releaseMutex(Mutex* moo);
void cancelTimer(Timer* timer);
void signalTimer(Handle timerHandle, Timer* timer);
void signalTimer(HandleType timerHandle, Timer* timer);
u64 getWakeupTick(s64 ns);
// Wake up the thread with the highest priority out of all threads in the waitlist
// Returns the index of the woken up thread
// Do not call this function with an empty waitlist!!!
int wakeupOneThread(u64 waitlist, Handle handle);
void wakeupAllThreads(u64 waitlist, Handle handle);
int wakeupOneThread(u64 waitlist, HandleType 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);
KernelObject* getProcessFromPID(Handle handle);
KernelObject* getProcessFromPID(HandleType handle);
s32 getCurrentResourceValue(const KernelObject* limit, u32 resourceName);
u32 getMaxForResource(const KernelObject* limit, u32 resourceName);
u32 getTLSPointer();
@ -178,22 +178,22 @@ public:
void waitSynchronizationN();
// File operations
void handleFileOperation(u32 messagePointer, Handle file);
void closeFile(u32 messagePointer, Handle file);
void flushFile(u32 messagePointer, Handle file);
void readFile(u32 messagePointer, Handle file);
void writeFile(u32 messagePointer, Handle file);
void getFileSize(u32 messagePointer, Handle file);
void openLinkFile(u32 messagePointer, Handle file);
void setFileSize(u32 messagePointer, Handle file);
void setFilePriority(u32 messagePointer, Handle file);
void handleFileOperation(u32 messagePointer, HandleType file);
void closeFile(u32 messagePointer, HandleType file);
void flushFile(u32 messagePointer, HandleType file);
void readFile(u32 messagePointer, HandleType file);
void writeFile(u32 messagePointer, HandleType file);
void getFileSize(u32 messagePointer, HandleType file);
void openLinkFile(u32 messagePointer, HandleType file);
void setFileSize(u32 messagePointer, HandleType file);
void setFilePriority(u32 messagePointer, HandleType file);
// Directory operations
void handleDirectoryOperation(u32 messagePointer, Handle directory);
void closeDirectory(u32 messagePointer, Handle directory);
void readDirectory(u32 messagePointer, Handle directory);
void handleDirectoryOperation(u32 messagePointer, HandleType directory);
void closeDirectory(u32 messagePointer, HandleType directory);
void readDirectory(u32 messagePointer, HandleType directory);
public:
public:
Kernel(CPU& cpu, Memory& mem, GPU& gpu, const EmulatorConfig& config);
void initializeFS() { return serviceManager.initializeFS(); }
void setVersion(u8 major, u8 minor);
@ -209,7 +209,7 @@ public:
}
}
Handle makeObject(KernelObjectType type) {
HandleType makeObject(KernelObjectType type) {
if (handleCounter > KernelHandles::Max) [[unlikely]] {
Helpers::panic("Hlep we somehow created enough kernel objects to overflow this thing");
}
@ -219,12 +219,10 @@ public:
return handleCounter++;
}
std::vector<KernelObject>& getObjects() {
return objects;
}
std::vector<KernelObject>& getObjects() { return objects; }
// 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
if (handle >= objects.size()) [[unlikely]] {
return nullptr;
@ -234,7 +232,7 @@ public:
}
// 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]] {
return nullptr;
}
@ -246,4 +244,4 @@ public:
void sendGPUInterrupt(GPUInterrupt type) { serviceManager.sendGPUInterrupt(type); }
void clearInstructionCache();
};
};

View file

@ -1,98 +1,102 @@
#pragma once
#include <array>
#include <cstring>
#include "fs/archive_base.hpp"
#include "handles.hpp"
#include "helpers.hpp"
#include "result/result.hpp"
enum class KernelObjectType : u8 {
AddressArbiter, Archive, 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
AddressArbiter,
Archive,
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 {
Application = 0,
SystemApplet = 1,
LibraryApplet = 2,
Misc = 3
};
enum class ResourceLimitCategory : int { Application = 0, SystemApplet = 1, LibraryApplet = 2, Misc = 3 };
// Reset types (for use with events and timers)
enum class ResetType {
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.
Pulse = 2, // Only meaningful for timers: same as ONESHOT but it will periodically signal the timer instead of just once.
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.
Pulse = 2, // Only meaningful for timers: same as ONESHOT but it will periodically signal the timer instead of just once.
};
enum class ArbitrationType {
Signal = 0,
WaitIfLess = 1,
DecrementAndWaitIfLess = 2,
WaitIfLessTimeout = 3,
DecrementAndWaitIfLessTimeout = 4
};
enum class ArbitrationType { Signal = 0, WaitIfLess = 1, DecrementAndWaitIfLess = 2, WaitIfLessTimeout = 3, DecrementAndWaitIfLessTimeout = 4 };
enum class ProcessorID : s32 {
AllCPUs = -1,
Default = -2,
AppCore = 0,
Syscore = 1,
New3DSExtra1 = 2,
New3DSExtra2 = 3
AllCPUs = -1,
Default = -2,
AppCore = 0,
Syscore = 1,
New3DSExtra1 = 2,
New3DSExtra2 = 3
};
struct AddressArbiter {};
struct ResourceLimits {
Handle handle;
HandleType handle;
s32 currentCommit = 0;
s32 currentCommit = 0;
};
struct Process {
// Resource limits for this process
ResourceLimits limits;
// Process ID
u32 id;
// Resource limits for this process
ResourceLimits limits;
// Process ID
u32 id;
Process(u32 id) : id(id) {}
Process(u32 id) : id(id) {}
};
struct Event {
// 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
enum class CallbackType : u32 {
None, DSPSemaphore,
};
// 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
enum class CallbackType : u32 {
None,
DSPSemaphore,
};
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;
CallbackType callback = CallbackType::None;
bool fired = false;
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;
CallbackType callback = CallbackType::None;
bool fired = false;
Event(ResetType resetType) : resetType(resetType), waitlist(0) {}
Event(ResetType resetType, CallbackType cb) : resetType(resetType), waitlist(0), callback(cb) {}
Event(ResetType resetType) : resetType(resetType), waitlist(0) {}
Event(ResetType resetType, CallbackType cb) : resetType(resetType), waitlist(0), callback(cb) {}
};
struct Port {
static constexpr u32 maxNameLen = 11;
static constexpr u32 maxNameLen = 11;
char name[maxNameLen + 1] = {};
bool isPublic = false; // Setting name=NULL creates a private port not accessible from svcConnectToPort.
char name[maxNameLen + 1] = {};
bool isPublic = false; // Setting name=NULL creates a private port not accessible from svcConnectToPort.
Port(const char* name) {
// If the name is empty (ie the first char is the null terminator) then the port is private
isPublic = name[0] != '\0';
std::strncpy(this->name, name, maxNameLen);
}
Port(const char* name) {
// If the name is empty (ie the first char is the null terminator) then the port is private
isPublic = name[0] != '\0';
std::strncpy(this->name, name, maxNameLen);
}
};
struct Session {
Handle portHandle; // The port this session is subscribed to
Session(Handle portHandle) : portHandle(portHandle) {}
HandleType portHandle; // The port this session is subscribed to
Session(HandleType portHandle) : portHandle(portHandle) {}
};
enum class ThreadStatus {
@ -115,14 +119,14 @@ struct Thread {
u32 arg;
ProcessorID processorID;
ThreadStatus status;
Handle handle; // OS handle for this thread
int index; // Index of the thread. 0 for the first thread, 1 for the second, and so on
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
// The waiting address for threads that are waiting on an AddressArbiter
u32 waitingAddress;
// 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
bool waitAll;
// For WaitSynchronizationN: The "out" pointer
@ -141,88 +145,86 @@ struct Thread {
};
static const char* kernelObjectTypeToString(KernelObjectType t) {
switch (t) {
case KernelObjectType::AddressArbiter: return "address arbiter";
case KernelObjectType::Archive: return "archive";
case KernelObjectType::Directory: return "directory";
case KernelObjectType::Event: return "event";
case KernelObjectType::File: return "file";
case KernelObjectType::MemoryBlock: return "memory block";
case KernelObjectType::Port: return "port";
case KernelObjectType::Process: return "process";
case KernelObjectType::ResourceLimit: return "resource limit";
case KernelObjectType::Session: return "session";
case KernelObjectType::Mutex: return "mutex";
case KernelObjectType::Semaphore: return "semaphore";
case KernelObjectType::Thread: return "thread";
case KernelObjectType::Dummy: return "dummy";
default: return "unknown";
}
switch (t) {
case KernelObjectType::AddressArbiter: return "address arbiter";
case KernelObjectType::Archive: return "archive";
case KernelObjectType::Directory: return "directory";
case KernelObjectType::Event: return "event";
case KernelObjectType::File: return "file";
case KernelObjectType::MemoryBlock: return "memory block";
case KernelObjectType::Port: return "port";
case KernelObjectType::Process: return "process";
case KernelObjectType::ResourceLimit: return "resource limit";
case KernelObjectType::Session: return "session";
case KernelObjectType::Mutex: return "mutex";
case KernelObjectType::Semaphore: return "semaphore";
case KernelObjectType::Thread: return "thread";
case KernelObjectType::Dummy: return "dummy";
default: return "unknown";
}
}
struct Mutex {
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
Handle handle; // Handle of the mutex itself
u32 lockCount; // Number of times this mutex has been locked by its daddy. 0 = not locked
bool locked;
u64 waitlist; // Refer to the getWaitlist function below for documentation
HandleType ownerThread = 0; // Index of the thread that holds the mutex if it's locked
HandleType handle; // HandleType of the mutex itself
u32 lockCount; // Number of times this mutex has been locked by its daddy. 0 = not 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 {
u64 waitlist; // Refer to the getWaitlist function below for documentation
s32 availableCount;
s32 maximumCount;
u64 waitlist; // Refer to the getWaitlist function below for documentation
s32 availableCount;
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 {
u64 waitlist; // Refer to the getWaitlist function below for documentation
ResetType resetType = ResetType::OneShot;
u64 fireTick; // CPU tick the timer will be fired
u64 interval; // Number of ns until the timer fires for the second and future times
bool fired; // Has this timer been signalled?
bool running; // Is this timer running or stopped?
u64 fireTick; // CPU tick the timer will be fired
u64 interval; // Number of ns until the timer fires for the second and future times
bool fired; // Has this timer been signalled?
bool running; // Is this timer running or stopped?
Timer(ResetType type) : resetType(type), fireTick(0), interval(0), waitlist(0), fired(false), running(false) {}
};
struct MemoryBlock {
u32 addr = 0;
u32 size = 0;
u32 myPermission = 0;
u32 otherPermission = 0;
bool mapped = false;
u32 addr = 0;
u32 size = 0;
u32 myPermission = 0;
u32 otherPermission = 0;
bool mapped = false;
MemoryBlock(u32 addr, u32 size, u32 myPerm, u32 otherPerm) : addr(addr), size(size), myPermission(myPerm), otherPermission(otherPerm),
mapped(false) {}
MemoryBlock(u32 addr, u32 size, u32 myPerm, u32 otherPerm)
: addr(addr), size(size), myPermission(myPerm), otherPermission(otherPerm), mapped(false) {}
};
// Generic kernel object class
struct KernelObject {
Handle handle = 0; // A u32 the OS will use to identify objects
void* data = nullptr;
KernelObjectType type;
HandleType handle = 0; // A u32 the OS will use to identify objects
void* data = nullptr;
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
// Thus, the kernel needs to delete it when appropriate
~KernelObject() {}
// 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
~KernelObject() {}
template <typename T>
T* getData() {
return static_cast<T*>(data);
}
template <typename T>
T* getData() {
return static_cast<T*>(data);
}
const char* getTypeName() const {
return kernelObjectTypeToString(type);
}
const char* getTypeName() const { 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 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.
@ -238,8 +240,7 @@ struct KernelObject {
case KernelObjectType::Timer: return getData<Timer>()->waitlist;
// This should be unreachable once we fully implement sync objects
default: [[unlikely]]
Helpers::panic("Called GetWaitList on kernel object without a waitlist (Type: %s)", getTypeName());
default: [[unlikely]] 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 "handles.hpp"
#include "helpers.hpp"
#include "loader/ncsd.hpp"
#include "loader/3dsx.hpp"
#include "loader/ncsd.hpp"
#include "services/region_codes.hpp"
namespace PhysicalAddrs {
@ -38,7 +38,7 @@ namespace VirtualAddrs {
DefaultStackSize = 0x4000,
NormalHeapStart = 0x08000000,
LinearHeapStartOld = 0x14000000, // If kernel version < 0x22C
LinearHeapStartOld = 0x14000000, // If kernel version < 0x22C
LinearHeapEndOld = 0x1C000000,
LinearHeapStartNew = 0x30000000,
@ -76,37 +76,36 @@ namespace KernelMemoryTypes {
PERMISSION_W = 1 << 1,
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.
// If it's for multiple allocations, it also makes no sense
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 perms; // Is this referring to a single page or?
u32 state;
u32 end() { return baseAddr + size; }
MemoryInfo(u32 baseAddr, u32 size, u32 perms, u32 state) : baseAddr(baseAddr), size(size)
, perms(perms), state(state) {}
MemoryInfo(u32 baseAddr, u32 size, u32 perms, u32 state) : baseAddr(baseAddr), size(size), perms(perms), state(state) {}
};
// Shared memory block for HID, GSP:GPU etc
struct SharedMemoryBlock {
u32 paddr; // Physical address of this block's memory
u32 size; // Size of block
u32 handle; // The handle of the shared memory block
bool mapped; // Has this block been mapped at least once?
u32 paddr; // Physical address of this block's memory
u32 size; // Size of block
u32 handle; // The handle of the shared memory block
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) {}
};
}
} // namespace KernelMemoryTypes
class Memory {
u8* fcram;
u8* dspRam; // Provided to us by Audio
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;
// 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::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(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, 0, KernelHandles::FontSharedMemHandle
), // Shared memory for the system font (size is 0 because we read the size from the cmrc filesystem
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
};
};
public:
public:
static constexpr u32 pageShift = 12;
static constexpr u32 pageSize = 1 << pageShift;
static constexpr u32 pageMask = pageSize - 1;
static constexpr u32 totalPageCount = 1 << (32 - pageShift);
static constexpr u32 FCRAM_SIZE = u32(128_MB);
static constexpr u32 FCRAM_APPLICATION_SIZE = u32(64_MB);
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_DATA_MEMORY_OFFSET = u32(256_KB);
private:
private:
std::bitset<FCRAM_PAGE_COUNT> usedFCRAMPages;
std::optional<u32> findPaddr(u32 size);
u64 timeSince3DSEpoch();
@ -147,9 +148,9 @@ private:
// Report a retail unit without JTAG
static constexpr u32 envInfo = 1;
// Stored in Configuration Memory starting @ 0x1FF80060
// Stored in Configuration Memory starting @ 0x1FF80060
struct FirmwareInfo {
u8 unk; // Usually 0 according to 3DBrew
u8 unk; // Usually 0 according to 3DBrew
u8 revision;
u8 minor;
u8 major;
@ -167,8 +168,8 @@ private:
public:
u16 kernelVersion = 0;
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 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)
Memory(u64& cpuTicks, const EmulatorConfig& config);
void reset();
@ -197,28 +198,20 @@ private:
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)
u32 totalSysFCRAM() {
return FCRAM_SIZE - FCRAM_APPLICATION_SIZE;
}
u32 totalSysFCRAM() { return FCRAM_SIZE - FCRAM_APPLICATION_SIZE; }
// Amount of OS-only FCRAM currently available
u32 remainingSysFCRAM() {
return totalSysFCRAM() - usedSystemMemory;
}
u32 remainingSysFCRAM() { return totalSysFCRAM() - usedSystemMemory; }
// 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
u32 sysFCRAMIndex() {
return FCRAM_APPLICATION_SIZE;
}
u32 sysFCRAMIndex() { return FCRAM_APPLICATION_SIZE; }
enum class BatteryLevel {
Empty = 0, AlmostEmpty, OneBar, TwoBars, ThreeBars, FourBars
};
enum class BatteryLevel { Empty = 0, AlmostEmpty, OneBar, TwoBars, ThreeBars, FourBars };
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
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
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 (charging) value |= 1 << 1; // Bit 1 shows if we're charging
return value;
}
@ -240,9 +233,7 @@ private:
}
// Returns whether "addr" is aligned to a page (4096 byte) boundary
static constexpr bool isAligned(u32 addr) {
return (addr & pageMask) == 0;
}
static constexpr bool isAligned(u32 addr) { return (addr & pageMask) == 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).
@ -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,
// 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
std::optional<u32> allocateMemory(u32 vaddr, u32 paddr, u32 size, bool linear, bool r = true, bool w = true, bool x = true,
bool adjustsAddrs = false, bool isMap = false);
std::optional<u32> allocateMemory(
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);
// For internal use
@ -266,7 +258,7 @@ private:
// The kernel has a second permission parameter in MapMemoryBlock but not sure what's used for
// TODO: Find out
// 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
// All of the above must be page-aligned.

View file

@ -119,9 +119,10 @@ class MainWindow : public QMainWindow {
void sendMessage(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 usingVk = false;
bool usingMtl = false;
// 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

View file

@ -1,7 +1,7 @@
#pragma once
#include <array>
#include <span>
#include <optional>
#include <span>
#include "PICA/pica_vertex.hpp"
#include "PICA/regs.hpp"
@ -17,6 +17,7 @@ enum class RendererType : s8 {
OpenGL = 1,
Vulkan = 2,
Software = 3,
Metal = 4,
};
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"
class ACService {
Handle handle = KernelHandles::AC;
HandleType handle = KernelHandles::AC;
Memory& mem;
MAKE_LOG_FUNCTION(log, acLogger)
@ -25,10 +25,10 @@ class ACService {
void setClientVersion(u32 messagePointer);
bool connected = false;
std::optional<Handle> disconnectEvent = std::nullopt;
std::optional<HandleType> disconnectEvent = std::nullopt;
public:
ACService(Memory& mem) : mem(mem) {}
void reset();
void handleSyncRequest(u32 messagePointer);
};
};

View file

@ -6,7 +6,7 @@
#include "result/result.hpp"
class ACTService {
Handle handle = KernelHandles::ACT;
HandleType handle = KernelHandles::ACT;
Memory& mem;
MAKE_LOG_FUNCTION(log, actLogger)
@ -15,8 +15,8 @@ class ACTService {
void generateUUID(u32 messagePointer);
void getAccountDataBlock(u32 messagePointer);
public:
public:
ACTService(Memory& mem) : mem(mem) {}
void reset();
void handleSyncRequest(u32 messagePointer);
};
};

View file

@ -6,7 +6,7 @@
#include "result/result.hpp"
class AMService {
Handle handle = KernelHandles::AM;
HandleType handle = KernelHandles::AM;
Memory& mem;
MAKE_LOG_FUNCTION(log, amLogger)
@ -15,8 +15,8 @@ class AMService {
void getPatchTitleInfo(u32 messagePointer);
void listTitleInfo(u32 messagePointer);
public:
public:
AMService(Memory& mem) : mem(mem) {}
void reset();
void handleSyncRequest(u32 messagePointer);
};
};

View file

@ -1,19 +1,17 @@
#pragma once
#include <optional>
#include "applets/applet_manager.hpp"
#include "helpers.hpp"
#include "kernel_types.hpp"
#include "logger.hpp"
#include "memory.hpp"
#include "result/result.hpp"
#include "applets/applet_manager.hpp"
// Yay, more circular dependencies
class Kernel;
enum class ConsoleModel : u32 {
Old3DS, New3DS
};
enum class ConsoleModel : u32 { Old3DS, New3DS };
// https://www.3dbrew.org/wiki/NS_and_APT_Services#Command
namespace APT::Transitions {
@ -41,13 +39,13 @@ namespace APT::Transitions {
}
class APTService {
Handle handle = KernelHandles::APT;
HandleType handle = KernelHandles::APT;
Memory& mem;
Kernel& kernel;
std::optional<Handle> lockHandle = std::nullopt;
std::optional<Handle> notificationEvent = std::nullopt;
std::optional<Handle> resumeEvent = std::nullopt;
std::optional<HandleType> lockHandle = std::nullopt;
std::optional<HandleType> notificationEvent = std::nullopt;
std::optional<HandleType> resumeEvent = std::nullopt;
ConsoleModel model = ConsoleModel::Old3DS;
Applets::AppletManager appletManager;
@ -99,8 +97,8 @@ class APTService {
u32 screencapPostPermission;
public:
public:
APTService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel), appletManager(mem) {}
void reset();
void handleSyncRequest(u32 messagePointer);
};
};

View file

@ -6,7 +6,7 @@
#include "result/result.hpp"
class BOSSService {
Handle handle = KernelHandles::BOSS;
HandleType handle = KernelHandles::BOSS;
Memory& mem;
MAKE_LOG_FUNCTION(log, bossLogger)
@ -17,7 +17,7 @@ class BOSSService {
void getNewArrivalFlag(u32 messagePointer);
void getNsDataIdList(u32 messagePointer, u32 commandWord);
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 getTaskInfo(u32 messagePointer);
void getTaskServiceStatus(u32 messagePointer);
@ -35,8 +35,9 @@ class BOSSService {
void unregisterTask(u32 messagePointer);
s8 optoutFlag;
public:
public:
BOSSService(Memory& mem) : mem(mem) {}
void reset();
void handleSyncRequest(u32 messagePointer);
};
};

View file

@ -12,7 +12,7 @@
class Kernel;
class CAMService {
using Event = std::optional<Handle>;
using Event = std::optional<HandleType>;
struct Port {
Event bufferErrorInterruptEvent = std::nullopt;
@ -26,7 +26,7 @@ class CAMService {
}
};
Handle handle = KernelHandles::CAM;
HandleType handle = KernelHandles::CAM;
Memory& mem;
Kernel& kernel;
MAKE_LOG_FUNCTION(log, camLogger)
@ -56,4 +56,4 @@ class CAMService {
CAMService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
void reset();
void handleSyncRequest(u32 messagePointer);
};
};

View file

@ -1,5 +1,6 @@
#pragma once
#include <optional>
#include "helpers.hpp"
#include "kernel_types.hpp"
#include "logger.hpp"
@ -9,19 +10,19 @@
class Kernel;
class CECDService {
Handle handle = KernelHandles::CECD;
HandleType handle = KernelHandles::CECD;
Memory& mem;
Kernel& kernel;
MAKE_LOG_FUNCTION(log, cecdLogger)
std::optional<Handle> infoEvent;
std::optional<HandleType> infoEvent;
// Service commands
void getInfoEventHandle(u32 messagePointer);
void openAndRead(u32 messagePointer);
public:
public:
CECDService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
void reset();
void handleSyncRequest(u32 messagePointer);
};
};

View file

@ -10,13 +10,13 @@
class Kernel;
class CSNDService {
Handle handle = KernelHandles::CSND;
HandleType handle = KernelHandles::CSND;
Memory& mem;
Kernel& kernel;
MAKE_LOG_FUNCTION(log, csndLogger)
u8* sharedMemory = nullptr;
std::optional<Handle> csndMutex = std::nullopt;
std::optional<HandleType> csndMutex = std::nullopt;
size_t sharedMemSize = 0;
bool initialized = false;
@ -30,7 +30,5 @@ class CSNDService {
void reset();
void handleSyncRequest(u32 messagePointer);
void setSharedMemory(u8* ptr) {
sharedMemory = ptr;
}
};
void setSharedMemory(u8* ptr) { sharedMemory = ptr; }
};

View file

@ -8,15 +8,15 @@
// Please forgive me for how everything in this file is named
// "dlp:SRVR" is not a nice name to work with
class DlpSrvrService {
Handle handle = KernelHandles::DLP_SRVR;
HandleType handle = KernelHandles::DLP_SRVR;
Memory& mem;
MAKE_LOG_FUNCTION(log, dlpSrvrLogger)
// Service commands
void isChild(u32 messagePointer);
public:
public:
DlpSrvrService(Memory& mem) : mem(mem) {}
void reset();
void handleSyncRequest(u32 messagePointer);
};
};

View file

@ -14,7 +14,7 @@
class Kernel;
class DSPService {
Handle handle = KernelHandles::DSP;
HandleType handle = KernelHandles::DSP;
Memory& mem;
Kernel& kernel;
Audio::DSPCore* dsp = nullptr;
@ -24,7 +24,7 @@ class DSPService {
static constexpr size_t pipeCount = 8;
// DSP service event handles
using DSPEvent = std::optional<Handle>;
using DSPEvent = std::optional<HandleType>;
DSPEvent semaphoreEvent;
DSPEvent interrupt0;
@ -82,4 +82,4 @@ class DSPService {
void triggerInterrupt1();
ComponentDumpResult dumpComponent(const std::filesystem::path& path);
};
};

View file

@ -16,7 +16,7 @@
class Kernel;
class FSService {
Handle handle = KernelHandles::FS;
HandleType handle = KernelHandles::FS;
Memory& mem;
Kernel& kernel;
@ -38,9 +38,9 @@ class FSService {
SystemSaveDataArchive systemSaveData;
ArchiveBase* getArchiveFromID(u32 id, const FSPath& archivePath);
Rust::Result<Handle, HorizonResult> openArchiveHandle(u32 archiveID, const FSPath& path);
Rust::Result<Handle, HorizonResult> openDirectoryHandle(ArchiveBase* archive, const FSPath& path);
std::optional<Handle> openFileHandle(ArchiveBase* archive, const FSPath& path, const FSPath& archivePath, const FilePerms& perms);
Rust::Result<HandleType, HorizonResult> openArchiveHandle(u32 archiveID, const FSPath& path);
Rust::Result<HandleType, HorizonResult> openDirectoryHandle(ArchiveBase* archive, const FSPath& path);
std::optional<HandleType> openFileHandle(ArchiveBase* archive, const FSPath& path, const FSPath& archivePath, const FilePerms& perms);
FSPath readPath(u32 type, u32 pointer, u32 size);
const EmulatorConfig& config;
@ -81,7 +81,7 @@ class FSService {
// Used for set/get priority: Not sure what sort of priority this is referring to
u32 priority;
public:
public:
FSService(Memory& mem, Kernel& kernel, const EmulatorConfig& config)
: 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),
@ -91,4 +91,4 @@ public:
void handleSyncRequest(u32 messagePointer);
// Creates directories for NAND, ExtSaveData, etc if they don't already exist. Should be executed after loading a new ROM.
void initializeFilesystem();
};
};

View file

@ -1,6 +1,7 @@
#pragma once
#include <cstring>
#include <optional>
#include "PICA/gpu.hpp"
#include "helpers.hpp"
#include "kernel_types.hpp"
@ -9,12 +10,12 @@
#include "result/result.hpp"
enum class GPUInterrupt : u8 {
PSC0 = 0, // Memory fill completed
PSC1 = 1, // ?
VBlank0 = 2, // ?
VBlank1 = 3, // ?
PPF = 4, // Display transfer finished
P3D = 5, // Command list processing finished
PSC0 = 0, // Memory fill completed
PSC1 = 1, // ?
VBlank0 = 2, // ?
VBlank1 = 3, // ?
PPF = 4, // Display transfer finished
P3D = 5, // Command list processing finished
DMA = 6
};
@ -22,17 +23,17 @@ enum class GPUInterrupt : u8 {
class Kernel;
class GPUService {
Handle handle = KernelHandles::GPU;
HandleType handle = KernelHandles::GPU;
Memory& mem;
GPU& gpu;
Kernel& kernel;
u32& currentPID; // Process ID of the current process
u8* sharedMem; // Pointer to GSP shared memory
u32& currentPID; // Process ID of the current process
u8* sharedMem; // Pointer to GSP shared memory
// At any point in time only 1 process has privileges to use rendering functions
// This is the PID of that process
u32 privilegedProcess;
std::optional<Handle> interruptEvent;
std::optional<HandleType> interruptEvent;
// Number of threads registered via RegisterInterruptRelayQueue
u32 gspThreadCount = 0;
@ -62,8 +63,8 @@ class GPUService {
// Used for saving and restoring GPU state via ImportDisplayCaptureInfo
struct CaptureInfo {
u32 leftFramebuffer; // Left framebuffer VA
u32 rightFramebuffer; // Right framebuffer VA (Top screen only)
u32 leftFramebuffer; // Left framebuffer VA
u32 rightFramebuffer; // Right framebuffer VA (Top screen only)
u32 format;
u32 stride;
};
@ -106,15 +107,14 @@ class GPUService {
FramebufferUpdate* getTopFramebufferInfo() { return getFramebufferInfo(0); }
FramebufferUpdate* getBottomFramebufferInfo() { return getFramebufferInfo(1); }
public:
GPUService(Memory& mem, GPU& gpu, Kernel& kernel, u32& currentPID) : mem(mem), gpu(gpu),
kernel(kernel), currentPID(currentPID) {}
public:
GPUService(Memory& mem, GPU& gpu, Kernel& kernel, u32& currentPID) : mem(mem), gpu(gpu), kernel(kernel), currentPID(currentPID) {}
void reset();
void handleSyncRequest(u32 messagePointer);
void requestInterrupt(GPUInterrupt type);
void setSharedMem(u8* 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);
}
}

View file

@ -6,14 +6,14 @@
#include "result/result.hpp"
class LCDService {
Handle handle = KernelHandles::LCD;
HandleType handle = KernelHandles::LCD;
Memory& mem;
MAKE_LOG_FUNCTION(log, gspLCDLogger)
// Service commands
public:
public:
LCDService(Memory& mem) : mem(mem) {}
void reset();
void handleSyncRequest(u32 messagePointer);
};
};

View file

@ -38,7 +38,7 @@ namespace HID::Keys {
class Kernel;
class HIDService {
Handle handle = KernelHandles::HID;
HandleType handle = KernelHandles::HID;
Memory& mem;
Kernel& kernel;
u8* sharedMem = nullptr; // Pointer to HID shared memory
@ -60,7 +60,7 @@ class HIDService {
bool gyroEnabled;
bool touchScreenPressed;
std::array<std::optional<Handle>, 5> events;
std::array<std::optional<HandleType>, 5> events;
MAKE_LOG_FUNCTION(log, hidLogger)
@ -141,9 +141,7 @@ class HIDService {
touchScreenPressed = true;
}
void releaseTouchScreen() {
touchScreenPressed = false;
}
void releaseTouchScreen() { touchScreenPressed = false; }
bool isTouchScreenPressed() { return touchScreenPressed; }
};

View file

@ -5,7 +5,7 @@
#include "memory.hpp"
class HTTPService {
Handle handle = KernelHandles::HTTP;
HandleType handle = KernelHandles::HTTP;
Memory& mem;
MAKE_LOG_FUNCTION(log, httpLogger)
@ -20,4 +20,4 @@ class HTTPService {
HTTPService(Memory& mem) : mem(mem) {}
void reset();
void handleSyncRequest(u32 messagePointer);
};
};

View file

@ -15,7 +15,7 @@ class IRUserService {
CirclePadPro = 1,
};
Handle handle = KernelHandles::IR_USER;
HandleType handle = KernelHandles::IR_USER;
Memory& mem;
Kernel& kernel;
MAKE_LOG_FUNCTION(log, irUserLogger)
@ -29,7 +29,7 @@ class IRUserService {
void requireConnection(u32 messagePointer);
void sendIrnop(u32 messagePointer);
using IREvent = std::optional<Handle>;
using IREvent = std::optional<HandleType>;
IREvent connectionStatusEvent = std::nullopt;
IREvent receiveEvent = std::nullopt;
@ -58,4 +58,4 @@ class IRUserService {
IRUserService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
void reset();
void handleSyncRequest(u32 messagePointer);
};
};

View file

@ -8,7 +8,7 @@
class Kernel;
class LDRService {
Handle handle = KernelHandles::LDR_RO;
HandleType handle = KernelHandles::LDR_RO;
Memory& mem;
Kernel& kernel;
MAKE_LOG_FUNCTION(log, ldrLogger)
@ -22,8 +22,8 @@ class LDRService {
void loadCRR(u32 messagePointer);
void unloadCRO(u32 messagePointer);
public:
public:
LDRService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
void reset();
void handleSyncRequest(u32 messagePointer);
};
};

View file

@ -7,7 +7,7 @@
namespace MCU {
class HWCService {
Handle handle = KernelHandles::MCU_HWC;
HandleType handle = KernelHandles::MCU_HWC;
Memory& mem;
MAKE_LOG_FUNCTION(log, mcuLogger)
@ -21,4 +21,4 @@ namespace MCU {
void reset();
void handleSyncRequest(u32 messagePointer);
};
} // namespace MCU
} // namespace MCU

View file

@ -9,7 +9,7 @@
class Kernel;
class MICService {
Handle handle = KernelHandles::MIC;
HandleType handle = KernelHandles::MIC;
Memory& mem;
Kernel& kernel;
MAKE_LOG_FUNCTION(log, micLogger)
@ -29,15 +29,15 @@ class MICService {
void unmapSharedMem(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 shouldClamp = false;
bool currentlySampling = false;
std::optional<Handle> eventHandle;
std::optional<HandleType> eventHandle;
public:
public:
MICService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
void reset();
void handleSyncRequest(u32 messagePointer);
};
};

View file

@ -8,7 +8,7 @@
class NDMService {
enum class ExclusiveState : u32 { None = 0, Infrastructure = 1, LocalComms = 2, StreetPass = 3, StreetPassData = 4 };
Handle handle = KernelHandles::NDM;
HandleType handle = KernelHandles::NDM;
Memory& mem;
MAKE_LOG_FUNCTION(log, ndmLogger)
@ -25,8 +25,8 @@ class NDMService {
ExclusiveState exclusiveState = ExclusiveState::None;
public:
public:
NDMService(Memory& mem) : mem(mem) {}
void reset();
void handleSyncRequest(u32 messagePointer);
};
};

View file

@ -5,7 +5,7 @@
#include "memory.hpp"
class NewsUService {
Handle handle = KernelHandles::NEWS_U;
HandleType handle = KernelHandles::NEWS_U;
Memory& mem;
MAKE_LOG_FUNCTION(log, newsLogger)
@ -15,4 +15,4 @@ class NewsUService {
NewsUService(Memory& mem) : mem(mem) {}
void reset();
void handleSyncRequest(u32 messagePointer);
};
};

View file

@ -12,7 +12,7 @@
class Kernel;
class NFCService {
Handle handle = KernelHandles::NFC;
HandleType handle = KernelHandles::NFC;
Memory& mem;
Kernel& kernel;
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
std::optional<Handle> tagInRangeEvent, tagOutOfRangeEvent;
std::optional<HandleType> tagInRangeEvent, tagOutOfRangeEvent;
AmiiboDevice device;
Old3DSAdapterStatus adapterStatus;
@ -63,4 +63,4 @@ class NFCService {
void handleSyncRequest(u32 messagePointer);
bool loadAmiibo(const std::filesystem::path& path);
};
};

View file

@ -6,15 +6,15 @@
#include "result/result.hpp"
class NIMService {
Handle handle = KernelHandles::NIM;
HandleType handle = KernelHandles::NIM;
Memory& mem;
MAKE_LOG_FUNCTION(log, nimLogger)
// Service commands
void initialize(u32 messagePointer);
public:
public:
NIMService(Memory& mem) : mem(mem) {}
void reset();
void handleSyncRequest(u32 messagePointer);
};
};

View file

@ -10,13 +10,13 @@
class Kernel;
class NwmUdsService {
Handle handle = KernelHandles::NWM_UDS;
HandleType handle = KernelHandles::NWM_UDS;
Memory& mem;
Kernel& kernel;
MAKE_LOG_FUNCTION(log, nwmUdsLogger)
bool initialized = false;
std::optional<Handle> eventHandle = std::nullopt;
std::optional<HandleType> eventHandle = std::nullopt;
// Service commands
void initializeWithVersion(u32 messagePointer);
@ -25,4 +25,4 @@ class NwmUdsService {
NwmUdsService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
void reset();
void handleSyncRequest(u32 messagePointer);
};
};

View file

@ -28,10 +28,10 @@
#include "services/mcu/mcu_hwc.hpp"
#include "services/mic.hpp"
#include "services/ndm.hpp"
#include "services/nwm_uds.hpp"
#include "services/news_u.hpp"
#include "services/nfc.hpp"
#include "services/nim.hpp"
#include "services/nwm_uds.hpp"
#include "services/ptm.hpp"
#include "services/soc.hpp"
#include "services/ssl.hpp"
@ -46,15 +46,15 @@ class ServiceManager {
Memory& mem;
Kernel& kernel;
std::optional<Handle> notificationSemaphore;
std::optional<HandleType> notificationSemaphore;
MAKE_LOG_FUNCTION(log, srvLogger)
ACService ac;
ACService ac;
ACTService act;
AMService am;
AMService am;
APTService apt;
BOSSService boss;
BOSSService boss;
CAMService cam;
CECDService cecd;
CFGService cfg;
@ -74,7 +74,7 @@ class ServiceManager {
NewsUService news_u;
NFCService nfc;
NwmUdsService nwm_uds;
NIMService nim;
NIMService nim;
PTMService ptm;
SOCService soc;
SSLService ssl;
@ -97,7 +97,7 @@ class ServiceManager {
void handleSyncRequest(u32 messagePointer);
// 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
void sendGPUInterrupt(GPUInterrupt type) { gsp_gpu.requestInterrupt(type); }

View file

@ -5,7 +5,7 @@
#include "memory.hpp"
class SOCService {
Handle handle = KernelHandles::SOC;
HandleType handle = KernelHandles::SOC;
Memory& mem;
MAKE_LOG_FUNCTION(log, socLogger)
@ -14,8 +14,8 @@ class SOCService {
// Service commands
void initializeSockets(u32 messagePointer);
public:
public:
SOCService(Memory& mem) : mem(mem) {}
void reset();
void handleSyncRequest(u32 messagePointer);
};
};

View file

@ -1,17 +1,17 @@
#pragma once
#include <random>
#include "helpers.hpp"
#include "kernel_types.hpp"
#include "logger.hpp"
#include "memory.hpp"
#include <random>
class SSLService {
Handle handle = KernelHandles::SSL;
HandleType handle = KernelHandles::SSL;
Memory& mem;
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;
// Service commands
@ -22,4 +22,4 @@ class SSLService {
SSLService(Memory& mem) : mem(mem) {}
void reset();
void handleSyncRequest(u32 messagePointer);
};
};

View file

@ -1,6 +1,7 @@
#pragma once
#include <array>
#include <optional>
#include "helpers.hpp"
#include "kernel_types.hpp"
#include "logger.hpp"
@ -10,18 +11,15 @@
class Kernel;
class Y2RService {
Handle handle = KernelHandles::Y2R;
HandleType handle = KernelHandles::Y2R;
Memory& mem;
Kernel& kernel;
MAKE_LOG_FUNCTION(log, y2rLogger)
std::optional<Handle> transferEndEvent;
std::optional<HandleType> transferEndEvent;
bool transferEndInterruptEnabled;
enum class BusyStatus : u32 {
NotBusy = 0,
Busy = 1
};
enum class BusyStatus : u32 { NotBusy = 0, Busy = 1 };
enum class InputFormat : u32 {
YUV422_Individual8 = 0,
@ -31,24 +29,14 @@ class Y2RService {
YUV422_Batch = 4,
};
enum class OutputFormat : u32 {
RGB32 = 0,
RGB24 = 1,
RGB15 = 2,
RGB565 = 3
};
enum class OutputFormat : u32 { RGB32 = 0, RGB24 = 1, RGB15 = 2, RGB565 = 3 };
// Clockwise rotation
enum class Rotation : u32 {
None = 0,
Rotate90 = 1,
Rotate180 = 2,
Rotate270 = 3
};
enum class Rotation : u32 { None = 0, Rotate90 = 1, Rotate180 = 2, Rotate270 = 3 };
enum class BlockAlignment : u32 {
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.
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.
};
// 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
}};
CoefficientSet conversionCoefficients; // Current conversion coefficients
CoefficientSet conversionCoefficients; // Current conversion coefficients
InputFormat inputFmt;
OutputFormat outputFmt;
@ -113,8 +101,8 @@ class Y2RService {
void startConversion(u32 messagePointer);
void stopConversion(u32 messagePointer);
public:
public:
Y2RService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
void reset();
void handleSyncRequest(u32 messagePointer);
};
};

View file

@ -40,7 +40,7 @@ void CPU::runFrame() {
execute:
const auto exitReason = jit->Run();
// Handle any scheduler events that need handling.
// HandleType any scheduler events that need handling.
emu.pollScheduler();
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)
#include "PICA/dynapica/shader_rec_emitter_x64.hpp"
#include <immintrin.h>
#include <smmintrin.h>
#include <algorithm>
#include <bit>
#include <cassert>
#include <cstddef>
#include <immintrin.h>
#include <smmintrin.h>
using namespace Xbyak;
using namespace Xbyak::util;
@ -41,9 +42,15 @@ void ShaderEmitter::compile(const PICAShader& shaderUnit) {
// Constants
align(16);
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);
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
align(16);
@ -86,7 +93,7 @@ void ShaderEmitter::scanCode(const PICAShader& shaderUnit) {
if (isCall(instruction)) {
const u32 num = instruction & 0xff;
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);
} else if (opcode == ShaderOpcodes::EX2) {
@ -129,23 +136,15 @@ void ShaderEmitter::compileInstruction(const PICAShader& shaderUnit) {
switch (opcode) {
case ShaderOpcodes::ADD: recADD(shaderUnit, instruction); break;
case ShaderOpcodes::CALL:
recCALL(shaderUnit, instruction);
break;
case ShaderOpcodes::CALLC:
recCALLC(shaderUnit, instruction);
break;
case ShaderOpcodes::CALLU:
recCALLU(shaderUnit, instruction);
break;
case ShaderOpcodes::CMP1: case ShaderOpcodes::CMP2:
recCMP(shaderUnit, instruction);
break;
case ShaderOpcodes::CALL: recCALL(shaderUnit, instruction); break;
case ShaderOpcodes::CALLC: recCALLC(shaderUnit, instruction); 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::DP4: recDP4(shaderUnit, instruction); break;
case ShaderOpcodes::DPH:
case ShaderOpcodes::DPHI:
recDPH(shaderUnit, instruction); break;
case ShaderOpcodes::DPHI: recDPH(shaderUnit, instruction); break;
case ShaderOpcodes::END: recEND(shaderUnit, instruction); break;
case ShaderOpcodes::EX2: recEX2(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;
// 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 0x38: case 0x39: case 0x3A: case 0x3B: case 0x3C: case 0x3D: case 0x3E: case 0x3F:
recMAD(shaderUnit, instruction);
break;
case 0x30:
case 0x31:
case 0x32:
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::SLTI:
recSLT(shaderUnit, instruction); break;
case ShaderOpcodes::SLTI: recSLT(shaderUnit, instruction); break;
case ShaderOpcodes::SGE:
case ShaderOpcodes::SGEI:
recSGE(shaderUnit, instruction); break;
case ShaderOpcodes::SGEI: recSGE(shaderUnit, instruction); break;
default:
Helpers::panic("Shader JIT: Unimplemented PICA opcode %X", opcode);
default: 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
template <int sourceIndex>
void ShaderEmitter::loadRegister(Xmm dest, const PICAShader& shader, u32 src, u32 index, u32 operandDescriptor) {
u32 compSwizzle; // Component swizzle pattern for the register
bool negate; // If true, negate all lanes of the register
u32 compSwizzle; // Component swizzle pattern for 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;
compSwizzle = getBits<5, 8>(operandDescriptor);
}
else if constexpr (sourceIndex == 2) { // SRC2
} else if constexpr (sourceIndex == 2) { // SRC2
negate = (getBit<13>(operandDescriptor)) != 0;
compSwizzle = getBits<14, 8>(operandDescriptor);
}
else if constexpr (sourceIndex == 3) { // SRC3
} else if constexpr (sourceIndex == 3) { // SRC3
negate = (getBit<22>(operandDescriptor)) != 0;
compSwizzle = getBits<23, 8>(operandDescriptor);
}
// 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
u32 convertedSwizzle = ((compSwizzle >> 6) & 0b11) | (((compSwizzle >> 4) & 0b11) << 2) | (((compSwizzle >> 2) & 0b11) << 4) | ((compSwizzle & 0b11) << 6);
// 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
u32 convertedSwizzle =
((compSwizzle >> 6) & 0b11) | (((compSwizzle >> 4) & 0b11) << 2) | (((compSwizzle >> 2) & 0b11) << 4) | ((compSwizzle & 0b11) << 6);
switch (index) {
case 0: [[likely]] { // Keep src as is, no need to offset it
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
case 0:
[[likely]] { // Keep src as is, no need to offset it
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
movaps(dest, xword[statePointer + offset]);
else // Swizzle is not trivial so we need to emit a shuffle instruction
pshufd(dest, xword[statePointer + offset], convertedSwizzle);
if (compSwizzle == noSwizzle) // Avoid emitting swizzle if not necessary
movaps(dest, xword[statePointer + offset]);
else // Swizzle is not trivial so we need to emit a shuffle instruction
pshufd(dest, xword[statePointer + offset], convertedSwizzle);
// Negate the register if necessary
if (negate) {
pxor(dest, xword[rip + negateVector]);
// Negate the register if necessary
if (negate) {
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: {
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;
}
case 2: {
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;
}
case 3: {
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;
}
default:
Helpers::panic("[ShaderJIT]: Unimplemented source index type %d", index);
default: 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
@ -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
swizzleAndLoadReg(inputOffset);
jmp(end);
// If (reg < 0x1F) return tempRegisters[reg - 0x10]
L(maybeTemp);
cmp(rax, 0x20);
@ -324,7 +332,7 @@ void ShaderEmitter::loadRegister(Xmm dest, const PICAShader& shader, u32 src, u3
jmp(end);
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);
// 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) {
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
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);
} 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)
} 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)
size_t index = 3 - bit;
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);
} else { // Shift right by 32 * index, then write bottom lane
} else { // Shift right by 32 * index, then write bottom lane
if (haveAVX) {
vpsrldq(scratch1, source, index * sizeof(float));
} 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
Xmm temp = (source == scratch1) ? scratch2 : scratch1;
movaps(temp, xword[statePointer + offset]); // Read current value of dest
blendps(temp, source, adjustedMask); // Blend with source
movaps(xword[statePointer + offset], temp); // Write back
movaps(temp, xword[statePointer + offset]); // Read current value of dest
blendps(temp, source, adjustedMask); // Blend with source
movaps(xword[statePointer + offset], temp); // Write back
} else {
// Blend algo referenced from Citra
const u8 selector = (((writeMask & 0b1000) ? 1 : 0) << 0) |
(((writeMask & 0b0100) ? 3 : 2) << 2) |
(((writeMask & 0b0010) ? 0 : 1) << 4) |
(((writeMask & 0b0001) ? 2 : 3) << 6);
const u8 selector = (((writeMask & 0b1000) ? 1 : 0) << 0) | (((writeMask & 0b0100) ? 3 : 2) << 2) | (((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,
// 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) {
movaps(scratch1, xword[statePointer + offset]);
movaps(scratch2, source);
@ -382,16 +389,16 @@ void ShaderEmitter::storeRegister(Xmm source, const PICAShader& shader, u32 dest
movaps(scratch2, source);
movaps(scratch1, xword[statePointer + offset]);
}
unpckhps(scratch2, scratch1); // Unpack X/Y 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
movaps(xword[statePointer + offset], scratch1); // Write back
unpckhps(scratch2, scratch1); // Unpack X/Y 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
movaps(xword[statePointer + offset], scratch1); // Write back
}
}
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 cmpRegYOffset = cmpRegXOffset + sizeof(bool);
@ -399,11 +406,12 @@ void ShaderEmitter::checkCmpRegister(const PICAShader& shader, u32 instruction)
const uint refY = getBit<24>(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);
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
// 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
xor_(al, 1);
break;
case 1: // Both cmp registers match
case 1: // Both cmp registers match
cmp(word[statePointer + cmpRegXOffset], refX_refY_merged);
break;
case 2: // At least cmp.x matches
case 2: // At least cmp.x matches
cmp(byte[statePointer + cmpRegXOffset], refX);
break;
default: // At least cmp.y matches
default: // At least cmp.y matches
cmp(byte[statePointer + cmpRegYOffset], refY);
break;
}
}
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);
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 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);
}
@ -460,12 +468,12 @@ void ShaderEmitter::recFLR(const PICAShader& shader, u32 instruction) {
const u32 idx = getBits<19, 2>(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) {
roundps(src1_xmm, src1_xmm, _MM_FROUND_FLOOR);
} else {
cvttps2dq(src1_xmm, src1_xmm); // Truncate and convert to integer
cvtdq2ps(src1_xmm, src1_xmm); // Convert from integer back to float
cvttps2dq(src1_xmm, src1_xmm); // Truncate and convert to integer
cvtdq2ps(src1_xmm, src1_xmm); // Convert from integer back to float
}
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 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);
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 addrRegisterYOffset = addrRegisterOffset + sizeof(shader.addrRegister[0]);
// If no register is being written to then it is a nop. Probably not common but whatever
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
if (writeX && writeY) {
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
}
else if (writeX) {
cvttss2si(eax, src1_xmm); // Convert bottom lane
mov(dword[statePointer + addrRegisterOffset], eax); // Write it back
}
else if (writeY) {
psrldq(src1_xmm, sizeof(float)); // Shift y component to bottom lane
cvttss2si(eax, src1_xmm); // Convert bottom lane
mov(dword[statePointer + addrRegisterYOffset], eax); // Write it back to y component
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
} else if (writeX) {
cvttss2si(eax, src1_xmm); // Convert bottom lane
mov(dword[statePointer + addrRegisterOffset], eax); // Write it back
} else if (writeY) {
psrldq(src1_xmm, sizeof(float)); // Shift y component to bottom lane
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) {
const u32 operandDescriptor = shader.operandDescriptors[instruction & 0x7f];
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 dest = getBits<21, 5>(instruction);
loadRegister<1>(src1_xmm, shader, src1, idx, 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);
}
void ShaderEmitter::recDP3(const PICAShader& shader, u32 instruction) {
const u32 operandDescriptor = shader.operandDescriptors[instruction & 0x7f];
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 dest = getBits<21, 5>(instruction);
// TODO: Safe multiplication equivalent (Multiplication is not IEEE compliant on the PICA)
loadRegister<1>(src1_xmm, shader, src1, idx, 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);
}
void ShaderEmitter::recDP4(const PICAShader& shader, u32 instruction) {
const u32 operandDescriptor = shader.operandDescriptors[instruction & 0x7f];
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 dest = getBits<21, 5>(instruction);
// TODO: Safe multiplication equivalent (Multiplication is not IEEE compliant on the PICA)
loadRegister<1>(src1_xmm, shader, src1, idx, 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);
}
@ -573,7 +579,7 @@ void ShaderEmitter::recDPH(const PICAShader& shader, u32 instruction) {
void ShaderEmitter::recMAX(const PICAShader& shader, u32 instruction) {
const u32 operandDescriptor = shader.operandDescriptors[instruction & 0x7f];
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 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) {
const u32 operandDescriptor = shader.operandDescriptors[instruction & 0x7f];
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 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) {
const u32 operandDescriptor = shader.operandDescriptors[instruction & 0x7f];
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 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 writeMask = operandDescriptor & 0xf;
loadRegister<1>(src1_xmm, shader, src, idx, operandDescriptor); // Load source 1 into scratch1
rcpss(src1_xmm, src1_xmm); // Compute rcp approximation
loadRegister<1>(src1_xmm, shader, src, idx, operandDescriptor); // Load source 1 into scratch1
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
// Otherwise we do
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
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
}
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 writeMask = operandDescriptor & 0xf;
loadRegister<1>(src1_xmm, shader, src, idx, operandDescriptor); // Load source 1 into scratch1
rsqrtss(src1_xmm, src1_xmm); // Compute rsqrt approximation
loadRegister<1>(src1_xmm, shader, src, idx, operandDescriptor); // Load source 1 into scratch1
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
// Otherwise we do
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
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
}
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);
storeRegister(src1_xmm, shader, dest, operandDescriptor);
}
// If we don't have FMA3, do a multiplication and addition
else {
// 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<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
cmpleps(src2_xmm, src1_xmm);
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) {
const u32 operandDescriptor = shader.operandDescriptors[instruction & 0x7f];
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 cmpY = getBits<21, 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);
// Condition codes for cmpps
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
};
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 };
// 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
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 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 cmpRegYOffset = cmpRegXOffset + sizeof(bool);
// Cmp x and y are the same compare function, we can use a single cmp instruction
if (cmpX == cmpY) {
cmpps(lhs_x, rhs_x, compareFuncX);
movq(rax, lhs_x); // Move both comparison results to rax
test(eax, eax); // Check bottom 32 bits first
setne(byte[statePointer + cmpRegXOffset]); // set cmp.x
movq(rax, lhs_x); // Move both comparison results to rax
test(eax, eax); // Check bottom 32 bits first
setne(byte[statePointer + cmpRegXOffset]); // set cmp.x
shr(rax, 32); // Check top 32 bits (shr will set the zero flag properly)
setne(byte[statePointer + cmpRegYOffset]); // set cmp.y
shr(rax, 32); // Check top 32 bits (shr will set the zero flag properly)
setne(byte[statePointer + cmpRegYOffset]); // set cmp.y
} else {
if (haveAVX) {
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(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
} 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);
cmpps(scratch1, rhs_x, compareFuncX); // Perform the compares
cmpps(scratch1, rhs_x, compareFuncX); // Perform the compares
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);
test(eax, eax); // Write back results with setne
test(eax, eax); // Write back results with setne
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]);
}
}
@ -807,10 +803,10 @@ void ShaderEmitter::recIFC(const PICAShader& shader, u32 instruction) {
jnz(elseBlock, T_NEAR);
compileUntil(shader, dest);
if (num == 0) { // Else block is empty,
if (num == 0) { // Else block is empty,
L(elseBlock);
} else { // Else block is NOT empty
jmp(endIf, T_NEAR); // Skip executing the else branch if the if branch was ran
} else { // Else block is NOT empty
jmp(endIf, T_NEAR); // Skip executing the else branch if the if branch was ran
L(elseBlock);
compileUntil(shader, dest + num);
L(endIf);
@ -832,10 +828,10 @@ void ShaderEmitter::recIFU(const PICAShader& shader, u32 instruction) {
jz(elseBlock, T_NEAR);
compileUntil(shader, dest);
if (num == 0) { // Else block is empty,
if (num == 0) { // Else block is empty,
L(elseBlock);
} else { // Else block is NOT empty
jmp(endIf, T_NEAR); // Skip executing the else branch if the if branch was ran
} else { // Else block is NOT empty
jmp(endIf, T_NEAR); // Skip executing the else branch if the if branch was ran
L(elseBlock);
compileUntil(shader, dest + num);
L(endIf);
@ -888,7 +884,7 @@ void ShaderEmitter::recJMPC(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);
Label& l = instructionLabels[dest];
@ -922,13 +918,13 @@ void ShaderEmitter::recLOOP(const PICAShader& shader, u32 instruction) {
// Offset of the loop register
const uintptr_t loopRegOffset = uintptr_t(&shader.loopCounter) - uintptr_t(&shader);
movzx(eax, byte[statePointer + uniformOffset]); // eax = loop iteration count
movzx(ecx, byte[statePointer + uniformOffset + sizeof(u8)]); // ecx = initial loop counter value
movzx(edx, byte[statePointer + uniformOffset + 2 * sizeof(u8)]); // edx = loop increment
movzx(eax, byte[statePointer + uniformOffset]); // eax = loop iteration count
movzx(ecx, byte[statePointer + uniformOffset + sizeof(u8)]); // ecx = initial loop counter value
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...
push(rax); // Push loop iteration counter
push(rdx); // Push loop increment
@ -957,8 +953,8 @@ void ShaderEmitter::recLG2(const PICAShader& shader, u32 instruction) {
const u32 writeMask = getBits<0, 4>(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
shufps(src1_xmm, src1_xmm, 0); // src1_xmm = src1_xmm.xxxx
}
@ -1147,7 +1143,7 @@ Xbyak::Label ShaderEmitter::emitExp2Func() {
align(16);
L(subroutine);
// Handle edge cases
// HandleType edge cases
ucomiss(src1_xmm, src1_xmm);
jp(retLabel);
@ -1277,4 +1273,4 @@ void ShaderEmitter::emitPrintLog(const PICAShader& shaderUnit) {
pop(rbp);
}
#endif
#endif

View file

@ -15,6 +15,9 @@
#ifdef PANDA3DS_ENABLE_VULKAN
#include "renderer_vk/renderer_vk.hpp"
#endif
#ifdef PANDA3DS_ENABLE_METAL
#include "renderer_mtl/renderer_mtl.hpp"
#endif
constexpr u32 topScreenWidth = 240;
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));
break;
}
#endif
#ifdef PANDA3DS_ENABLE_METAL
case RendererType::Metal: {
renderer.reset(new RendererMTL(*this, regs, externalRegs));
break;
}
#endif
default: {
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
shaderUnit.vs.run();
// Map shader outputs to fixed function properties
const u32 totalShaderOutputs = regs[PICA::InternalRegs::ShaderOutputCount] & 7;
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);
// 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) {
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);
}
// Handle control flow statements. The ordering is important as the priority goes: LOOP > IF > CALL
// Handle loop
// HandleType control flow statements. The ordering is important as the priority goes: LOOP > IF > CALL
// HandleType loop
if (loopIndex != 0) {
auto& loop = loopInfo[loopIndex - 1];
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) {
auto& info = conditionalInfo[ifIndex - 1];
if (pc == info.endingPC) { // Check if the IF block ended
@ -100,7 +100,7 @@ void PICAShader::run() {
}
}
// Handle calls
// HandleType calls
if (callIndex != 0) {
auto& info = callInfo[callIndex - 1];
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
pc = dest;
}
}

View file

@ -12,34 +12,36 @@ static const char* arbitrationTypeToString(u32 type) {
}
}
Handle Kernel::makeArbiter() {
HandleType Kernel::makeArbiter() {
if (arbiterCount >= appResourceLimits.maxAddressArbiters) {
Helpers::panic("Overflowed the number of address arbiters");
}
arbiterCount++;
Handle ret = makeObject(KernelObjectType::AddressArbiter);
HandleType ret = makeObject(KernelObjectType::AddressArbiter);
objects[ret].data = new AddressArbiter();
return ret;
}
// Result CreateAddressArbiter(Handle* arbiter)
// Result CreateAddressArbiter(HandleType* arbiter)
void Kernel::createAddressArbiter() {
logSVC("CreateAddressArbiter\n");
regs[0] = Result::Success;
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() {
const Handle handle = regs[0];
const HandleType handle = regs[0];
const u32 address = regs[1];
const u32 type = regs[2];
const s32 value = s32(regs[3]);
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,
arbitrationTypeToString(type), value, ns);
logSVC(
"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);
if (arbiter == nullptr) [[unlikely]] {
@ -61,7 +63,7 @@ void Kernel::arbitrateAddress() {
switch (static_cast<ArbitrationType>(type)) {
// Puts this thread to sleep if word < value until another thread arbitrates the address using SIGNAL
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) {
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
// If the thread is put to sleep, the arbiter address is decremented
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) {
mem.write32(address, word - 1);
sleepThreadOnArbiter(address);
@ -79,12 +81,9 @@ void Kernel::arbitrateAddress() {
break;
}
case ArbitrationType::Signal:
signalArbiter(address, value);
break;
case ArbitrationType::Signal: signalArbiter(address, value); break;
default:
Helpers::panic("ArbitrateAddress: Unimplemented type %s", arbitrationTypeToString(type));
default: Helpers::panic("ArbitrateAddress: Unimplemented type %s", arbitrationTypeToString(type));
}
requireReschedule();
@ -92,8 +91,9 @@ void Kernel::arbitrateAddress() {
// Signal up to "threadCount" threads waiting on the arbiter indicated by "waitingAddress"
void Kernel::signalArbiter(u32 waitingAddress, s32 threadCount) {
if (threadCount == 0) [[unlikely]] return;
s32 count = 0; // Number of threads we've woken up
if (threadCount == 0) [[unlikely]]
return;
s32 count = 0; // Number of threads we've woken up
// Wake threads with the highest priority threads being woken up first
for (auto index : threadIndices) {
@ -106,4 +106,4 @@ void Kernel::signalArbiter(u32 waitingAddress, s32 threadCount) {
if (count == threadCount && threadCount > 0) break;
}
}
}
}

View file

@ -8,10 +8,7 @@
#include "kernel.hpp"
namespace DirectoryOps {
enum : u32 {
Read = 0x08010042,
Close = 0x08020000
};
enum : u32 { Read = 0x08010042, Close = 0x08020000 };
}
// 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
// "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
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
// TODO: Use constexpr when C++20 support is solid
@ -66,7 +63,7 @@ Filename83 convertTo83(const std::string& path) {
filenameTooBig = true;
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
@ -87,7 +84,7 @@ Filename83 convertTo83(const std::string& path) {
return {filename, extension};
}
void Kernel::handleDirectoryOperation(u32 messagePointer, Handle directory) {
void Kernel::handleDirectoryOperation(u32 messagePointer, HandleType directory) {
const u32 cmd = mem.read32(messagePointer);
switch (cmd) {
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);
const auto p = getObject(directory, KernelObjectType::Directory);
@ -109,11 +106,11 @@ void Kernel::closeDirectory(u32 messagePointer, Handle directory) {
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 outPointer = mem.read32(messagePointer + 12);
logFileIO("Directory::Read (handle = %X, entry count = %d, out pointer = %08X)\n", directory, entryCount, outPointer);
const auto p = getObject(directory, KernelObjectType::Directory);
if (p == nullptr) [[unlikely]] {
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);
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 namePointer = entryPointer + 0x20C;
u32 extensionPointer = entryPointer + 0x216;
@ -152,7 +149,7 @@ void Kernel::readDirectory(u32 messagePointer, Handle directory) {
mem.write16(utfPointer, u16(c));
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
for (auto c : shortFilename) {

View file

@ -1,38 +1,25 @@
#include "kernel.hpp"
namespace Commands {
enum : u32 {
Throw = 0x00010800
};
enum : u32 { Throw = 0x00010800 };
}
namespace FatalErrorType {
enum : u32 {
Generic = 0,
Corrupted = 1,
CardRemoved = 2,
Exception = 3,
ResultFailure = 4,
Logged = 5
};
enum : u32 { 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) {
u32 cmd = mem.read32(messagePointer);
switch (cmd) {
case Commands::Throw:
throwError(messagePointer);
break;
case Commands::Throw: throwError(messagePointer); break;
default:
Helpers::panic("Unimplemented err:f command %08X\n", cmd);
break;
default: Helpers::panic("Unimplemented err:f command %08X\n", cmd); break;
}
}
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 pid = mem.read32(messagePointer + 16);
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");
}
}

View file

@ -1,8 +1,9 @@
#include "kernel.hpp"
#include "cpu.hpp"
#include <bit>
#include <utility>
#include "cpu.hpp"
#include "kernel.hpp"
const char* Kernel::resetTypeToString(u32 type) {
switch (type) {
case 0: return "One shot";
@ -12,13 +13,13 @@ const char* Kernel::resetTypeToString(u32 type) {
}
}
Handle Kernel::makeEvent(ResetType resetType, Event::CallbackType callback) {
Handle ret = makeObject(KernelObjectType::Event);
HandleType Kernel::makeEvent(ResetType resetType, Event::CallbackType callback) {
HandleType ret = makeObject(KernelObjectType::Event);
objects[ret].data = new Event(resetType, callback);
return ret;
}
bool Kernel::signalEvent(Handle handle) {
bool Kernel::signalEvent(HandleType handle) {
KernelObject* object = getObject(handle, KernelObjectType::Event);
if (object == nullptr) [[unlikely]] {
Helpers::panic("Tried to signal non-existent event");
@ -52,13 +53,12 @@ bool Kernel::signalEvent(Handle handle) {
return true;
}
// Result CreateEvent(Handle* event, ResetType resetType)
// Result CreateEvent(HandleType* event, ResetType resetType)
void Kernel::svcCreateEvent() {
const u32 outPointer = regs[0];
const u32 resetType = regs[1];
if (resetType > 2)
Helpers::panic("Invalid reset type for event %d", resetType);
if (resetType > 2) Helpers::panic("Invalid reset type for event %d", 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));
}
// Result ClearEvent(Handle event)
// Result ClearEvent(HandleType event)
void Kernel::svcClearEvent() {
const Handle handle = regs[0];
const HandleType handle = regs[0];
const auto event = getObject(handle, KernelObjectType::Event);
logSVC("ClearEvent(event handle = %X)\n", handle);
@ -82,9 +82,9 @@ void Kernel::svcClearEvent() {
regs[0] = Result::Success;
}
// Result SignalEvent(Handle event)
// Result SignalEvent(HandleType event)
void Kernel::svcSignalEvent() {
const Handle handle = regs[0];
const HandleType handle = regs[0];
logSVC("SignalEvent(event handle = %X)\n", handle);
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() {
const Handle handle = regs[0];
const HandleType handle = regs[0];
const s64 ns = s64(u64(regs[2]) | (u64(regs[3]) << 32));
logSVC("WaitSynchronization1(handle = %X, ns = %lld)\n", handle, ns);
@ -117,7 +117,7 @@ void Kernel::waitSynchronization1() {
}
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;
} else {
// Timeout is 0, don't bother waiting, instantly timeout
@ -126,7 +126,7 @@ void Kernel::waitSynchronization1() {
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];
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() {
// TODO: Are these arguments even correct?
s32 ns1 = regs[0];
@ -149,13 +149,12 @@ void Kernel::waitSynchronizationN() {
s32 handleCount = regs[2];
bool waitAll = regs[3] != 0;
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);
logSVC("WaitSynchronizationN (handle pointer: %08X, count: %d, timeout = %lld)\n", handles, handleCount, ns);
if (handleCount <= 0)
Helpers::panic("WaitSyncN: Invalid handle count");
if (handleCount <= 0) Helpers::panic("WaitSyncN: Invalid handle count");
// 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
@ -165,11 +164,11 @@ void Kernel::waitSynchronizationN() {
return;
}
using WaitObject = std::pair<Handle, KernelObject*>;
using WaitObject = std::pair<HandleType, KernelObject*>;
std::vector<WaitObject> waitObjects(handleCount);
// 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
// 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;
for (s32 i = 0; i < handleCount; i++) {
Handle handle = mem.read32(handles);
handles += sizeof(Handle);
HandleType handle = mem.read32(handles);
handles += sizeof(HandleType);
auto object = getObject(handle);
// 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
if (!isWaitable(object)) [[unlikely]] {
Helpers::panic("Tried to wait on a non waitable object in WaitSyncN. Type: %s, handle: %X\n",
object->getTypeName(), handle);
Helpers::panic("Tried to wait on a non waitable object in WaitSyncN. Type: %s, handle: %X\n", object->getTypeName(), handle);
}
if (shouldWaitOnObject(object)) {
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
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
if (!oneObjectReady) {
oneObjectReady = true;
firstReadyObjectIndex = i;
@ -213,12 +211,12 @@ void Kernel::waitSynchronizationN() {
// If there's ready objects, acquire the first one and return
if (oneObjectReady) {
regs[0] = Result::Success;
regs[1] = firstReadyObjectIndex; // Return index of the acquired object
acquireSyncObject(waitObjects[firstReadyObjectIndex].second, t); // Acquire object
regs[1] = firstReadyObjectIndex; // Return index of the acquired object
acquireSyncObject(waitObjects[firstReadyObjectIndex].second, t); // Acquire object
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
regs[1] = 0xFFFFFFFF;
t.waitList.resize(handleCount);
@ -227,8 +225,8 @@ void Kernel::waitSynchronizationN() {
t.wakeupTick = getWakeupTick(ns);
for (s32 i = 0; i < handleCount; i++) {
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
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
}
requireReschedule();
@ -243,4 +241,4 @@ void Kernel::runEventCallback(Event::CallbackType callback) {
case Event::CallbackType::DSPSemaphore: serviceManager.getDSP().onSemaphoreEventSignal(); break;
default: Helpers::panic("Unimplemented special callback for kernel event!"); break;
}
}
}

View file

@ -14,8 +14,7 @@ namespace FileOps {
};
}
void Kernel::handleFileOperation(u32 messagePointer, Handle file) {
void Kernel::handleFileOperation(u32 messagePointer, HandleType file) {
const u32 cmd = mem.read32(messagePointer);
switch (cmd) {
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);
const auto p = getObject(fileHandle, KernelObjectType::File);
@ -48,7 +47,7 @@ void Kernel::closeFile(u32 messagePointer, Handle fileHandle) {
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);
const auto p = getObject(fileHandle, KernelObjectType::File);
@ -65,13 +64,12 @@ void Kernel::flushFile(u32 messagePointer, Handle fileHandle) {
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);
u32 size = mem.read32(messagePointer + 12);
u32 dataPointer = mem.read32(messagePointer + 20);
logFileIO("Trying to read %X bytes from file %X, starting from offset %llX into memory address %08X\n",
size, fileHandle, offset, dataPointer);
logFileIO("Trying to read %X bytes from file %X, starting from offset %llX into memory address %08X\n", size, fileHandle, offset, dataPointer);
const auto p = getObject(fileHandle, KernelObjectType::File);
if (p == nullptr) [[unlikely]] {
@ -85,7 +83,7 @@ void Kernel::readFile(u32 messagePointer, Handle fileHandle) {
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) {
std::unique_ptr<u8[]> data(new u8[size]);
IOFile f(file->fd);
@ -94,8 +92,7 @@ void Kernel::readFile(u32 messagePointer, Handle fileHandle) {
if (!success) {
Helpers::panic("Kernel::ReadFile with file descriptor failed");
}
else {
} else {
for (size_t i = 0; i < bytesRead; i++) {
mem.write8(u32(dataPointer + i), data[i]);
}
@ -107,7 +104,7 @@ void Kernel::readFile(u32 messagePointer, Handle fileHandle) {
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;
std::optional<u32> bytesRead = archive->readFile(file, offset, size, dataPointer);
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);
u32 size = mem.read32(messagePointer + 12);
u32 writeOption = mem.read32(messagePointer + 16);
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",
size, fileHandle, offset, dataPointer);
logFileIO("Trying to write %X bytes to file %X, starting from file offset %llX and memory address %08X\n", size, fileHandle, offset, dataPointer);
const auto p = getObject(fileHandle, KernelObjectType::File);
if (p == nullptr) [[unlikely]] {
@ -137,8 +133,7 @@ void Kernel::writeFile(u32 messagePointer, Handle fileHandle) {
Helpers::panic("Tried to write closed file");
}
if (!file->fd)
Helpers::panic("[Kernel::File::WriteFile] Tried to write to file without a valid file descriptor");
if (!file->fd) Helpers::panic("[Kernel::File::WriteFile] Tried to write to file without a valid file descriptor");
std::unique_ptr<u8[]> data(new u8[size]);
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);
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);
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);
const auto p = getObject(fileHandle, KernelObjectType::File);
@ -247,7 +242,7 @@ void Kernel::openLinkFile(u32 messagePointer, Handle fileHandle) {
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);
logFileIO("Setting priority of file %X to %d\n", fileHandle, priority);

View file

@ -1,11 +1,13 @@
#include <cassert>
#include "kernel.hpp"
#include "kernel_types.hpp"
#include <cassert>
#include "cpu.hpp"
#include "kernel_types.hpp"
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) {
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);
portHandles.reserve(32);
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.status = ThreadStatus::Dead;
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
t.outPointer = 0;
t.waitAll = false;
@ -79,12 +81,12 @@ void Kernel::setVersion(u8 major, u8 minor) {
u16 descriptor = (u16(major) << 8) | u16(minor);
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) {
const Handle processHandle = makeObject(KernelObjectType::Process);
const Handle resourceLimitHandle = makeObject(KernelObjectType::ResourceLimit);
HandleType Kernel::makeProcess(u32 id) {
const HandleType processHandle = makeObject(KernelObjectType::Process);
const HandleType resourceLimitHandle = makeObject(KernelObjectType::ResourceLimit);
// Allocate data
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
// 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]] {
return getObject(currentProcess, KernelObjectType::Process);
} else {
@ -142,7 +144,7 @@ void Kernel::reset() {
for (auto& t : threads) {
t.status = ThreadStatus::Dead;
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) {
@ -159,7 +161,7 @@ void Kernel::reset() {
// Allocate handle #0 to a dummy object and make a main process object
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.
// 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();
// Create some of the OS ports
srvHandle = makePort("srv:"); // Service manager port
errorPortHandle = makePort("err:f"); // Error display port
srvHandle = makePort("srv:"); // Service manager port
errorPortHandle = makePort("err:f"); // Error display port
}
// Get pointer to thread-local storage
u32 Kernel::getTLSPointer() {
return VirtualAddrs::TLSBase + currentThreadIndex * VirtualAddrs::TLSSize;
}
u32 Kernel::getTLSPointer() { return VirtualAddrs::TLSBase + currentThreadIndex * VirtualAddrs::TLSSize; }
// Result CloseHandle(Handle handle)
// Result CloseHandle(HandleType handle)
void Kernel::svcCloseHandle() {
logSVC("CloseHandle(handle = %d) (Unimplemented)\n", regs[0]);
const Handle handle = regs[0];
const HandleType handle = regs[0];
KernelObject* object = getObject(handle);
if (object != nullptr) {
@ -242,7 +242,7 @@ void Kernel::getProcessID() {
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() {
const auto pid = regs[1];
const auto type = regs[2];
@ -269,26 +269,25 @@ void Kernel::getProcessInfo() {
regs[2] = 0;
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[2] = 0;
break;
default:
Helpers::panic("GetProcessInfo: unimplemented type %d", type);
default: Helpers::panic("GetProcessInfo: unimplemented type %d", type);
}
regs[0] = Result::Success;
}
// Result DuplicateHandle(Handle* out, Handle original)
// Result DuplicateHandle(HandleType* out, HandleType original)
void Kernel::duplicateHandle() {
Handle original = regs[1];
HandleType original = regs[1];
logSVC("DuplicateHandle(handle = %X)\n", original);
if (original == KernelHandles::CurrentThread) {
regs[0] = Result::Success;
Handle ret = makeObject(KernelObjectType::Thread);
HandleType ret = makeObject(KernelObjectType::Thread);
objects[ret].data = &threads[currentThreadIndex];
regs[1] = ret;
@ -379,7 +378,7 @@ void Kernel::getSystemInfo() {
regs[2] = 0;
break;
default:
default:
Helpers::warn("GetSystemInfo: Unknown PandaInformation subtype %x\n", subtype);
regs[0] = Result::FailurePlaceholder;
break;

View file

@ -17,37 +17,35 @@ namespace Operation {
namespace MemoryPermissions {
enum : u32 {
None = 0, // ---
Read = 1, // R--
Write = 2, // -W-
ReadWrite = 3, // RW-
Execute = 4, // --X
ReadExecute = 5, // R-X
WriteExecute = 6, // -WX
ReadWriteExecute = 7, // RWX
None = 0, // ---
Read = 1, // R--
Write = 2, // -W-
ReadWrite = 3, // RW-
Execute = 4, // --X
ReadExecute = 5, // R-X
WriteExecute = 6, // -WX
ReadWriteExecute = 7, // RWX
DontCare = 0x10000000
};
}
// Returns whether "value" is aligned to a page boundary (Ie a boundary of 4096 bytes)
static constexpr bool isAligned(u32 value) {
return (value & 0xFFF) == 0;
}
static constexpr bool isAligned(u32 value) { return (value & 0xFFF) == 0; }
// Result ControlMemory(u32* outaddr, u32 addr0, u32 addr1, u32 size,
// MemoryOperation operation, MemoryPermission permissions)
// This has a weird ABI documented here https://www.3dbrew.org/wiki/Kernel_ABI
// TODO: Does this need to write to outaddr?
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 addr1 = regs[2];
u32 size = regs[3];
u32 perms = regs[4];
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");
}
@ -57,33 +55,33 @@ void Kernel::controlMemory() {
bool x = perms & 0b100;
bool linear = operation & Operation::Linear;
if (x)
Helpers::panic("ControlMemory: attempted to allocate executable memory");
if (x) Helpers::panic("ControlMemory: attempted to allocate executable memory");
if (!isAligned(addr0) || !isAligned(addr1) || !isAligned(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",
addr0, addr1, size, operation, r ? 'r' : '-', w ? 'w' : '-', x ? 'x' : '-', linear ? ", linear" : ""
logSVC(
"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) {
case Operation::Commit: {
std::optional<u32> address = mem.allocateMemory(addr0, 0, size, linear, r, w, x, true);
if (!address.has_value())
Helpers::panic("ControlMemory: Failed to allocate memory");
if (!address.has_value()) Helpers::panic("ControlMemory: Failed to allocate memory");
regs[1] = address.value();
break;
}
case Operation::Map:
mem.mirrorMapping(addr0, addr1, size);
break;
case Operation::Map: mem.mirrorMapping(addr0, addr1, size); break;
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;
default: Helpers::warn("ControlMemory: unknown operation %X\n", operation); break;
@ -106,12 +104,12 @@ void Kernel::queryMemory() {
regs[2] = info.size;
regs[3] = info.perms;
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() {
const Handle block = regs[0];
const HandleType block = regs[0];
u32 addr = regs[1];
const u32 myPerms = regs[2];
const u32 otherPerms = regs[3];
@ -123,21 +121,15 @@ void Kernel::mapMemoryBlock() {
if (KernelHandles::isSharedMemHandle(block)) {
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
switch (block) {
case KernelHandles::HIDSharedMemHandle:
serviceManager.setHIDSharedMem(ptr);
break;
case KernelHandles::HIDSharedMemHandle: serviceManager.setHIDSharedMem(ptr); break;
case KernelHandles::GSPSharedMemHandle:
serviceManager.setGSPSharedMem(ptr);
break;
case KernelHandles::GSPSharedMemHandle: serviceManager.setGSPSharedMem(ptr); break;
case KernelHandles::FontSharedMemHandle:
mem.copySharedFont(ptr);
break;
case KernelHandles::FontSharedMemHandle: mem.copySharedFont(ptr); break;
case KernelHandles::CSNDSharedMemHandle:
serviceManager.setCSNDSharedMem(ptr);
@ -154,8 +146,8 @@ void Kernel::mapMemoryBlock() {
regs[0] = Result::Success;
}
Handle Kernel::makeMemoryBlock(u32 addr, u32 size, u32 myPermission, u32 otherPermission) {
Handle ret = makeObject(KernelObjectType::MemoryBlock);
HandleType Kernel::makeMemoryBlock(u32 addr, u32 size, u32 myPermission, u32 otherPermission) {
HandleType ret = makeObject(KernelObjectType::MemoryBlock);
objects[ret].data = new MemoryBlock(addr, size, myPermission, otherPermission);
return ret;
@ -165,7 +157,7 @@ void Kernel::createMemoryBlock() {
const u32 addr = regs[1];
const u32 size = regs[2];
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);
// Returns whether a permission is valid
@ -175,10 +167,9 @@ void Kernel::createMemoryBlock() {
case MemoryPermissions::Read:
case MemoryPermissions::Write:
case MemoryPermissions::ReadWrite:
case MemoryPermissions::DontCare:
return true;
case MemoryPermissions::DontCare: 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;
}
};
@ -197,8 +188,7 @@ void Kernel::createMemoryBlock() {
// TODO: The address needs to be in a specific range otherwise it throws an invalid address error
if (addr == 0)
Helpers::panic("CreateMemoryBlock: Tried to use addr = 0");
if (addr == 0) Helpers::panic("CreateMemoryBlock: Tried to use addr = 0");
// Implement "Don't care" permission as RW
if (myPermission == MemoryPermissions::DontCare) myPermission = MemoryPermissions::ReadWrite;
@ -209,7 +199,7 @@ void Kernel::createMemoryBlock() {
}
void Kernel::unmapMemoryBlock() {
Handle block = regs[0];
HandleType block = regs[0];
u32 addr = regs[1];
logSVC("Unmap memory block (block handle = %X, addr = %08X)\n", block, addr);

View file

@ -1,29 +1,30 @@
#include "kernel.hpp"
#include <cstring>
Handle Kernel::makePort(const char* name) {
Handle ret = makeObject(KernelObjectType::Port);
portHandles.push_back(ret); // Push the port handle to our cache of port handles
#include "kernel.hpp"
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);
return ret;
}
Handle Kernel::makeSession(Handle portHandle) {
HandleType Kernel::makeSession(HandleType portHandle) {
const auto port = getObject(portHandle, KernelObjectType::Port);
if (port == nullptr) [[unlikely]] {
Helpers::panic("Trying to make session for non-existent port");
}
// Allocate data for session
const Handle ret = makeObject(KernelObjectType::Session);
const HandleType ret = makeObject(KernelObjectType::Session);
objects[ret].data = new Session(portHandle);
return ret;
}
// Get the handle of a port based on its name
// 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) {
const auto data = objects[handle].getData<Port>();
if (std::strncmp(name, data->name, Port::maxNameLen) == 0) {
@ -34,7 +35,7 @@ std::optional<Handle> Kernel::getPortHandle(const char* name) {
return std::nullopt;
}
// Result ConnectToPort(Handle* out, const char* portName)
// Result ConnectToPort(HandleType* out, const char* portName)
void Kernel::connectToPort() {
const u32 handlePointer = regs[0];
// 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
std::optional<Handle> optionalHandle = getPortHandle(port.c_str());
std::optional<HandleType> optionalHandle = getPortHandle(port.c_str());
if (!optionalHandle.has_value()) [[unlikely]] {
Helpers::panic("ConnectToPort: Port doesn't exist\n");
regs[0] = Result::Kernel::NotFound;
return;
}
Handle portHandle = optionalHandle.value();
HandleType portHandle = optionalHandle.value();
const auto portData = objects[portHandle].getData<Port>();
if (!portData->isPublic) {
@ -63,17 +64,17 @@ void Kernel::connectToPort() {
}
// TODO: Actually create session
Handle sessionHandle = makeSession(portHandle);
HandleType sessionHandle = makeSession(portHandle);
regs[0] = Result::Success;
regs[1] = sessionHandle;
}
// Result SendSyncRequest(Handle session)
// Result SendSyncRequest(HandleType session)
// Send an IPC message to a port (typically "srv:") or a service
void Kernel::sendSyncRequest() {
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);
// 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
bool isFileOperation = getObject(handle, KernelObjectType::File) != nullptr;
if (isFileOperation) {
regs[0] = Result::Success; // r0 goes first here too
regs[0] = Result::Success; // r0 goes first here too
handleFileOperation(messagePointer, handle);
return;
}
@ -101,7 +102,7 @@ void Kernel::sendSyncRequest() {
// Check if our sync request is targetting a directory instead of a service
bool isDirectoryOperation = getObject(handle, KernelObjectType::Directory) != nullptr;
if (isDirectoryOperation) {
regs[0] = Result::Success; // r0 goes first here too
regs[0] = Result::Success; // r0 goes first here too
handleDirectoryOperation(messagePointer, handle);
return;
}
@ -115,12 +116,12 @@ void Kernel::sendSyncRequest() {
}
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;
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;
handleErrorSyncRequest(messagePointer);
} else {

View file

@ -1,7 +1,8 @@
#include "resource_limits.hpp"
#include "kernel.hpp"
// Result GetResourceLimit(Handle* resourceLimit, Handle process)
// Result GetResourceLimit(HandleType* resourceLimit, HandleType process)
// out: r0 -> result, r1 -> handle
void Kernel::getResourceLimit() {
const auto handlePointer = regs[0];
@ -20,10 +21,10 @@ void Kernel::getResourceLimit() {
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() {
u32 values = regs[0]; // Pointer to values (The resource limits get output here)
const Handle resourceLimit = regs[1];
u32 values = regs[0]; // Pointer to values (The resource limits get output here)
const HandleType resourceLimit = regs[1];
u32 names = regs[2]; // Pointer to resources that we should return
u32 count = regs[3]; // Number of resources
@ -49,10 +50,10 @@ void Kernel::getResourceLimitLimitValues() {
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() {
u32 values = regs[0]; // Pointer to values (The resource limits get output here)
const Handle resourceLimit = regs[1];
u32 values = regs[0]; // Pointer to values (The resource limits get output here)
const HandleType resourceLimit = regs[1];
u32 names = regs[2]; // Pointer to resources that we should return
u32 count = regs[3]; // Number of resources
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
cpu.setCPSR(newThread.cpsr); // Load CPSR
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;
}
@ -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
void Kernel::sortThreads() {
std::vector<int>& v = threadIndices;
std::sort(v.begin(), v.end(), [&](int a, int b) {
return threads[a].priority < threads[b].priority;
});
std::sort(v.begin(), v.end(), [&](int a, int b) { return threads[a].priority < threads[b].priority; });
}
bool Kernel::canThreadRun(const Thread& t) {
if (t.status == ThreadStatus::Ready) {
return true;
} else if (t.status == ThreadStatus::WaitSleep || t.status == ThreadStatus::WaitSync1
|| t.status == ThreadStatus::WaitSyncAny || t.status == ThreadStatus::WaitSyncAll) {
} else if (t.status == ThreadStatus::WaitSleep || t.status == ThreadStatus::WaitSync1 || t.status == ThreadStatus::WaitSyncAny ||
t.status == ThreadStatus::WaitSyncAll) {
// TODO: Set r0 to the correct error code on timeout for WaitSync{1/Any/All}
return cpu.getTicks() >= t.wakeupTick;
}
// Handle timeouts and stuff here
// HandleType timeouts and stuff here
return false;
}
@ -100,8 +98,8 @@ void Kernel::rescheduleThreads() {
// Case 1: A thread can run
if (newThreadIndex.has_value()) {
switchThread(newThreadIndex.value());
}
}
// Case 2: No other thread can run, straight to the idle thread
else {
switchThread(idleThreadIndex);
@ -109,30 +107,30 @@ void Kernel::rescheduleThreads() {
}
// Internal OS function to spawn a thread
Handle 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
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
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++;
} 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++) {
if (threads[i].status == ThreadStatus::Dead) {
index = i;
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!!");
}
aliveThreadCount++;
threadIndices.push_back(index);
Thread& t = threads[index]; // Reference to thread data
Handle ret = makeObject(KernelObjectType::Thread);
Thread& t = threads[index]; // Reference to thread data
HandleType ret = makeObject(KernelObjectType::Thread);
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
t.gprs.fill(0);
@ -150,7 +148,7 @@ Handle Kernel::makeThread(u32 entrypoint, u32 initialSP, u32 priority, Processor
t.status = status;
t.handle = ret;
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.fpscr = FPSCR::ThreadDefault;
@ -161,8 +159,8 @@ Handle Kernel::makeThread(u32 entrypoint, u32 initialSP, u32 priority, Processor
return ret;
}
Handle Kernel::makeMutex(bool locked) {
Handle ret = makeObject(KernelObjectType::Mutex);
HandleType Kernel::makeMutex(bool locked) {
HandleType ret = makeObject(KernelObjectType::Mutex);
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
@ -181,15 +179,15 @@ Handle Kernel::makeMutex(bool locked) {
void Kernel::releaseMutex(Mutex* moo) {
// 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 (moo->lockCount == 0) {
moo->locked = false;
if (moo->waitlist != 0) {
int index = wakeupOneThread(moo->waitlist, moo->handle); // Wake up one thread and get its index
moo->waitlist ^= (1ull << index); // Remove thread from waitlist
int index = wakeupOneThread(moo->waitlist, moo->handle); // Wake up one thread and get its index
moo->waitlist ^= (1ull << index); // Remove thread from waitlist
// Have new thread acquire mutex
moo->locked = true;
@ -201,8 +199,8 @@ void Kernel::releaseMutex(Mutex* moo) {
}
}
Handle Kernel::makeSemaphore(u32 initialCount, u32 maximumCount) {
Handle ret = makeObject(KernelObjectType::Semaphore);
HandleType Kernel::makeSemaphore(u32 initialCount, u32 maximumCount) {
HandleType ret = makeObject(KernelObjectType::Semaphore);
objects[ret].data = new Semaphore(initialCount, maximumCount);
return ret;
@ -221,7 +219,7 @@ void Kernel::acquireSyncObject(KernelObject* object, const Thread& thread) {
switch (object->type) {
case KernelObjectType::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;
}
break;
@ -245,15 +243,14 @@ void Kernel::acquireSyncObject(KernelObject* object, const Thread& thread) {
case KernelObjectType::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");
s->availableCount -= 1;
break;
}
case KernelObjectType::Thread:
break;
case KernelObjectType::Thread: break;
case KernelObjectType::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
// 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]]
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.
// 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 maxPriority = threads[threadIndex].priority; // Set initial max prio to the prio of the first thread
waitlist ^= (1ull << threadIndex); // Remove thread from the waitlist
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
waitlist ^= (1ull << threadIndex); // Remove thread from the waitlist
while (waitlist != 0) {
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
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
threadIndex = newThread;
maxPriority = threads[newThread].priority;
}
waitlist ^= (1ull << threadIndex); // Remove thread from waitlist
waitlist ^= (1ull << threadIndex); // Remove thread from waitlist
}
Thread& t = threads[threadIndex];
switch (t.status) {
case ThreadStatus::WaitSync1:
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;
case ThreadStatus::WaitSyncAny:
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
for (size_t i = 0; i < t.waitList.size(); i++) {
@ -309,44 +306,40 @@ int Kernel::wakeupOneThread(u64 waitlist, Handle handle) {
}
break;
case ThreadStatus::WaitSyncAll:
Helpers::panic("WakeupOneThread: Thread on WaitSyncAll");
break;
case ThreadStatus::WaitSyncAll: Helpers::panic("WakeupOneThread: Thread on WaitSyncAll"); break;
}
return threadIndex;
}
// 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) {
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
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
// Get the thread we'll be signalling
Thread& t = threads[index];
switch (t.status) {
case ThreadStatus::WaitSync1:
t.status = ThreadStatus::Ready;
t.gprs[0] = Result::Success; // The thread did not timeout, so write success to r0
break;
case ThreadStatus::WaitSync1:
t.status = ThreadStatus::Ready;
t.gprs[0] = Result::Success; // The thread did not timeout, so write success to r0
break;
case ThreadStatus::WaitSyncAny:
t.status = ThreadStatus::Ready;
t.gprs[0] = Result::Success; // The thread did not timeout, so write success to r0
case ThreadStatus::WaitSyncAny:
t.status = ThreadStatus::Ready;
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
for (size_t i = 0; i < t.waitList.size(); i++) {
if (t.waitList[i] == handle) {
t.gprs[1] = u32(i);
break;
// 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++) {
if (t.waitList[i] == handle) {
t.gprs[1] = u32(i);
break;
}
}
}
break;
break;
case ThreadStatus::WaitSyncAll:
Helpers::panic("WakeupAllThreads: Thread on WaitSyncAll");
break;
case ThreadStatus::WaitSyncAll: Helpers::panic("WakeupAllThreads: Thread on WaitSyncAll"); break;
}
}
}
@ -404,12 +397,11 @@ void Kernel::sleepThread(s64 ns) {
void Kernel::createThread() {
u32 priority = regs[0];
u32 entrypoint = regs[1];
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 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
s32 id = static_cast<s32>(regs[4]);
logSVC("CreateThread(entry = %08X, stacktop = %08X, arg = %X, priority = %X, processor ID = %d)\n", entrypoint,
initialSP, arg, priority, id);
logSVC("CreateThread(entry = %08X, stacktop = %08X, arg = %X, priority = %X, processor ID = %d)\n", entrypoint, initialSP, arg, priority, id);
if (priority > 0x3F) [[unlikely]] {
Helpers::panic("Created thread with bad priority value %X", priority);
@ -429,14 +421,14 @@ void Kernel::createThread() {
// void SleepThread(s64 nanoseconds)
void Kernel::svcSleepThread() {
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;
sleepThread(ns);
}
void Kernel::getThreadID() {
Handle handle = regs[1];
HandleType handle = regs[1];
logSVC("GetThreadID(handle = %X)\n", handle);
if (handle == KernelHandles::CurrentThread) {
@ -456,7 +448,7 @@ void Kernel::getThreadID() {
}
void Kernel::getThreadPriority() {
const Handle handle = regs[1];
const HandleType handle = regs[1];
logSVC("GetThreadPriority (handle = %X)\n", handle);
if (handle == KernelHandles::CurrentThread) {
@ -474,7 +466,7 @@ void Kernel::getThreadPriority() {
}
void Kernel::getThreadIdealProcessor() {
const Handle handle = regs[1]; // Thread handle
const HandleType handle = regs[1]; // Thread 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
@ -490,7 +482,7 @@ void Kernel::getThreadContext() {
}
void Kernel::setThreadPriority() {
const Handle handle = regs[0];
const HandleType handle = regs[0];
const u32 priority = regs[1];
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
switch (id) {
// TODO: This is picked from exheader
case ProcessorID::Default:
ret = static_cast<s32>(ProcessorID::AppCore);
break;
case ProcessorID::Default: ret = static_cast<s32>(ProcessorID::AppCore); break;
case ProcessorID::AllCPUs:
ret = static_cast<s32>(ProcessorID::AppCore);
@ -565,8 +555,7 @@ void Kernel::exitThread() {
// Remove the index of this thread from the thread indices vector
for (int i = 0; i < threadIndices.size(); i++) {
if (threadIndices[i] == currentThreadIndex)
threadIndices.erase(threadIndices.begin() + i);
if (threadIndices[i] == currentThreadIndex) threadIndices.erase(threadIndices.begin() + i);
}
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
// This is how thread joining is implemented in the kernel - you wait on a thread, like any other wait object.
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);
t.threadsWaitingForTermination = 0; // No other threads waiting
t.threadsWaitingForTermination = 0; // No other threads waiting
}
requireReschedule();
@ -593,7 +582,7 @@ void Kernel::svcCreateMutex() {
}
void Kernel::svcReleaseMutex() {
const Handle handle = regs[0];
const HandleType handle = regs[0];
logSVC("ReleaseMutex (handle = %x)\n", handle);
const auto object = getObject(handle, KernelObjectType::Mutex);
@ -619,18 +608,16 @@ void Kernel::svcCreateSemaphore() {
s32 maxCount = static_cast<s32>(regs[2]);
logSVC("CreateSemaphore (initial count = %d, max count = %d)\n", initialCount, maxCount);
if (initialCount > maxCount)
Helpers::panic("CreateSemaphore: Initial count higher than max count");
if (initialCount > maxCount) Helpers::panic("CreateSemaphore: Initial count higher than max count");
if (initialCount < 0 || maxCount < 0)
Helpers::panic("CreateSemaphore: Negative count value");
if (initialCount < 0 || maxCount < 0) Helpers::panic("CreateSemaphore: Negative count value");
regs[0] = Result::Success;
regs[1] = makeSemaphore(initialCount, maxCount);
}
void Kernel::svcReleaseSemaphore() {
const Handle handle = regs[1];
const HandleType handle = regs[1];
const s32 releaseCount = static_cast<s32>(regs[2]);
logSVC("ReleaseSemaphore (handle = %X, release count = %d)\n", handle, releaseCount);
@ -641,12 +628,10 @@ void Kernel::svcReleaseSemaphore() {
return;
}
if (releaseCount < 0)
Helpers::panic("ReleaseSemaphore: Negative count");
if (releaseCount < 0) Helpers::panic("ReleaseSemaphore: Negative count");
Semaphore* s = object->getData<Semaphore>();
if (s->maximumCount - s->availableCount < releaseCount)
Helpers::panic("ReleaseSemaphore: Release count too high");
if (s->maximumCount - s->availableCount < releaseCount) Helpers::panic("ReleaseSemaphore: Release count too high");
// Write success and old available count to r0 and r1 respectively
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
while (s->availableCount > 0 && s->waitlist != 0) {
int index = wakeupOneThread(s->waitlist, handle); // Wake up highest priority thread
s->waitlist ^= (1ull << index); // Remove thread from waitlist
int index = wakeupOneThread(s->waitlist, handle); // Wake up highest priority thread
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
bool Kernel::shouldWaitOnObject(KernelObject* object) {
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;
case KernelObjectType::Mutex: {
Mutex* moo = object->getData<Mutex>(); // mooooooooooo
return moo->locked && moo->ownerThread != currentThreadIndex; // If the current thread owns the moo then no reason to wait
Mutex* moo = object->getData<Mutex>(); // mooooooooooo
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;
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;
case KernelObjectType::Semaphore: // Wait if the semaphore count <= 0
case KernelObjectType::Semaphore: // Wait if the semaphore count <= 0
return object->getData<Semaphore>()->availableCount <= 0;
default:
Helpers::panic("Not sure whether to wait on object (type: %s)", object->getTypeName());
return true;
default: 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 "scheduler.hpp"
Handle Kernel::makeTimer(ResetType type) {
Handle ret = makeObject(KernelObjectType::Timer);
HandleType Kernel::makeTimer(ResetType type) {
HandleType ret = makeObject(KernelObjectType::Timer);
objects[ret].data = new Timer(type);
if (type == ResetType::Pulse) {
@ -52,11 +52,9 @@ void Kernel::pollTimers() {
}
}
void Kernel::cancelTimer(Timer* timer) {
timer->running = false;
}
void Kernel::cancelTimer(Timer* timer) { timer->running = false; }
void Kernel::signalTimer(Handle timerHandle, Timer* timer) {
void Kernel::signalTimer(HandleType timerHandle, Timer* timer) {
timer->fired = true;
requireReschedule();
@ -94,7 +92,7 @@ void Kernel::svcCreateTimer() {
}
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
const s64 initial = s64(u64(regs[2]) | (u64(regs[3]) << 32));
const s64 interval = s64(u64(regs[1]) | (u64(regs[4]) << 32));
@ -112,7 +110,7 @@ void Kernel::svcSetTimer() {
timer->interval = interval;
timer->running = true;
timer->fireTick = cpu.getTicks() + Scheduler::nsToCycles(initial);
Scheduler& scheduler = cpu.getScheduler();
// Signal an event to poll timers as soon as possible
scheduler.removeEvent(Scheduler::EventType::UpdateTimers);
@ -127,7 +125,7 @@ void Kernel::svcSetTimer() {
}
void Kernel::svcClearTimer() {
Handle handle = regs[0];
HandleType handle = regs[0];
logSVC("ClearTimer (handle = %X)\n", handle);
KernelObject* object = getObject(handle, KernelObjectType::Timer);
@ -141,7 +139,7 @@ void Kernel::svcClearTimer() {
}
void Kernel::svcCancelTimer() {
Handle handle = regs[0];
HandleType handle = regs[0];
logSVC("CancelTimer (handle = %X)\n", handle);
KernelObject* object = getObject(handle, KernelObjectType::Timer);
@ -152,4 +150,4 @@ void Kernel::svcCancelTimer() {
cancelTimer(object->getData<Timer>());
regs[0] = Result::Success;
}
}
}

View file

@ -119,7 +119,7 @@ u8 Memory::read8(u32 vaddr) {
case ConfigMem::FirmRevision: return firm.revision;
case ConfigMem::FirmVersionMinor: return firm.minor;
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 + 1:
@ -171,11 +171,10 @@ u32 Memory::read32(u32 vaddr) {
case ConfigMem::AppMemAlloc: return appResourceLimits.maxCommit;
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
case ConfigMem::WifiMac:
return (u32(MACAddress[3]) << 24) | (u32(MACAddress[2]) << 16) | (u32(MACAddress[1]) << 8) |
MACAddress[0];
case ConfigMem::WifiMac: 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.
case ConfigMem::SliderState3D: return Helpers::bit_cast<u32, float>(0.0f);
@ -185,7 +184,7 @@ u32 Memory::read32(u32 vaddr) {
default:
if (vaddr >= VirtualAddrs::VramStart && vaddr < VirtualAddrs::VramStart + VirtualAddrs::VramSize) {
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++;
Helpers::warn("VRAM read!\n");
}
@ -440,7 +439,7 @@ MemoryInfo Memory::queryMemory(u32 vaddr) {
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) {
if (e.handle == handle) {
// Virtual Console titles trigger this. TODO: Investigate how it should work
@ -534,4 +533,4 @@ std::optional<u64> Memory::getProgramID() {
}
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 "ipc.hpp"
namespace ACCommands {
@ -72,7 +73,7 @@ void ACService::getLastErrorCode(u32 messagePointer) {
mem.write32(messagePointer, IPC::responseHeader(0x0A, 2, 0));
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) {
@ -130,10 +131,10 @@ void ACService::registerDisconnectEvent(u32 messagePointer) {
const u32 pidHeader = mem.read32(messagePointer + 4);
const u32 copyHandleHeader = mem.read32(messagePointer + 12);
// 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;
mem.write32(messagePointer, IPC::responseHeader(0x30, 1, 0));
mem.write32(messagePointer + 4, Result::Success);
}
}

View file

@ -1,10 +1,11 @@
#include "services/apt.hpp"
#include "ipc.hpp"
#include "kernel.hpp"
#include <algorithm>
#include <vector>
#include "ipc.hpp"
#include "kernel.hpp"
namespace APTCommands {
enum : u32 {
GetLockHandle = 0x00010040,
@ -84,8 +85,7 @@ void APTService::appletUtility(u32 messagePointer) {
u32 outputSize = mem.read32(messagePointer + 12);
u32 inputPointer = mem.read32(messagePointer + 20);
log("APT::AppletUtility(utility = %d, input size = %x, output size = %x, inputPointer = %08X)\n", utility, inputSize, outputSize,
inputPointer);
log("APT::AppletUtility(utility = %d, input size = %x, output size = %x, inputPointer = %08X)\n", utility, inputSize, outputSize, inputPointer);
std::vector<u8> out(outputSize);
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 + 4, Result::Success);
mem.write8(messagePointer + 20, 1); // 1 = registered
mem.write8(messagePointer + 24, 1); // 1 = loaded
// TODO: The rest of this
mem.write8(messagePointer + 20, 1); // 1 = registered
mem.write8(messagePointer + 24, 1); // 1 = loaded
// TODO: The rest of this
}
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 + 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) {
@ -144,7 +144,7 @@ void APTService::prepareToStartLibraryApplet(u32 messagePointer) {
void APTService::startLibraryApplet(u32 messagePointer) {
const u32 appID = mem.read32(messagePointer + 4);
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);
log("APT::StartLibraryApplet (app ID = %X)\n", appID);
@ -178,7 +178,7 @@ void APTService::checkNew3DS(u32 messagePointer) {
log("APT::CheckNew3DS\n");
mem.write32(messagePointer, IPC::responseHeader(0x102, 2, 0));
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
@ -186,7 +186,7 @@ void APTService::checkNew3DSApp(u32 messagePointer) {
log("APT::CheckNew3DSApp\n");
mem.write32(messagePointer, IPC::responseHeader(0x101, 2, 0));
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) {
@ -207,14 +207,14 @@ void APTService::initialize(u32 messagePointer) {
notificationEvent = 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 + 4, Result::Success);
mem.write32(messagePointer + 8, 0x04000000); // Translation descriptor
mem.write32(messagePointer + 12, notificationEvent.value()); // Notification Event Handle
mem.write32(messagePointer + 16, resumeEvent.value()); // Resume Event Handle
mem.write32(messagePointer + 8, 0x04000000); // Translation descriptor
mem.write32(messagePointer + 12, notificationEvent.value()); // Notification Event HandleType
mem.write32(messagePointer + 16, resumeEvent.value()); // Resume Event HandleType
}
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 + 4, Result::Success); // Result code
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 + 16, 0); // Translation descriptor
mem.write32(messagePointer + 20, lockHandle.value()); // Lock handle
mem.write32(messagePointer + 4, Result::Success); // Result code
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 + 16, 0); // Translation descriptor
mem.write32(messagePointer + 20, lockHandle.value()); // Lock handle
}
// 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 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);
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) {
u32 fixed = mem.read32(messagePointer + 4); // MUST be 1.
u32 percentage = mem.read32(messagePointer + 8); // CPU time percentage between 5% and 89%
u32 fixed = mem.read32(messagePointer + 4); // MUST be 1.
u32 percentage = mem.read32(messagePointer + 8); // CPU time percentage between 5% and 89%
log("APT::SetApplicationCpuTimeLimit (percentage = %d%%)\n", percentage);
mem.write32(messagePointer, IPC::responseHeader(0x4F, 1, 0));
@ -409,15 +409,14 @@ void APTService::theSmashBrosFunction(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);
if (size > 0x10)
Helpers::panic("APT::GetWirelessInfo with size > 0x10 bytes");
if (size > 0x10) Helpers::panic("APT::GetWirelessInfo with size > 0x10 bytes");
mem.write32(messagePointer, IPC::responseHeader(0x45, 1, 2));
mem.write32(messagePointer + 4, Result::Success);
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 "ipc.hpp"
namespace BOSSCommands {
@ -31,9 +32,7 @@ namespace BOSSCommands {
};
}
void BOSSService::reset() {
optoutFlag = 0;
}
void BOSSService::reset() { optoutFlag = 0; }
void BOSSService::handleSyncRequest(u32 messagePointer) {
const u32 command = mem.read32(messagePointer);
@ -44,8 +43,7 @@ void BOSSService::handleSyncRequest(u32 messagePointer) {
case BOSSCommands::GetNsDataIdList:
case BOSSCommands::GetNsDataIdList1:
case BOSSCommands::GetNsDataIdList2:
case BOSSCommands::GetNsDataIdList3:
getNsDataIdList(messagePointer, command); break;
case BOSSCommands::GetNsDataIdList3: getNsDataIdList(messagePointer, command); break;
case BOSSCommands::GetOptoutFlag: getOptoutFlag(messagePointer); break;
case BOSSCommands::GetStorageEntryInfo: getStorageEntryInfo(messagePointer); break;
case BOSSCommands::GetTaskIdList: getTaskIdList(messagePointer); break;
@ -99,7 +97,7 @@ void BOSSService::getTaskState(u32 messagePointer) {
mem.write32(messagePointer + 4, Result::Success);
mem.write8(messagePointer + 8, 0); // TaskStatus: Report the task finished successfully
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) {
@ -150,15 +148,15 @@ void BOSSService::getErrorCode(u32 messagePointer) {
log("BOSS::GetErrorCode (stubbed)\n");
mem.write32(messagePointer, IPC::responseHeader(0x2E, 2, 0));
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) {
log("BOSS::GetStorageEntryInfo (undocumented)\n");
mem.write32(messagePointer, IPC::responseHeader(0x30, 3, 0));
mem.write32(messagePointer + 4, Result::Success);
mem.write32(messagePointer + 8, 0); // u32, unknown meaning
mem.write16(messagePointer + 12, 0); // s16, unknown meaning
mem.write32(messagePointer + 8, 0); // u32, unknown meaning
mem.write16(messagePointer + 12, 0); // s16, unknown meaning
}
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 + 4, Result::Success);
mem.write32(messagePointer + 8, 0); // Read size
// TODO: Should this do anything else?
// TODO: Should this do anything else?
}
void BOSSService::receiveProperty(u32 messagePointer) {
const u32 id = mem.read32(messagePointer + 4);
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);
mem.write32(messagePointer, IPC::responseHeader(0x16, 2, 2));
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
// I need to update the 3DBrew page when it's known what it does properly
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);
mem.write32(messagePointer, IPC::responseHeader(0x8, 1, 0));
@ -252,5 +249,5 @@ void BOSSService::getNewArrivalFlag(u32 messagePointer) {
log("BOSS::GetNewArrivalFlag (stubbed)\n");
mem.write32(messagePointer, IPC::responseHeader(0x7, 2, 0));
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 size = mem.read32(messagePointer + 12);
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);
log("CAM::SetReceiving (port = %d)\n", portIndex);

View file

@ -1,10 +1,11 @@
#include "services/dsp.hpp"
#include "ipc.hpp"
#include "kernel.hpp"
#include <algorithm>
#include <fstream>
#include "ipc.hpp"
#include "kernel.hpp"
namespace DSPCommands {
enum : u32 {
RecvData = 0x00010040,
@ -25,10 +26,7 @@ namespace DSPCommands {
}
namespace Result {
enum : u32 {
HeadphonesNotInserted = 0,
HeadphonesInserted = 1
};
enum : u32 { HeadphonesNotInserted = 0, HeadphonesInserted = 1 };
}
void DSPService::reset() {
@ -74,7 +72,7 @@ void DSPService::convertProcessAddressFromDspDram(u32 messagePointer) {
mem.write32(messagePointer, IPC::responseHeader(0xC, 2, 0));
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) {
@ -94,9 +92,9 @@ void DSPService::loadComponent(u32 messagePointer) {
mem.write32(messagePointer, IPC::responseHeader(0x11, 2, 2));
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 + 16, mem.read32(messagePointer + 20)); // Component buffer
mem.write32(messagePointer + 16, mem.read32(messagePointer + 20)); // Component buffer
}
void DSPService::unloadComponent(u32 messagePointer) {
@ -121,7 +119,7 @@ void DSPService::readPipeIfPossible(u32 messagePointer) {
}
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) {
@ -153,12 +151,10 @@ DSPService::DSPEvent& DSPService::getEventRef(u32 type, u32 pipe) {
case 1: return interrupt1;
case 2:
if (pipe >= pipeCount)
Helpers::panic("Tried to access the event of an invalid pipe");
if (pipe >= pipeCount) Helpers::panic("Tried to access the event of an invalid pipe");
return pipeEvents[pipe];
default:
Helpers::panic("Unknown type for DSP::getEventRef");
default: 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
if (eventHandle == 0) {
DSPEvent& e = getEventRef(interrupt, channel); // Get event
if (e.has_value()) { // Remove if it exists
DSPEvent& e = getEventRef(interrupt, channel); // Get event
if (e.has_value()) { // Remove if it exists
totalEventCount--;
e = std::nullopt;
}
@ -198,7 +194,7 @@ void DSPService::getHeadphoneStatus(u32 messagePointer) {
mem.write32(messagePointer, IPC::responseHeader(0x1F, 2, 0));
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) {
@ -211,7 +207,7 @@ void DSPService::getSemaphoreEventHandle(u32 messagePointer) {
mem.write32(messagePointer, IPC::responseHeader(0x16, 1, 2));
mem.write32(messagePointer + 4, Result::Success);
// 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());
}
@ -249,7 +245,7 @@ void DSPService::writeProcessPipe(u32 messagePointer) {
void DSPService::flushDataCache(u32 messagePointer) {
const u32 address = mem.read32(messagePointer + 4);
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);
mem.write32(messagePointer, IPC::responseHeader(0x13, 1, 0));
@ -259,7 +255,7 @@ void DSPService::flushDataCache(u32 messagePointer) {
void DSPService::invalidateDCache(u32 messagePointer) {
const u32 address = mem.read32(messagePointer + 4);
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);
mem.write32(messagePointer, IPC::responseHeader(0x14, 1, 0));
@ -303,4 +299,4 @@ void DSPService::triggerInterrupt1() {
if (interrupt1.has_value()) {
kernel.signalEvent(*interrupt1);
}
}
}

View file

@ -1,10 +1,11 @@
#include "services/fs.hpp"
#include "kernel/kernel.hpp"
#include "io_file.hpp"
#include "ipc.hpp"
#include "kernel/kernel.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 CreateFile
#undef DeleteFile
@ -47,21 +48,18 @@ namespace FSCommands {
};
}
void FSService::reset() {
priority = 0;
}
void FSService::reset() { priority = 0; }
// Creates directories for NAND, ExtSaveData, etc if they don't already exist. Should be executed after loading a new ROM.
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 savePath = IOFile::getAppData() / "SaveData"; // Create SaveData
const auto formatPath = IOFile::getAppData() / "FormatInfo"; // Create folder for storing archive formatting info
const auto savePath = IOFile::getAppData() / "SaveData"; // Create SaveData
const auto formatPath = IOFile::getAppData() / "FormatInfo"; // Create folder for storing archive formatting info
const auto systemSaveDataPath = IOFile::getAppData() / ".." / "SharedFiles" / "SystemSaveData";
namespace fs = std::filesystem;
if (!fs::is_directory(nandSharedpath)) {
fs::create_directories(nandSharedpath);
}
@ -89,25 +87,21 @@ ArchiveBase* FSService::getArchiveFromID(u32 id, const FSPath& archivePath) {
case ArchiveID::SaveData: return &saveData;
case ArchiveID::UserSaveData2: return &userSaveData2;
case ArchiveID::ExtSaveData:
return &extSaveData_sdmc;
case ArchiveID::ExtSaveData: return &extSaveData_sdmc;
case ArchiveID::SharedExtSaveData:
return &sharedExtSaveData_nand;
case ArchiveID::SharedExtSaveData: return &sharedExtSaveData_nand;
case ArchiveID::SystemSaveData: return &systemSaveData;
case ArchiveID::SDMC: return &sdmc;
case ArchiveID::SDMCWriteOnly: return &sdmcWriteOnly;
case ArchiveID::SavedataAndNcch: return &ncch; // This can only access NCCH outside of FSPXI
default:
Helpers::panic("Unknown archive. ID: %d\n", id);
return nullptr;
case ArchiveID::SavedataAndNcch: return &ncch; // This can only access NCCH outside of FSPXI
default: 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);
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& 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);
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& object = kernel.getObjects()[handle];
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);
if (archive == nullptr) [[unlikely]] {
@ -147,8 +141,7 @@ Rust::Result<Handle, Result::HorizonResult> FSService::openArchiveHandle(u32 arc
archiveObject.data = new ArchiveSession(res.unwrap(), path);
return Ok(handle);
}
else {
} else {
return Err(res.unwrapErr());
}
}
@ -157,8 +150,7 @@ FSPath FSService::readPath(u32 type, u32 pointer, u32 size) {
std::vector<u8> data;
data.resize(size);
for (u32 i = 0; i < size; i++)
data[i] = mem.read8(pointer + i);
for (u32 i = 0; i < size; i++) data[i] = mem.read8(pointer + i);
return FSPath(type, data);
}
@ -217,7 +209,7 @@ void FSService::initializeWithSdkVersion(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);
log("FSService::CloseArchive(handle = %X)\n", handle);
@ -241,7 +233,7 @@ void FSService::openArchive(u32 messagePointer) {
auto archivePath = readPath(archivePathType, archivePathPointer, archivePathSize);
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));
if (res.isOk()) {
mem.write32(messagePointer + 4, Result::Success);
@ -254,7 +246,7 @@ void FSService::openArchive(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 filePathSize = mem.read32(messagePointer + 20);
const u32 openFlags = mem.read32(messagePointer + 24);
@ -276,14 +268,14 @@ void FSService::openFile(u32 messagePointer) {
auto filePath = readPath(filePathType, filePathPointer, filePathSize);
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));
if (!handle.has_value()) {
printf("OpenFile failed\n");
mem.write32(messagePointer + 4, Result::FS::FileNotFound);
} else {
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());
}
}
@ -291,7 +283,7 @@ void FSService::openFile(u32 messagePointer) {
void FSService::createDirectory(u32 messagePointer) {
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 pathSize = mem.read32(messagePointer + 20);
const u32 pathPointer = mem.read32(messagePointer + 32);
@ -313,7 +305,7 @@ void FSService::createDirectory(u32 messagePointer) {
void FSService::openDirectory(u32 messagePointer) {
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 pathSize = mem.read32(messagePointer + 16);
const u32 pathPointer = mem.read32(messagePointer + 24);
@ -366,7 +358,7 @@ void FSService::openFileDirectly(u32 messagePointer) {
}
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));
if (!handle.has_value()) {
printf("OpenFileDirectly failed\n");
@ -378,7 +370,7 @@ void FSService::openFileDirectly(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 filePathSize = mem.read32(messagePointer + 20);
const u32 attributes = mem.read32(messagePointer + 24);
@ -403,7 +395,7 @@ void FSService::createFile(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 filePathSize = mem.read32(messagePointer + 20);
const u32 filePathPointer = mem.read32(messagePointer + 28);
@ -425,7 +417,7 @@ void FSService::deleteFile(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 filePathSize = mem.read32(messagePointer + 20);
const u32 filePathPointer = mem.read32(messagePointer + 28);
@ -470,8 +462,7 @@ void FSService::formatSaveData(u32 messagePointer) {
log("FS::FormatSaveData\n");
const u32 archiveID = mem.read32(messagePointer + 4);
if (archiveID != ArchiveID::SaveData)
Helpers::panic("FS::FormatSaveData: Archive is not SaveData");
if (archiveID != ArchiveID::SaveData) Helpers::panic("FS::FormatSaveData: Archive is not SaveData");
// Read path and path info
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
const u32 blockSize = mem.read32(messagePointer + 16);
if (blockSize != 0x200 && blockSize != 0x1000)
Helpers::panic("FS::FormatSaveData: Invalid SaveData block size");
if (blockSize != 0x200 && blockSize != 0x1000) Helpers::panic("FS::FormatSaveData: Invalid SaveData block size");
const u32 directoryNum = mem.read32(messagePointer + 20); // Max number of directories
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 fileBucketNum = mem.read32(messagePointer + 32); // Same here
const u32 directoryNum = mem.read32(messagePointer + 20); // Max number of directories
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 fileBucketNum = mem.read32(messagePointer + 32); // Same here
const bool duplicateData = mem.read8(messagePointer + 36) != 0;
ArchiveBase::FormatInfo info {
.size = blockSize * 0x200,
.numOfDirectories = directoryNum,
.numOfFiles = fileNum,
.duplicateData = duplicateData
};
ArchiveBase::FormatInfo info{.size = blockSize * 0x200, .numOfDirectories = directoryNum, .numOfFiles = fileNum, .duplicateData = duplicateData};
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);
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
// When we properly implement it, it will just be a recursive directory deletion
// 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 When we properly implement it, it will just be a recursive directory deletion
mem.write32(messagePointer + 4, Result::Success);
}
@ -521,7 +506,8 @@ void FSService::createExtSaveData(u32 messagePointer) {
Helpers::warn("Stubbed call to FS::CreateExtSaveData!");
// First 4 words of parameters are the ExtSaveData info
// 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 u64 saveID = mem.read64(messagePointer + 8);
const u32 numOfDirectories = mem.read32(messagePointer + 20);
@ -541,18 +527,13 @@ void FSService::formatThisUserSaveData(u32 messagePointer) {
log("FS::FormatThisUserSaveData\n");
const u32 blockSize = mem.read32(messagePointer + 4);
const u32 directoryNum = mem.read32(messagePointer + 8); // Max number of directories
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 fileBucketNum = mem.read32(messagePointer + 20); // Same here
const u32 directoryNum = mem.read32(messagePointer + 8); // Max number of directories
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 fileBucketNum = mem.read32(messagePointer + 20); // Same here
const bool duplicateData = mem.read8(messagePointer + 24) != 0;
ArchiveBase::FormatInfo info {
.size = blockSize * 0x200,
.numOfDirectories = directoryNum,
.numOfFiles = fileNum,
.duplicateData = duplicateData
};
ArchiveBase::FormatInfo info{.size = blockSize * 0x200, .numOfDirectories = directoryNum, .numOfFiles = fileNum, .duplicateData = duplicateData};
FSPath emptyPath;
mem.write32(messagePointer, IPC::responseHeader(0x080F, 1, 0));
@ -560,7 +541,7 @@ void FSService::formatThisUserSaveData(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 inputSize = mem.read32(messagePointer + 16);
const u32 outputSize = mem.read32(messagePointer + 20);
@ -578,24 +559,22 @@ void FSService::controlArchive(u32 messagePointer) {
}
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);
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");
mem.write32(messagePointer + 4, Result::Success);
break;
default:
Helpers::panic("Unimplemented action for ControlArchive (action = %X)\n", action);
break;
default: Helpers::panic("Unimplemented action for ControlArchive (action = %X)\n", action); break;
}
}
void FSService::getFreeBytes(u32 messagePointer) {
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);
mem.write32(messagePointer, IPC::responseHeader(0x812, 3, 0));
@ -639,7 +618,7 @@ void FSService::getArchiveResource(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);
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 + 4, Result::Success);
mem.write8(messagePointer + 8, 0); // Secure value does not exist
mem.write8(messagePointer + 12, 1); // TODO: What is this?
mem.write64(messagePointer + 16, 0); // Secure value
mem.write8(messagePointer + 8, 0); // Secure value does not exist
mem.write8(messagePointer + 12, 1); // TODO: What is this?
mem.write64(messagePointer + 16, 0); // Secure value
}
void FSService::setThisSaveDataSecureValue(u32 messagePointer) {
@ -731,8 +710,8 @@ void FSService::renameFile(u32 messagePointer) {
mem.write32(messagePointer, IPC::responseHeader(0x805, 1, 0));
const Handle sourceArchiveHandle = mem.read64(messagePointer + 8);
const Handle destArchiveHandle = mem.read64(messagePointer + 24);
const HandleType sourceArchiveHandle = mem.read64(messagePointer + 8);
const HandleType destArchiveHandle = mem.read64(messagePointer + 24);
// Read path info
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 + 16, resource.partitionCapacityInClusters);
mem.write32(messagePointer + 20, resource.freeSpaceInClusters);
}
}

View file

@ -1,7 +1,9 @@
#include "services/hid.hpp"
#include <bit>
#include "ipc.hpp"
#include "kernel.hpp"
#include <bit>
namespace HIDCommands {
enum : u32 {
@ -86,24 +88,24 @@ void HIDService::disableGyroscopeLow(u32 messagePointer) {
void HIDService::getGyroscopeLowCalibrateParam(u32 messagePointer) {
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 + 4, Result::Success);
// Fill calibration data (for x/y/z depending on 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 + 1 * sizeof(u16), unit); // Positive unit point
mem.write16(pointer + 2 * sizeof(u16), -unit); // Negative unit point
mem.write16(pointer, 0); // Zero point
mem.write16(pointer + 1 * sizeof(u16), unit); // Positive unit point
mem.write16(pointer + 2 * sizeof(u16), -unit); // Negative unit point
}
}
void HIDService::getGyroscopeCoefficient(u32 messagePointer) {
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 + 4, Result::Success);
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 + 4, Result::Success); // Result code
mem.write32(messagePointer + 8, 0x14000000); // Translation descriptor
mem.write32(messagePointer + 12, KernelHandles::HIDSharedMemHandle); // Shared memory handle
mem.write32(messagePointer + 4, Result::Success); // Result code
mem.write32(messagePointer + 8, 0x14000000); // Translation descriptor
mem.write32(messagePointer + 12, KernelHandles::HIDSharedMemHandle); // Shared memory handle
// Write HID event handles
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) {
// First, update the pad state
if (nextPadIndex == 0) {
writeSharedMem<u64>(0x8, readSharedMem<u64>(0x0)); // Copy previous tick count
writeSharedMem<u64>(0x0, currentTick); // Write new tick count
writeSharedMem<u64>(0x8, readSharedMem<u64>(0x0)); // Copy previous tick count
writeSharedMem<u64>(0x0, currentTick); // Write new tick count
}
writeSharedMem<u32>(0x10, nextPadIndex); // Index last updated by the HID module
writeSharedMem<u32>(0x1C, newButtons); // Current PAD state
writeSharedMem<s16>(0x20, circlePadX); // Current circle pad state
writeSharedMem<u32>(0x10, nextPadIndex); // Index last updated by the HID module
writeSharedMem<u32>(0x1C, newButtons); // Current PAD state
writeSharedMem<s16>(0x20, circlePadX); // Current circle pad state
writeSharedMem<s16>(0x22, circlePadY);
const size_t padEntryOffset = 0x28 + (nextPadIndex * 0x10); // Offset in the array of 8 pad entries
nextPadIndex = (nextPadIndex + 1) % 8; // Move to next entry
const size_t padEntryOffset = 0x28 + (nextPadIndex * 0x10); // Offset in the array of 8 pad entries
nextPadIndex = (nextPadIndex + 1) % 8; // Move to next entry
const u32 pressed = (newButtons ^ oldButtons) & newButtons; // Pressed buttons
const u32 released = (newButtons ^ oldButtons) & oldButtons; // Released buttons
const u32 pressed = (newButtons ^ oldButtons) & newButtons; // Pressed buttons
const u32 released = (newButtons ^ oldButtons) & oldButtons; // Released buttons
oldButtons = newButtons;
writeSharedMem<u32>(padEntryOffset, newButtons);
@ -173,12 +175,12 @@ void HIDService::updateInputs(u64 currentTick) {
// Next, update touchscreen state
if (nextTouchscreenIndex == 0) {
writeSharedMem<u64>(0xB0, readSharedMem<u64>(0xA8)); // Copy previous tick count
writeSharedMem<u64>(0xA8, currentTick); // Write new tick count
writeSharedMem<u64>(0xB0, readSharedMem<u64>(0xA8)); // Copy previous tick count
writeSharedMem<u64>(0xA8, currentTick); // Write new tick count
}
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
nextTouchscreenIndex = (nextTouchscreenIndex + 1) % 8; // Move to next entry
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
nextTouchscreenIndex = (nextTouchscreenIndex + 1) % 8; // Move to next entry
writeSharedMem<u16>(touchEntryOffset, touchScreenX);
writeSharedMem<u16>(touchEntryOffset + 2, touchScreenY);
@ -186,16 +188,16 @@ void HIDService::updateInputs(u64 currentTick) {
// Next, update accelerometer state
if (nextAccelerometerIndex == 0) {
writeSharedMem<u64>(0x110, readSharedMem<u64>(0x108)); // Copy previous tick count
writeSharedMem<u64>(0x108, currentTick); // Write new tick count
writeSharedMem<u64>(0x110, readSharedMem<u64>(0x108)); // Copy previous tick count
writeSharedMem<u64>(0x108, currentTick); // Write new tick count
}
writeSharedMem<u32>(0x118, nextAccelerometerIndex); // Index last updated by the HID module
nextAccelerometerIndex = (nextAccelerometerIndex + 1) % 8; // Move to next entry
writeSharedMem<u32>(0x118, nextAccelerometerIndex); // Index last updated by the HID module
nextAccelerometerIndex = (nextAccelerometerIndex + 1) % 8; // Move to next entry
// Next, update gyro state
if (nextGyroIndex == 0) {
writeSharedMem<u64>(0x160, readSharedMem<u64>(0x158)); // Copy previous tick count
writeSharedMem<u64>(0x158, currentTick); // Write new tick count
writeSharedMem<u64>(0x160, readSharedMem<u64>(0x158)); // Copy previous 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
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
roll = pitch = yaw = 0;
writeSharedMem<u32>(0x168, nextGyroIndex); // Index last updated by the HID module
nextGyroIndex = (nextGyroIndex + 1) % 32; // Move to next entry
writeSharedMem<u32>(0x168, nextGyroIndex); // Index last updated by the HID module
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
@ -218,4 +220,4 @@ void HIDService::updateInputs(u64 currentTick) {
kernel.signalEvent(e.value());
}
}
}
}

View file

@ -1,10 +1,11 @@
#include "services/ldr_ro.hpp"
#include "ipc.hpp"
#include "kernel.hpp"
#include <cstdio>
#include <string>
#include "ipc.hpp"
#include "kernel.hpp"
namespace LDRCommands {
enum : u32 {
Initialize = 0x000100C2,
@ -65,10 +66,13 @@ namespace SegmentTable {
namespace SegmentID {
enum : u32 {
TEXT, RODATA, DATA, BSS,
TEXT,
RODATA,
DATA,
BSS,
};
}
}
} // namespace SegmentTable
namespace NamedExportTable {
enum : u32 {
@ -118,8 +122,8 @@ namespace RelocationPatch {
enum : u32 {
SegmentOffset = 0,
PatchType = 4,
IsLastEntry = 5, // For import patches
SegmentIndex = 5, // For relocation patches
IsLastEntry = 5, // For import patches
SegmentIndex = 5, // For relocation patches
IsResolved = 6,
Addend = 8,
};
@ -129,7 +133,7 @@ namespace RelocationPatch {
AbsoluteAddress = 2,
};
};
};
}; // namespace RelocationPatch
struct CROHeaderEntry {
u32 offset, size;
@ -144,12 +148,12 @@ static const std::string CRR_MAGIC("CRR0");
class CRO {
Memory &mem;
u32 croPointer; // Origin address of CRO in RAM
u32 croPointer; // Origin address of CRO in RAM
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() = default;
@ -159,21 +163,13 @@ public:
return mem.readString(moduleName.offset, moduleName.size);
}
u32 getNextCRO() {
return mem.read32(croPointer + CROHeader::NextCRO);
}
u32 getPrevCRO() {
return mem.read32(croPointer + CROHeader::PrevCRO);
}
u32 getNextCRO() { return mem.read32(croPointer + CROHeader::NextCRO); }
void setNextCRO(u32 nextCRO) {
mem.write32(croPointer + CROHeader::NextCRO, nextCRO);
}
u32 getPrevCRO() { return mem.read32(croPointer + CROHeader::PrevCRO); }
void setPrevCRO(u32 prevCRO) {
mem.write32(croPointer + CROHeader::PrevCRO, prevCRO);
}
void setNextCRO(u32 nextCRO) { mem.write32(croPointer + CROHeader::NextCRO, nextCRO); }
void setPrevCRO(u32 prevCRO) { mem.write32(croPointer + CROHeader::PrevCRO, prevCRO); }
void write32(u32 addr, u32 value) {
// 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()
auto writePointer = mem.getWritePointer(addr);
if (writePointer) {
*(u32*)writePointer = value;
*(u32 *)writePointer = value;
} else {
auto readPointer = mem.getReadPointer(addr);
if (readPointer) {
*(u32*)readPointer = value;
*(u32 *)readPointer = value;
} else {
Helpers::panic("LDR_RO write to invalid address = %X\n", addr);
}
@ -219,11 +215,9 @@ public:
return entryOffset + offset;
}
u32 getOnUnresolvedAddr() {
return getSegmentAddr(mem.read32(croPointer + CROHeader::OnUnresolved));
}
u32 getOnUnresolvedAddr() { 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,
// 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++) {
const u32 nameOffset = mem.read32(namedExportTable.offset + 8 * namedExport + NamedExportTable::NameOffset);
const std::string exportSymbolName = mem.readString(nameOffset, exportStringSize);
if (symbolName.compare(exportSymbolName) == 0) {
@ -437,13 +431,16 @@ public:
const u32 segmentID = mem.read32(segmentTable.offset + 12 * segment + SegmentTable::ID);
switch (segmentID) {
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::TEXT:
case SegmentTable::SegmentID::RODATA:
if (segmentOffset != 0) segmentOffset += croPointer; break;
default:
Helpers::panic("Unknown segment ID = %u", segmentID);
if (segmentOffset != 0) segmentOffset += croPointer;
break;
default: Helpers::panic("Unknown segment ID = %u", segmentID);
}
mem.write32(segmentTable.offset + 12 * segment + SegmentTable::Offset, segmentOffset);
@ -464,9 +461,9 @@ public:
case SegmentTable::SegmentID::BSS: segmentOffset = 0; break;
case SegmentTable::SegmentID::TEXT:
case SegmentTable::SegmentID::RODATA:
if (segmentOffset != 0) segmentOffset -= croPointer; break;
default:
Helpers::panic("Unknown segment ID = %u", segmentID);
if (segmentOffset != 0) segmentOffset -= croPointer;
break;
default: Helpers::panic("Unknown segment ID = %u", segmentID);
}
mem.write32(segmentTable.offset + 12 * segment + SegmentTable::Offset, segmentOffset);
@ -630,7 +627,9 @@ public:
u32 relocationOffset = mem.read32(anonymousImportTable.offset + 8 * anonymousImport + AnonymousImportTable::RelocationOffset);
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);
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) {
const u8* header = (u8*)mem.getReadPointer(croPointer);
const u8 *header = (u8 *)mem.getReadPointer(croPointer);
const CROHeaderEntry relocationPatchTable = getHeaderEntry(CROHeader::RelocationPatchTableOffset);
const CROHeaderEntry segmentTable = getHeaderEntry(CROHeader::SegmentTableOffset);
@ -708,7 +709,7 @@ public:
for (u32 namedImport = 0; namedImport < namedImportTable.size; namedImport++) {
const u32 nameOffset = mem.read32(namedImportTable.offset + 8 * namedImport + NamedImportTable::NameOffset);
const u32 relocationOffset = mem.read32(namedImportTable.offset + 8 * namedImport + NamedImportTable::RelocationOffset);
const std::string symbolName = mem.readString(nameOffset, importStringSize);
if (symbolName.compare(std::string("__aeabi_atexit")) == 0) {
@ -720,7 +721,7 @@ public:
const u32 exportSymbolAddr = cro.getNamedExportSymbolAddr(std::string("nnroAeabiAtexit_"));
if (exportSymbolAddr != 0) {
patchBatch(relocationOffset, exportSymbolAddr);
return true;
}
@ -750,7 +751,7 @@ public:
if (isResolved == 0) {
const u32 nameOffset = mem.read32(namedImportTable.offset + 8 * namedImport + NamedImportTable::NameOffset);
const std::string symbolName = mem.readString(nameOffset, importStringSize);
// Check every loaded CRO for the symbol (the pain)
@ -859,7 +860,7 @@ public:
return true;
}
bool clearModules() {
const u32 onUnresolvedAddr = getOnUnresolvedAddr();
@ -874,7 +875,7 @@ public:
if (indexedOffset == 0) {
Helpers::panic("Indexed symbol offset is NULL");
}
const u32 relocationOffset = mem.read32(indexedOffset + 8 * indexedImport + IndexedImportTable::RelocationOffset);
patchBatch(relocationOffset, onUnresolvedAddr, true);
@ -919,7 +920,7 @@ public:
if (isResolved == 0) {
const u32 nameOffset = mem.read32(namedImportTable.offset + 8 * namedImport + NamedImportTable::NameOffset);
const std::string symbolName = mem.readString(nameOffset, importStringSize);
// Check our current CRO for the symbol
@ -983,7 +984,7 @@ public:
u32 currentCROPointer = loadedCRS;
while (currentCROPointer != 0) {
CRO cro(mem, currentCROPointer, true);
const u32 onUnresolvedAddr = cro.getOnUnresolvedAddr();
const u32 importStringSize = mem.read32(currentCROPointer + CROHeader::ImportStringSize);
@ -998,7 +999,7 @@ public:
if (isResolved != 0) {
const u32 nameOffset = mem.read32(namedImportTable.offset + 8 * namedImport + NamedImportTable::NameOffset);
const std::string symbolName = mem.readString(nameOffset, importStringSize);
// Check our current CRO for the symbol
@ -1106,7 +1107,7 @@ public:
}
CRO crs(mem, loadedCRS, false);
u32 headAddr = crs.getPrevCRO();
if (autoLink) {
headAddr = crs.getNextCRO();
@ -1189,9 +1190,7 @@ public:
}
};
void LDRService::reset() {
loadedCRS = 0;
}
void LDRService::reset() { loadedCRS = 0; }
void LDRService::handleSyncRequest(u32 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 size = mem.read32(messagePointer + 8);
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);
@ -1258,7 +1257,7 @@ void LDRService::initialize(u32 messagePointer) {
void LDRService::linkCRO(u32 messagePointer) {
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);
@ -1287,7 +1286,7 @@ void LDRService::linkCRO(u32 messagePointer) {
void LDRService::loadCRR(u32 messagePointer) {
const u32 crrPointer = mem.read32(messagePointer + 4);
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);
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 bool autoLink = mem.read32(messagePointer + 36) != 0;
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
if (size < CRO_HEADER_SIZE) {
@ -1362,7 +1363,7 @@ void LDRService::loadCRO(u32 messagePointer, bool isNew) {
void LDRService::unloadCRO(u32 messagePointer) {
const u32 mapVaddr = mem.read32(messagePointer + 4);
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);
@ -1392,4 +1393,4 @@ void LDRService::unloadCRO(u32 messagePointer) {
mem.write32(messagePointer, IPC::responseHeader(0x5, 1, 0));
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)
: 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),
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),
news_u(mem), nwm_uds(mem, kernel), ptm(mem, config), soc(mem), ssl(mem), y2r(mem, kernel) {}
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), news_u(mem), nwm_uds(mem, kernel), ptm(mem, config), soc(mem), ssl(mem), y2r(mem, kernel) {}
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
// messagePointer: The base pointer for the IPC message
void ServiceManager::handleSyncRequest(u32 messagePointer) {
@ -93,7 +93,7 @@ void ServiceManager::registerClient(u32 messagePointer) {
}
// clang-format off
static std::map<std::string, Handle> serviceMap = {
static std::map<std::string, HandleType> serviceMap = {
{ "ac:u", KernelHandles::AC },
{ "act:a", 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 + 4, Result::Success); // Result code
mem.write32(messagePointer + 8, 0); // Translation descriptor
// Handle to semaphore signaled on process notification
mem.write32(messagePointer + 4, Result::Success); // Result code
mem.write32(messagePointer + 8, 0); // Translation descriptor
// HandleType to semaphore signaled on process notification
mem.write32(messagePointer + 12, notificationSemaphore.value());
}
@ -175,8 +175,8 @@ void ServiceManager::receiveNotification(u32 messagePointer) {
log("srv::ReceiveNotification() (STUBBED)\n");
mem.write32(messagePointer, IPC::responseHeader(0xB, 2, 0));
mem.write32(messagePointer + 4, Result::Success); // Result code
mem.write32(messagePointer + 8, 0); // Notification ID
mem.write32(messagePointer + 4, Result::Success); // Result code
mem.write32(messagePointer + 8, 0); // Notification ID
}
void ServiceManager::subscribe(u32 messagePointer) {
@ -195,7 +195,7 @@ void ServiceManager::unsubscribe(u32 messagePointer) {
mem.write32(messagePointer + 4, Result::Success);
}
void ServiceManager::sendCommandToService(u32 messagePointer, Handle handle) {
void ServiceManager::sendCommandToService(u32 messagePointer, HandleType handle) {
switch (handle) {
// 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;
@ -237,4 +237,4 @@ void ServiceManager::sendCommandToService(u32 messagePointer, Handle handle) {
case KernelHandles::Y2R: y2r.handleSyncRequest(messagePointer); break;
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) {
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);
// 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 + 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 "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");
// Enable drop events for loading ROMs
setAcceptDrops(true);
@ -90,6 +91,7 @@ MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent)
const RendererType rendererType = emu->getConfig().rendererType;
usingGL = (rendererType == RendererType::OpenGL || rendererType == RendererType::Software || rendererType == RendererType::Null);
usingVk = (rendererType == RendererType::Vulkan);
usingMtl = (rendererType == RendererType::Metal);
if (usingGL) {
// Make GL context current for this thread, enable VSync
@ -100,6 +102,8 @@ MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent)
emu->initGraphicsContext(glContext);
} else if (usingVk) {
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 {
Helpers::panic("Unsupported graphics backend for Qt frontend!");
}
@ -264,8 +268,7 @@ void MainWindow::dumpDspFirmware() {
case DSPService::ComponentDumpResult::Success: break;
case DSPService::ComponentDumpResult::NotLoaded: {
QMessageBox messageBox(
QMessageBox::Icon::Warning, tr("No DSP firmware loaded"),
tr("The currently loaded app has not uploaded a firmware to the DSP")
QMessageBox::Icon::Warning, tr("No DSP firmware loaded"), tr("The currently loaded app has not uploaded a firmware to the DSP")
);
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
#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);
}
@ -240,7 +250,7 @@ void FrontendSDL::run() {
case SDL_MOUSEMOTION: {
if (emu.romType == ROMType::None) break;
// Handle "dragging" across the touchscreen
// HandleType "dragging" across the touchscreen
if (hid.isTouchScreenPressed()) {
const s32 x = event.motion.x;
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},
{"vk", RendererType::Vulkan}, {"vulkan", RendererType::Vulkan}, {"vulcan", RendererType::Vulkan},
{"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()) {
@ -34,6 +34,7 @@ const char* Renderer::typeToString(RendererType rendererType) {
case RendererType::OpenGL: return "opengl";
case RendererType::Vulkan: return "vulkan";
case RendererType::Software: return "software";
case RendererType::Metal: return "metal";
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