diff --git a/include/kernel/fcram.hpp b/include/kernel/fcram.hpp index 235b366f..e1690ad0 100644 --- a/include/kernel/fcram.hpp +++ b/include/kernel/fcram.hpp @@ -1,27 +1,42 @@ #pragma once #include #include -#include "kernel_types.hpp" + +#include "helpers.hpp" class Memory; +enum class FcramRegion { + App = 0x100, + Sys = 0x200, + Base = 0x300, +}; + +struct FcramBlock { + u32 paddr; + s32 pages; + + FcramBlock(u32 paddr, s32 pages) : paddr(paddr), pages(pages) {} +}; + using FcramBlockList = std::list; class KFcram { struct Region { struct Block { s32 pages; - s32 pageOffs; + s32 pageOffset; bool used; - Block(s32 pages, u32 pageOffs) : pages(pages), pageOffs(pageOffs), used(false) {} + Block(s32 pages, u32 pageOffset) : pages(pages), pageOffset(pageOffset), used(false) {} }; std::list blocks; u32 start; s32 pages; s32 freePages; - public: + + public: Region() : start(0), pages(0) {} void reset(u32 start, size_t size); void alloc(std::list& out, s32 pages, bool linear); @@ -35,7 +50,8 @@ class KFcram { Region appRegion, sysRegion, baseRegion; uint8_t* fcram; std::unique_ptr refs; -public: + + public: KFcram(Memory& memory); void reset(size_t ramSize, size_t appSize, size_t sysSize, size_t baseSize); void alloc(FcramBlockList& out, s32 pages, FcramRegion region, bool linear); diff --git a/include/kernel/kernel_types.hpp b/include/kernel/kernel_types.hpp index b48a701c..c77efd28 100644 --- a/include/kernel/kernel_types.hpp +++ b/include/kernel/kernel_types.hpp @@ -1,99 +1,97 @@ #pragma once #include #include + #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, -enum class FcramRegion { - App = 0x100, - Sys = 0x200, - Base = 0x300 + AppCore = 0, + Syscore = 1, + New3DSExtra1 = 2, + New3DSExtra2 = 3 }; struct AddressArbiter {}; struct ResourceLimits { - HorizonHandle handle; + HorizonHandle 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 { @@ -151,92 +149,90 @@ 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 { - using Handle = HorizonHandle; + using Handle = HorizonHandle; - 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 + 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; - Mutex(bool lock, Handle handle) : locked(lock), waitlist(0), lockCount(lock ? 1 : 0), handle(handle) {} + Mutex(bool lock, Handle 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 { using Handle = HorizonHandle; - Handle handle = 0; // A u32 the OS will use to identify objects - void* data = nullptr; - KernelObjectType type; + Handle 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(Handle 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 - T* getData() { - return static_cast(data); - } + template + T* getData() { + return static_cast(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. @@ -252,15 +248,7 @@ struct KernelObject { case KernelObjectType::Timer: return getData()->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()); } } }; - -struct FcramBlock { - u32 paddr; - s32 pages; - - FcramBlock(u32 paddr, s32 pages) : paddr(paddr), pages(pages) {} -}; \ No newline at end of file diff --git a/include/memory.hpp b/include/memory.hpp index a561f903..4a17f6d9 100644 --- a/include/memory.hpp +++ b/include/memory.hpp @@ -11,7 +11,7 @@ #include "handles.hpp" #include "helpers.hpp" #include "host_memory/host_memory.h" -#include "kernel/kernel_types.hpp" +#include "kernel/fcram.hpp" #include "loader/3dsx.hpp" #include "loader/ncsd.hpp" #include "result/result.hpp" diff --git a/include/renderer_mtl/pica_to_mtl.hpp b/include/renderer_mtl/pica_to_mtl.hpp index d4c6dc7c..5e9f62c4 100644 --- a/include/renderer_mtl/pica_to_mtl.hpp +++ b/include/renderer_mtl/pica_to_mtl.hpp @@ -14,10 +14,10 @@ namespace PICA { bool needsSwizzle = false; MTL::TextureSwizzleChannels swizzle{ - .red = MTL::TextureSwizzleRed, - .green = MTL::TextureSwizzleGreen, - .blue = MTL::TextureSwizzleBlue, - .alpha = MTL::TextureSwizzleAlpha, + MTL::TextureSwizzleRed, + MTL::TextureSwizzleGreen, + MTL::TextureSwizzleBlue, + MTL::TextureSwizzleAlpha, }; }; @@ -33,7 +33,7 @@ namespace PICA { case ColorFmt::RGBA5551: return MTL::PixelFormatRGBA8Unorm; // TODO: use MTL::PixelFormatBGR5A1Unorm? case ColorFmt::RGB565: return MTL::PixelFormatRGBA8Unorm; // TODO: use MTL::PixelFormatB5G6R5Unorm? #ifdef PANDA3DS_IOS - case ColorFmt::RGBA4: return MTL::PixelFormatRGBA8Unorm; // IOS + Metal doesn't support AGBR4 properly, at least on simulator + case ColorFmt::RGBA4: return MTL::PixelFormatRGBA8Unorm; // IOS + Metal doesn't support AGBR4 properly, at least on simulator #else case ColorFmt::RGBA4: return MTL::PixelFormatABGR4Unorm; #endif @@ -130,8 +130,7 @@ namespace PICA { case PrimType::TriangleFan: Helpers::warn("Triangle fans are not supported on Metal, using triangles instead"); return MTL::PrimitiveTypeTriangle; - case PrimType::GeometryPrimitive: - return MTL::PrimitiveTypeTriangle; + case PrimType::GeometryPrimitive: return MTL::PrimitiveTypeTriangle; } } diff --git a/src/core/kernel/fcram.cpp b/src/core/kernel/fcram.cpp index d5cdc67f..ebb58c34 100644 --- a/src/core/kernel/fcram.cpp +++ b/src/core/kernel/fcram.cpp @@ -2,7 +2,6 @@ #include "memory.hpp" - void KFcram::Region::reset(u32 start, size_t size) { this->start = start; pages = size >> 12; @@ -22,7 +21,7 @@ void KFcram::Region::alloc(std::list& out, s32 allocPages, bool line // If the current block is bigger than the allocation, split it if (it->pages > allocPages) { - Block newBlock(it->pages - allocPages, it->pageOffs + allocPages); + Block newBlock(it->pages - allocPages, it->pageOffset + allocPages); it->pages = allocPages; blocks.insert(it, newBlock); } @@ -32,7 +31,7 @@ void KFcram::Region::alloc(std::list& out, s32 allocPages, bool line allocPages -= it->pages; freePages -= it->pages; - u32 paddr = start + (it->pageOffs << 12); + u32 paddr = start + (it->pageOffset << 12); FcramBlock outBlock(paddr, it->pages); out.push_back(outBlock); diff --git a/src/core/renderer_mtl/pica_to_mtl.cpp b/src/core/renderer_mtl/pica_to_mtl.cpp index 973ad1bf..21b520f2 100644 --- a/src/core/renderer_mtl/pica_to_mtl.cpp +++ b/src/core/renderer_mtl/pica_to_mtl.cpp @@ -16,27 +16,27 @@ namespace PICA { decodeTexelAI8ToRG8, true, { - .red = MTL::TextureSwizzleRed, - .green = MTL::TextureSwizzleRed, - .blue = MTL::TextureSwizzleRed, - .alpha = MTL::TextureSwizzleGreen, + MTL::TextureSwizzleRed, + MTL::TextureSwizzleRed, + MTL::TextureSwizzleRed, + MTL::TextureSwizzleGreen, }}, // IA8 {MTL::PixelFormatRG8Unorm, 2, decodeTexelGR8ToRG8}, // RG8 {MTL::PixelFormatR8Unorm, 1, decodeTexelI8ToR8, true, - {.red = MTL::TextureSwizzleRed, .green = MTL::TextureSwizzleRed, .blue = MTL::TextureSwizzleRed, .alpha = MTL::TextureSwizzleOne}}, // I8 - {MTL::PixelFormatA8Unorm, 1, decodeTexelA8ToA8}, // A8 - {MTL::PixelFormatABGR4Unorm, 2, decodeTexelAI4ToABGR4}, // IA4 + {MTL::TextureSwizzleRed, MTL::TextureSwizzleRed, MTL::TextureSwizzleRed, MTL::TextureSwizzleOne}}, // I8 + {MTL::PixelFormatA8Unorm, 1, decodeTexelA8ToA8}, // A8 + {MTL::PixelFormatABGR4Unorm, 2, decodeTexelAI4ToABGR4}, // IA4 {MTL::PixelFormatR8Unorm, 1, decodeTexelI4ToR8, true, - {.red = MTL::TextureSwizzleRed, .green = MTL::TextureSwizzleRed, .blue = MTL::TextureSwizzleRed, .alpha = MTL::TextureSwizzleOne}}, // I4 - {MTL::PixelFormatA8Unorm, 1, decodeTexelA4ToA8}, // A4 - {MTL::PixelFormatRGBA8Unorm, 4, decodeTexelETC1ToRGBA8}, // ETC1 - {MTL::PixelFormatRGBA8Unorm, 4, decodeTexelETC1A4ToRGBA8}, // ETC1A4 + {MTL::TextureSwizzleRed, MTL::TextureSwizzleRed, MTL::TextureSwizzleRed, MTL::TextureSwizzleOne}}, // I4 + {MTL::PixelFormatA8Unorm, 1, decodeTexelA4ToA8}, // A4 + {MTL::PixelFormatRGBA8Unorm, 4, decodeTexelETC1ToRGBA8}, // ETC1 + {MTL::PixelFormatRGBA8Unorm, 4, decodeTexelETC1A4ToRGBA8}, // ETC1A4 }; void checkForMTLPixelFormatSupport(MTL::Device* device) { @@ -57,10 +57,10 @@ namespace PICA { decodeTexelAI4ToRG8, true, { - .red = MTL::TextureSwizzleRed, - .green = MTL::TextureSwizzleRed, - .blue = MTL::TextureSwizzleRed, - .alpha = MTL::TextureSwizzleGreen, + MTL::TextureSwizzleRed, + MTL::TextureSwizzleRed, + MTL::TextureSwizzleRed, + MTL::TextureSwizzleGreen, } }; }