Improve Shared Fonts + Fix AM PopLaunchParameter & Choreographer Bug

* Move Shared Font TTFs to AAsset storage + Support external shared font loading from `/data/data/skyline.emu/data/fonts`
* Fix bug in `IApplicationFunctions::PopLaunchParameter` caused by ignoring `LaunchParameterKind`
* Fix bug with Choreographer causing it to be awoken and exit prior to the destruction of `PresentationEngine`
* Fix bug with `IDirectory::Read` where it used `inputBuf` for the output buffer rather than `outputBuf`
* Improve `GetFunctionStackTrace` logs when `dli_sname` or `dli_fname` are missing
* Support more RT Formats
This commit is contained in:
PixelyIon 2021-09-30 20:42:30 +05:30 committed by Billy Laws
parent 95a08627e5
commit f8acc1e131
38 changed files with 228 additions and 155 deletions

View File

@ -50,6 +50,15 @@ android {
debuggable true
minifyEnabled false
shrinkResources false
/* Vulkan Validation Layers */
sourceSets {
main {
jniLibs {
srcDir "$buildDir/generated/vulkan_layers"
}
}
}
}
}
buildFeatures {
@ -71,17 +80,6 @@ android {
}
}
/* Vulkan Validation Layers */
sourceSets {
debug {
main {
jniLibs {
srcDir "$buildDir/generated/vulkan_layers"
}
}
}
}
/* Android Assets */
aaptOptions {
ignoreAssetsPattern "*.md"

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,4 @@
#### Skyline FOSS Shared Fonts: (Credit to [FearlessTobi/yuzu_system_archives](https://github.com/FearlessTobi/yuzu_system_archives) for font choice)
* [FontStandard](FontStandard.ttf), [FontKorean](FontKorean.ttf), [FontChineseSimplified](FontChineseSimplified.ttf) and [FontChineseTraditional](FontChineseTraditional.ttf) are using [Open Sans Regular](https://fonts.google.com/specimen/Open+Sans), which is licensed under [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0)
* [FontNintendoExtended](FontNintendoExtended.ttf) is using [Roboto](https://fonts.google.com/specimen/Roboto), which is licensed under [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0)
* [FontExtendedChineseSimplified](FontExtendedChineseSimplified.ttf) is using [Source Sans Pro](https://fonts.google.com/specimen/Source+Sans+Pro), which is licensed under [Open Font License](https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL)

View File

@ -425,9 +425,9 @@ namespace skyline {
return std::string_view(reinterpret_cast<const char *>(span::data()), nullTerminated ? (std::find(span::begin(), span::end(), 0) - span::begin()) : span::size_bytes());
}
template<typename Out, size_t OutExtent = std::dynamic_extent>
template<typename Out, size_t OutExtent = std::dynamic_extent, bool SkipAlignmentCheck = false>
constexpr span<Out> cast() {
if (util::IsAligned(span::size_bytes(), sizeof(Out)))
if (SkipAlignmentCheck || util::IsAligned(span::size_bytes(), sizeof(Out)))
return span<Out, OutExtent>(reinterpret_cast<Out *>(span::data()), span::size_bytes() / sizeof(Out));
throw exception("Span size not aligned with Out type size (0x{:X}/0x{:X})", span::size_bytes(), sizeof(Out));
}

View File

@ -6,29 +6,29 @@
/**
* @brief A case statement for an enumerant value to use alongside ENUM_STRING
*/
#define ENUM_CASE(key) \
case ENUM_TYPE::key: \
#define ENUM_CASE(key) \
case ENUM_TYPE::key: \
return #key
/**
* @brief Creates a function to convert an enumerant to its string representation at runtime
* @example ENUM_STRING(Example, { ENUM_CASE(A); ENUM_CASE(B); })
*/
#define ENUM_STRING(name, cases) \
constexpr const char *ToString(name value) { \
using ENUM_TYPE = name; \
switch (value) { \
cases \
default: \
return "Unknown"; \
} \
#define ENUM_STRING(name, cases) \
constexpr const char *ToString(name value) { \
using ENUM_TYPE = name; \
switch (value) { \
cases \
default: \
return "Unknown"; \
} \
}
/**
* @brief A case statement for an enumerant value to use alongside ENUM_SWITCH
*/
#define ENUM_CASE_PAIR(key, value) \
case ENUM_TYPE::key: \
#define ENUM_CASE_PAIR(key, value) \
case ENUM_TYPE::key: \
return value
/**

View File

@ -28,7 +28,7 @@ namespace skyline::gpu::interconnect {
nodes.emplace_back(std::in_place_type_t<node::NextSubpassNode>(), function);
}
void CommandExecutor::AddClearSubpass(TextureView attachment, const vk::ClearColorValue &value) {
void CommandExecutor::AddClearColorSubpass(TextureView attachment, const vk::ClearColorValue &value) {
bool newRenderpass{CreateRenderpass(vk::Rect2D{
.extent = attachment.backing->dimensions,
})};

View File

@ -35,7 +35,7 @@ namespace skyline::gpu::interconnect {
* @brief Adds a subpass that clears the entirety of the specified attachment with a value, it may utilize VK_ATTACHMENT_LOAD_OP_CLEAR for a more efficient clear when possible
* @note Any texture supplied to this **must** be locked by the calling thread, it should also undergo no persistent layout transitions till execution
*/
void AddClearSubpass(TextureView attachment, const vk::ClearColorValue& value);
void AddClearColorSubpass(TextureView attachment, const vk::ClearColorValue& value);
/**
* @brief Execute all the nodes and submit the resulting command buffer to the GPU

View File

@ -22,7 +22,7 @@ namespace skyline::gpu::interconnect {
gpu::interconnect::CommandExecutor &executor;
struct RenderTarget {
bool disabled{}; //!< If this RT has been disabled and will be an unbound attachment instead
bool disabled{true}; //!< If this RT has been disabled and will be an unbound attachment instead
union {
u64 gpuAddress;
struct {
@ -90,6 +90,10 @@ namespace skyline::gpu::interconnect {
return {};
case maxwell3d::RenderTarget::ColorFormat::R32B32G32A32Float:
return format::R32B32G32A32Float;
case maxwell3d::RenderTarget::ColorFormat::R16G16B16A16Unorm:
return format::R16G16B16A16Unorm;
case maxwell3d::RenderTarget::ColorFormat::R16G16B16A16Uint:
return format::R16G16B16A16Uint;
case maxwell3d::RenderTarget::ColorFormat::R16G16B16A16Float:
return format::R16G16B16A16Float;
case maxwell3d::RenderTarget::ColorFormat::A2B10G10R10Unorm:
@ -98,6 +102,8 @@ namespace skyline::gpu::interconnect {
return format::R8G8B8A8Unorm;
case maxwell3d::RenderTarget::ColorFormat::A8B8G8R8Srgb:
return format::A8B8G8R8Srgb;
case maxwell3d::RenderTarget::ColorFormat::A8B8G8R8Snorm:
return format::A8B8G8R8Snorm;
case maxwell3d::RenderTarget::ColorFormat::R16G16Snorm:
return format::R16G16Snorm;
case maxwell3d::RenderTarget::ColorFormat::R16G16Float:
@ -106,8 +112,12 @@ namespace skyline::gpu::interconnect {
return format::B10G11R11Float;
case maxwell3d::RenderTarget::ColorFormat::R32Float:
return format::R32Float;
case maxwell3d::RenderTarget::ColorFormat::R8G8Unorm:
return format::R8G8Unorm;
case maxwell3d::RenderTarget::ColorFormat::R8G8Snorm:
return format::R8G8Snorm;
case maxwell3d::RenderTarget::ColorFormat::R16Unorm:
return format::R16Unorm;
case maxwell3d::RenderTarget::ColorFormat::R16Float:
return format::R16Float;
case maxwell3d::RenderTarget::ColorFormat::R8Unorm:
@ -234,8 +244,8 @@ namespace skyline::gpu::interconnect {
if (scissor.extent.width == 0 || scissor.extent.height == 0)
return;
if (scissor.extent.width == renderTarget.backing->dimensions.width && scissor.extent.width == renderTarget.backing->dimensions.width && renderTarget.range.baseArrayLayer == 0 && renderTarget.range.layerCount == 1 && clear.layerId == 0) {
executor.AddClearSubpass(renderTarget, clearColorValue);
if (scissor.extent.width == renderTarget.backing->dimensions.width && scissor.extent.height == renderTarget.backing->dimensions.height && renderTarget.range.baseArrayLayer == 0 && renderTarget.range.layerCount == 1 && clear.layerId == 0) {
executor.AddClearColorSubpass(renderTarget, clearColorValue);
} else {
executor.AddSubpass([aspect, clearColorValue = clearColorValue, layerId = clear.layerId, scissor](vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &, GPU &) {
commandBuffer.clearAttachments(vk::ClearAttachment{

View File

@ -32,8 +32,10 @@ namespace skyline::gpu {
env->DeleteGlobalRef(jSurface);
if (choreographerThread.joinable()) {
if (choreographerLooper)
if (choreographerLooper) {
choreographerStop = true;
ALooper_wake(choreographerLooper);
}
choreographerThread.join();
}
}
@ -62,7 +64,7 @@ namespace skyline::gpu {
signal::SetSignalHandler({SIGINT, SIGILL, SIGTRAP, SIGBUS, SIGFPE, SIGSEGV}, signal::ExceptionalSignalHandler);
choreographerLooper = ALooper_prepare(0);
AChoreographer_postFrameCallback64(AChoreographer_getInstance(), reinterpret_cast<AChoreographer_frameCallback64>(&ChoreographerCallback), this);
ALooper_pollAll(-1, nullptr, nullptr, nullptr); // Will block and process callbacks till ALooper_wake() is called
while (ALooper_pollAll(-1, nullptr, nullptr, nullptr) == ALOOPER_POLL_WAKE && !choreographerStop); // Will block and process callbacks till ALooper_wake() is called with choreographerStop set
} catch (const signal::SignalException &e) {
state.logger->Error("{}\nStack Trace:{}", e.what(), state.loader->GetStackTrace(e.frames));
if (state.process)
@ -275,9 +277,8 @@ namespace skyline::gpu {
// We need to nullify the timestamp if it transitioned from being specified (non-zero) to unspecified (zero)
timestamp = NativeWindowTimestampAuto;
if (timestamp)
if (window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP, timestamp))
throw exception("Setting the buffer timestamp to {} failed with {}", timestamp, result);
if (timestamp && (result = window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP, timestamp)))
throw exception("Setting the buffer timestamp to {} failed with {}", timestamp, result);
if ((result = window->perform(window, NATIVE_WINDOW_GET_NEXT_FRAME_ID, &frameId)))
throw exception("Retrieving the next frame's ID failed with {}", result);

View File

@ -49,6 +49,7 @@ namespace skyline::gpu {
ALooper *choreographerLooper{};
i64 lastChoreographerTime{}; //!< The timestamp of the last invocation of Choreographer::doFrame
i64 refreshCycleDuration{}; //!< The duration of a single refresh cycle for the display in nanoseconds
bool choreographerStop{}; //!< If the Choreographer thread should stop on the next ALooper_wake()
/**
* @url https://developer.android.com/ndk/reference/group/choreographer#achoreographer_postframecallback64

View File

@ -15,17 +15,22 @@ namespace skyline::gpu::format {
constexpr Format R5G6B5Unorm{sizeof(u16), vkf::eR5G6B5UnormPack16};
constexpr Format A2B10G10R10Unorm{sizeof(u32), vkf::eA2B10G10R10UnormPack32};
constexpr Format A8B8G8R8Srgb{sizeof(u32), vkf::eA8B8G8R8SrgbPack32};
constexpr Format A8B8G8R8Snorm{sizeof(u32), vkf::eA8B8G8R8SnormPack32};
constexpr Format R16G16Snorm{sizeof(u32), vkf::eR16G16Snorm};
constexpr Format R16G16Float{sizeof(u32), vkf::eR16G16Sfloat};
constexpr Format B10G11R11Float{sizeof(u32), vkf::eB10G11R11UfloatPack32};
constexpr Format R32Float{sizeof(u32), vkf::eR32Sfloat};
constexpr Format R8G8Unorm{sizeof(u16), vkf::eR8G8Unorm};
constexpr Format R8G8Snorm{sizeof(u16), vkf::eR8G8Snorm};
constexpr Format R16Unorm{sizeof(u16), vkf::eR16Unorm};
constexpr Format R16Float{sizeof(u16), vkf::eR16Sfloat};
constexpr Format R8Unorm{sizeof(u8), vkf::eR8Unorm};
constexpr Format R32B32G32A32Float{sizeof(u32) * 4, vkf::eR32G32B32A32Sfloat, .swizzle = {
.blue = swc::Green,
.green = swc::Blue,
}};
constexpr Format R16G16B16A16Unorm{sizeof(u16) * 4, vkf::eR16G16B16A16Unorm};
constexpr Format R16G16B16A16Uint{sizeof(u16) * 4, vkf::eR16G16B16A16Uint};
constexpr Format R16G16B16A16Float{sizeof(u16) * 4, vkf::eR16G16B16A16Sfloat};
/**
@ -41,6 +46,8 @@ namespace skyline::gpu::format {
return A2B10G10R10Unorm;
case vk::Format::eA8B8G8R8SrgbPack32:
return A8B8G8R8Srgb;
case vk::Format::eA8B8G8R8SnormPack32:
return A8B8G8R8Snorm;
case vk::Format::eR16G16Snorm:
return R16G16Snorm;
case vk::Format::eR16G16Sfloat:
@ -49,12 +56,20 @@ namespace skyline::gpu::format {
return B10G11R11Float;
case vk::Format::eR32Sfloat:
return format::R32Float;
case vk::Format::eR16Unorm:
return R16Unorm;
case vk::Format::eR16Sfloat:
return R16Float;
case vk::Format::eR8G8Unorm:
return R8G8Unorm;
case vk::Format::eR8G8Snorm:
return R8G8Snorm;
case vk::Format::eR8Unorm:
return R8Unorm;
case vk::Format::eR16G16B16A16Unorm:
return R16G16B16A16Unorm;
case vk::Format::eR16G16B16A16Uint:
return R16G16B16A16Uint;
case vk::Format::eR16G16B16A16Sfloat:
return R16G16B16A16Float;
default:

View File

@ -71,11 +71,9 @@ namespace skyline::gpu {
textures.emplace(mappingEnd, TextureMapping{texture, it, guestMapping});
while ((++it) != texture->guest->mappings.end()) {
guestMapping = *it;
mappingEnd = hostMapping = std::upper_bound(textures.begin(), textures.end(), guestMapping);
while (hostMapping != textures.begin() && std::prev(hostMapping)->end() > guestMapping.begin()) {
// TODO: Delete textures not in texture pool
}
textures.emplace(mappingEnd, TextureMapping{texture, it, guestMapping});
auto mapping{std::upper_bound(textures.begin(), textures.end(), guestMapping)};
// TODO: Delete overlapping textures that aren't in texture pool
textures.emplace(mapping, TextureMapping{texture, it, guestMapping});
}
return TextureView(texture, static_cast<vk::ImageViewType>(guestTexture.type), vk::ImageSubresourceRange{

View File

@ -92,7 +92,14 @@ namespace skyline::loader {
size_t length{};
std::unique_ptr<char, decltype(&std::free)> demangled{abi::__cxa_demangle(info.dli_sname, nullptr, &length, &status), std::free};
return fmt::format("\n* 0x{:X} ({} from {})", reinterpret_cast<uintptr_t>(pointer), (status == 0) ? std::string_view(demangled.get()) : info.dli_sname ? info.dli_sname : "Unresolved", info.dli_fname ? info.dli_fname : "Unresolved");
if (info.dli_sname && info.dli_fname)
return fmt::format("\n* 0x{:X} ({} from {})", reinterpret_cast<uintptr_t>(pointer), (status == 0) ? std::string_view(demangled.get()) : info.dli_sname, info.dli_fname);
else if (info.dli_sname)
return fmt::format("\n* 0x{:X} ({})", reinterpret_cast<uintptr_t>(pointer), (status == 0) ? std::string_view(demangled.get()) : info.dli_sname);
else if (info.dli_fname)
return fmt::format("\n* 0x{:X} (from {})", reinterpret_cast<uintptr_t>(pointer), info.dli_fname);
else
return fmt::format("\n* 0x{:X}", reinterpret_cast<uintptr_t>(pointer));
} else {
return fmt::format("\n* 0x{:X}", reinterpret_cast<uintptr_t>(pointer));
}

View File

@ -17,11 +17,33 @@ namespace skyline::service::am {
constexpr u32 LaunchParameterMagic{0xC79497CA}; //!< The magic of the application launch parameters
constexpr size_t LaunchParameterSize{0x88}; //!< The size of the launch parameter IStorage
auto storageService{std::make_shared<IStorage>(state, manager, LaunchParameterSize)};
enum class LaunchParameterKind : u32 {
UserChannel = 1,
PreselectedUser = 2,
Unknown = 3,
} launchParameterKind{request.Pop<LaunchParameterKind>()};
storageService->Push<u32>(LaunchParameterMagic);
storageService->Push<u32>(1);
storageService->Push(constant::DefaultUserId);
std::shared_ptr<IStorage> storageService;
switch (launchParameterKind) {
case LaunchParameterKind::UserChannel:
return result::NotAvailable;
case LaunchParameterKind::PreselectedUser: {
storageService = std::make_shared<IStorage>(state, manager, LaunchParameterSize);
storageService->Push<u32>(LaunchParameterMagic);
storageService->Push<u32>(1);
storageService->Push(constant::DefaultUserId);
break;
}
case LaunchParameterKind::Unknown:
throw exception("Popping 'Unknown' Launch Parameter: {}", static_cast<u32>(launchParameterKind));
default:
return result::InvalidInput;
}
manager.RegisterService(storageService, session, response);
return {};

View File

@ -8,6 +8,8 @@
namespace skyline::service::am {
namespace result {
constexpr Result NotAvailable(128, 2);
constexpr Result InvalidInput(128, 500);
constexpr Result InvalidParameters(128, 506);
}

View File

@ -5,7 +5,7 @@
#include "IStorage.h"
namespace skyline::service::am {
IStorage::IStorage(const DeviceState &state, ServiceManager &manager, size_t size) : content(size), BaseService(state, manager) {}
IStorage::IStorage(const DeviceState &state, ServiceManager &manager, size_t size) : content(size, 0), BaseService(state, manager) {}
Result IStorage::Open(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
manager.RegisterService(std::make_shared<IStorageAccessor>(state, manager, shared_from_this()), session, response);

View File

@ -25,7 +25,7 @@ namespace skyline::service::fssrv {
Result IDirectory::Read(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
auto entries{backing->Read()};
auto outputEntries{request.inputBuf.at(0).cast<DirectoryEntry>()};
auto outputEntries{request.outputBuf.at(0).cast<DirectoryEntry, std::dynamic_extent, true>()};
size_t i{};
for (; i < std::min(entries.size(), outputEntries.size()); i++) {

View File

@ -1,48 +1,11 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
#include <kernel/types/KProcess.h>
#include "resources/FontChineseSimplified.ttf.h"
#include "resources/FontChineseTraditional.ttf.h"
#include "resources/FontExtendedChineseSimplified.ttf.h"
#include "resources/FontKorean.ttf.h"
#include "resources/FontNintendoExtended.ttf.h"
#include "resources/FontStandard.ttf.h"
#include "IPlatformServiceManager.h"
#include "shared_font_core.h"
namespace skyline::service::pl {
struct FontEntry {
u8 *data; //!< The font TTF data
size_t length; //!< The length of the font TTF data
size_t offset; //!< The offset of the font in shared memory
};
std::array<FontEntry, 6> fontTable{
{
{FontChineseSimplified, FontExtendedChineseSimplifiedLength},
{FontChineseTraditional, FontChineseTraditionalLength},
{FontExtendedChineseSimplified, FontExtendedChineseSimplifiedLength},
{FontKorean, FontKoreanLength},
{FontNintendoExtended, FontNintendoExtendedLength},
{FontStandard, FontStandardLength}
}
};
IPlatformServiceManager::IPlatformServiceManager(const DeviceState &state, ServiceManager &manager) : fontSharedMem(std::make_shared<kernel::type::KSharedMemory>(state, constant::FontSharedMemSize)), BaseService(state, manager) {
constexpr u32 SharedFontResult{0x7F9A0218}; //!< The decrypted magic for a single font in the shared font data
constexpr u32 SharedFontMagic{0x36F81A1E}; //!< The encrypted magic for a single font in the shared font data
constexpr u32 SharedFontKey{SharedFontMagic ^ SharedFontResult}; //!< The XOR key for encrypting the font size
auto ptr{reinterpret_cast<u32 *>(fontSharedMem->host.ptr)};
for (auto &font : fontTable) {
*ptr++ = SharedFontResult;
*ptr++ = font.length ^ SharedFontKey;
font.offset = reinterpret_cast<u64>(ptr) - reinterpret_cast<u64>(fontSharedMem->host.ptr);
std::memcpy(ptr, font.data, font.length);
ptr = reinterpret_cast<u32 *>(reinterpret_cast<u8 *>(ptr) + font.length);
}
}
IPlatformServiceManager::IPlatformServiceManager(const DeviceState &state, ServiceManager &manager, SharedFontCore &core) : BaseService(state, manager), core(core) {}
Result IPlatformServiceManager::GetLoadState(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
constexpr u32 FontLoaded{1}; //!< "All fonts have been loaded into memory"
@ -52,18 +15,18 @@ namespace skyline::service::pl {
Result IPlatformServiceManager::GetSize(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
auto fontId{request.Pop<u32>()};
response.Push<u32>(fontTable.at(fontId).length);
response.Push<u32>(core.fonts.at(fontId).length);
return {};
}
Result IPlatformServiceManager::GetSharedMemoryAddressOffset(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
auto fontId{request.Pop<u32>()};
response.Push<u32>(fontTable.at(fontId).offset);
response.Push<u32>(core.fonts.at(fontId).offset);
return {};
}
Result IPlatformServiceManager::GetSharedMemoryNativeHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
auto handle{state.process->InsertItem<type::KSharedMemory>(fontSharedMem)};
auto handle{state.process->InsertItem<type::KSharedMemory>(core.sharedFontMemory)};
response.copyHandles.push_back(handle);
return {};
}

View File

@ -6,53 +6,49 @@
#include <kernel/types/KSharedMemory.h>
#include <services/serviceman.h>
namespace skyline {
namespace constant {
constexpr u32 FontSharedMemSize{0x1100000}; //!< The total size of the font shared memory
}
namespace skyline::service::pl {
struct SharedFontCore;
/**
* @brief IPlatformServiceManager is used to access shared fonts
* @url https://switchbrew.org/wiki/Shared_Database_services#pl:u.2C_pl:s
*/
class IPlatformServiceManager : public BaseService {
private:
SharedFontCore &core;
public:
IPlatformServiceManager(const DeviceState &state, ServiceManager &manager, SharedFontCore &core);
namespace service::pl {
/**
* @brief IPlatformServiceManager is used to access shared fonts
* @url https://switchbrew.org/wiki/Shared_Database_services#pl:u.2C_pl:s
* @brief Returns the loading state of the requested font
* @url https://switchbrew.org/wiki/Shared_Database_services#GetLoadState
*/
class IPlatformServiceManager : public BaseService {
private:
std::shared_ptr<kernel::type::KSharedMemory> fontSharedMem; //!< The KSharedMemory that stores the TTF data of all shared fonts
Result GetLoadState(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
public:
IPlatformServiceManager(const DeviceState &state, ServiceManager &manager);
/**
* @brief Returns the size of the requested font
* @url https://switchbrew.org/wiki/Shared_Database_services#GetSize
*/
Result GetSize(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
/**
* @brief Returns the loading state of the requested font
* @url https://switchbrew.org/wiki/Shared_Database_services#GetLoadState
*/
Result GetLoadState(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
/**
* @brief Returns the offset in shared memory of the requested font
* @url https://switchbrew.org/wiki/Shared_Database_services#GetSharedMemoryAddressOffset
*/
Result GetSharedMemoryAddressOffset(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
/**
* @brief Returns the size of the requested font
* @url https://switchbrew.org/wiki/Shared_Database_services#GetSize
*/
Result GetSize(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
/**
* @brief Returns a handle to the whole font shared memory
* @url https://switchbrew.org/wiki/Shared_Database_services#GetSharedMemoryNativeHandle
*/
Result GetSharedMemoryNativeHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
/**
* @brief Returns the offset in shared memory of the requested font
* @url https://switchbrew.org/wiki/Shared_Database_services#GetSharedMemoryAddressOffset
*/
Result GetSharedMemoryAddressOffset(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
/**
* @brief Returns a handle to the whole font shared memory
* @url https://switchbrew.org/wiki/Shared_Database_services#GetSharedMemoryNativeHandle
*/
Result GetSharedMemoryNativeHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
SERVICE_DECL(
SFUNC(0x1, IPlatformServiceManager, GetLoadState),
SFUNC(0x2, IPlatformServiceManager, GetSize),
SFUNC(0x3, IPlatformServiceManager, GetSharedMemoryAddressOffset),
SFUNC(0x4, IPlatformServiceManager, GetSharedMemoryNativeHandle)
)
};
}
SERVICE_DECL(
SFUNC(0x1, IPlatformServiceManager, GetLoadState),
SFUNC(0x2, IPlatformServiceManager, GetSize),
SFUNC(0x3, IPlatformServiceManager, GetSharedMemoryAddressOffset),
SFUNC(0x4, IPlatformServiceManager, GetSharedMemoryNativeHandle)
)
};
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,4 +0,0 @@
#### Skyline FOSS Shared Fonts: (Credit to [FearlessTobi/yuzu_system_archives](https://github.com/FearlessTobi/yuzu_system_archives) for font choice)
* [FontStandard](FontStandard.ttf.h), [FontKorean](FontKorean.ttf.h), [FontChineseSimplified](FontChineseSimplified.ttf.h) and [FontChineseTraditional](FontChineseTraditional.ttf.h) are using [Open Sans Regular](https://fonts.google.com/specimen/Open+Sans), which is licensed under [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0)
* [FontNintendoExtended](FontNintendoExtended.ttf.h) is using [Roboto](https://fonts.google.com/specimen/Roboto), which is licensed under [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0)
* [FontExtendedChineseSimplified](FontExtendedChineseSimplified.ttf.h) is using [Source Sans Pro](https://fonts.google.com/specimen/Source+Sans+Pro), which is licensed under [Open Font License](https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL)

View File

@ -0,0 +1,59 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
#pragma once
#include <os.h>
#include <kernel/types/KProcess.h>
#include <vfs/os_filesystem.h>
namespace skyline::service::pl {
/**
* @brief A persistent object for managing the shared memory utilized by shared fonts
*/
struct SharedFontCore {
static constexpr u32 FontSharedMemSize{0x1100000}; //!< The total size of the font shared memory
std::shared_ptr<kernel::type::KSharedMemory> sharedFontMemory; //!< The KSharedMemory that stores the TTF data of all shared fonts
struct FontEntry {
std::string path; //!< The path of the font asset
size_t length; //!< The length of the font TTF data
size_t offset; //!< The offset of the font in shared memory
};
std::array<FontEntry, 6> fonts{
{
{"FontChineseSimplified.ttf"},
{"FontChineseTraditional.ttf"},
{"FontExtendedChineseSimplified.ttf"},
{"FontKorean.ttf"},
{"FontNintendoExtended.ttf"},
{"FontStandard.ttf"},
}
};
SharedFontCore(const DeviceState &state) : sharedFontMemory(std::make_shared<kernel::type::KSharedMemory>(state, FontSharedMemSize)) {
constexpr u32 SharedFontResult{0x7F9A0218}; //!< The decrypted magic for a single font in the shared font data
constexpr u32 SharedFontMagic{0x36F81A1E}; //!< The encrypted magic for a single font in the shared font data
constexpr u32 SharedFontKey{SharedFontMagic ^ SharedFontResult}; //!< The XOR key for encrypting the font size
auto fontsDirectory{std::make_shared<vfs::OsFileSystem>(state.os->appFilesPath + "fonts/")};
auto ptr{reinterpret_cast<u32 *>(sharedFontMemory->host.ptr)};
for (auto &font : fonts) {
*ptr++ = 0x18029a7f;
*ptr++ = util::SwapEndianness(font.length ^ 0x49621806);
font.offset = reinterpret_cast<u64>(ptr) - reinterpret_cast<u64>(sharedFontMemory->host.ptr);
std::shared_ptr<vfs::Backing> fontFile;
if (fontsDirectory->FileExists(font.path))
fontFile = fontsDirectory->OpenFile(font.path);
else
fontFile = state.os->assetFileSystem->OpenFile("fonts/" + font.path);
font.length = fontFile->size;
fontFile->Read(span<u8>(reinterpret_cast<u8 *>(ptr), font.length));
ptr = reinterpret_cast<u32 *>(reinterpret_cast<u8 *>(ptr) + font.length);
}
}
};
}

View File

@ -25,6 +25,7 @@
#include "visrv/ISystemRootService.h"
#include "visrv/IManagerRootService.h"
#include "pl/IPlatformServiceManager.h"
#include "pl/shared_font_core.h"
#include "aocsrv/IAddOnContentManager.h"
#include "pctl/IParentalControlServiceFactory.h"
#include "lm/ILogService.h"
@ -49,9 +50,10 @@
namespace skyline::service {
struct GlobalServiceState {
timesrv::core::TimeServiceObject timesrv;
pl::SharedFontCore sharedFontCore;
nvdrv::Driver nvdrv;
explicit GlobalServiceState(const DeviceState &state) : timesrv(state), nvdrv(state) {}
explicit GlobalServiceState(const DeviceState &state) : timesrv(state), sharedFontCore(state), nvdrv(state) {}
};
ServiceManager::ServiceManager(const DeviceState &state) : state(state), smUserInterface(std::make_shared<sm::IUserInterface>(state, *this)), globalServiceState(std::make_shared<GlobalServiceState>(state)) {}
@ -83,7 +85,7 @@ namespace skyline::service {
SERVICE_CASE(visrv::IApplicationRootService, "vi:u")
SERVICE_CASE(visrv::ISystemRootService, "vi:s")
SERVICE_CASE(visrv::IManagerRootService, "vi:m")
SERVICE_CASE(pl::IPlatformServiceManager, "pl:u")
SERVICE_CASE(pl::IPlatformServiceManager, "pl:u", globalServiceState->sharedFontCore)
SERVICE_CASE(aocsrv::IAddOnContentManager, "aoc:u")
SERVICE_CASE(pctl::IParentalControlServiceFactory, "pctl")
SERVICE_CASE(pctl::IParentalControlServiceFactory, "pctl:a")

View File

@ -43,15 +43,20 @@ namespace skyline::soc::gm20b::engine::maxwell3d::type {
enum class ColorFormat : u32 {
None = 0x0,
R32B32G32A32Float = 0xC0,
R16G16B16A16Unorm = 0xC6,
R16G16B16A16Uint = 0xC9,
R16G16B16A16Float = 0xCA,
A2B10G10R10Unorm = 0xD1,
R8G8B8A8Unorm = 0xD5,
A8B8G8R8Srgb = 0xD6,
A8B8G8R8Snorm = 0xD7,
R16G16Snorm = 0xDB,
R16G16Float = 0xDE,
B10G11R11Float = 0xE0,
R32Float = 0xE5,
R8G8Unorm = 0xEA,
R8G8Snorm = 0xEB,
R16Unorm = 0xEE,
R16Float = 0xF2,
R8Unorm = 0xF3,
} format;

View File

@ -6,7 +6,7 @@
#include <soc.h>
namespace skyline::soc::gm20b::engine::maxwell3d {
Maxwell3D::Maxwell3D(const DeviceState &state, GMMU &gmmu, gpu::interconnect::CommandExecutor& executor) : Engine(state), macroInterpreter(*this), context(*state.gpu, gmmu, executor) {
Maxwell3D::Maxwell3D(const DeviceState &state, GMMU &gmmu, gpu::interconnect::CommandExecutor &executor) : Engine(state), macroInterpreter(*this), context(*state.gpu, gmmu, executor) {
ResetRegs();
}

View File

@ -95,7 +95,13 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
u32 compareMask; // 0x3D7
} stencilBackExtra;
u32 _pad7_[0x13]; // 0x3D8
u32 tiledCacheEnable; // 0x3D8
struct {
u16 width;
u16 height;
} tiledCacheSize; // 0x3D9
u32 _pad7_[0x11]; // 0x3DA
u32 rtSeparateFragData; // 0x3EB
u32 _pad8_[0x6C]; // 0x3EC
std::array<type::VertexAttribute, 0x20> vertexAttributeState; // 0x458
@ -241,7 +247,7 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
std::array<u32, 0x2000> macroCode{}; //!< Stores GPU macros, writes to it will wraparound on overflow
Maxwell3D(const DeviceState &state, GMMU &gmmu, gpu::interconnect::CommandExecutor& executor);
Maxwell3D(const DeviceState &state, GMMU &gmmu, gpu::interconnect::CommandExecutor &executor);
/**
* @brief Resets the Maxwell 3D registers to their default values

View File

@ -35,7 +35,7 @@ namespace skyline::vfs {
} nacpContents{};
static_assert(sizeof(NacpData) == 0x4000);
u32 supportedTitleLanguages{}; //<! A bitmask containing the available title entry languages and game icons
u32 supportedTitleLanguages{}; //!< A bitmask containing the available title entry languages and game icons
NACP(const std::shared_ptr<vfs::Backing> &backing);

View File

@ -9,7 +9,7 @@
#include "os_filesystem.h"
namespace skyline::vfs {
OsFileSystem::OsFileSystem(const std::string &basePath) : FileSystem(), basePath(basePath) {
OsFileSystem::OsFileSystem(const std::string &basePath) : FileSystem(), basePath(basePath.ends_with('/') ? basePath : basePath + '/') {
if (!DirectoryExists(basePath))
if (!CreateDirectory(basePath, true))
throw exception("Error creating the OS filesystem backing directory");