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 debuggable true
minifyEnabled false minifyEnabled false
shrinkResources false shrinkResources false
/* Vulkan Validation Layers */
sourceSets {
main {
jniLibs {
srcDir "$buildDir/generated/vulkan_layers"
}
}
}
} }
} }
buildFeatures { buildFeatures {
@ -71,17 +80,6 @@ android {
} }
} }
/* Vulkan Validation Layers */
sourceSets {
debug {
main {
jniLibs {
srcDir "$buildDir/generated/vulkan_layers"
}
}
}
}
/* Android Assets */ /* Android Assets */
aaptOptions { aaptOptions {
ignoreAssetsPattern "*.md" 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()); 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() { 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)); 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)); throw exception("Span size not aligned with Out type size (0x{:X}/0x{:X})", span::size_bytes(), sizeof(Out));
} }

View File

@ -28,7 +28,7 @@ namespace skyline::gpu::interconnect {
nodes.emplace_back(std::in_place_type_t<node::NextSubpassNode>(), function); 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{ bool newRenderpass{CreateRenderpass(vk::Rect2D{
.extent = attachment.backing->dimensions, .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 * @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 * @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 * @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; gpu::interconnect::CommandExecutor &executor;
struct RenderTarget { 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 { union {
u64 gpuAddress; u64 gpuAddress;
struct { struct {
@ -90,6 +90,10 @@ namespace skyline::gpu::interconnect {
return {}; return {};
case maxwell3d::RenderTarget::ColorFormat::R32B32G32A32Float: case maxwell3d::RenderTarget::ColorFormat::R32B32G32A32Float:
return format::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: case maxwell3d::RenderTarget::ColorFormat::R16G16B16A16Float:
return format::R16G16B16A16Float; return format::R16G16B16A16Float;
case maxwell3d::RenderTarget::ColorFormat::A2B10G10R10Unorm: case maxwell3d::RenderTarget::ColorFormat::A2B10G10R10Unorm:
@ -98,6 +102,8 @@ namespace skyline::gpu::interconnect {
return format::R8G8B8A8Unorm; return format::R8G8B8A8Unorm;
case maxwell3d::RenderTarget::ColorFormat::A8B8G8R8Srgb: case maxwell3d::RenderTarget::ColorFormat::A8B8G8R8Srgb:
return format::A8B8G8R8Srgb; return format::A8B8G8R8Srgb;
case maxwell3d::RenderTarget::ColorFormat::A8B8G8R8Snorm:
return format::A8B8G8R8Snorm;
case maxwell3d::RenderTarget::ColorFormat::R16G16Snorm: case maxwell3d::RenderTarget::ColorFormat::R16G16Snorm:
return format::R16G16Snorm; return format::R16G16Snorm;
case maxwell3d::RenderTarget::ColorFormat::R16G16Float: case maxwell3d::RenderTarget::ColorFormat::R16G16Float:
@ -106,8 +112,12 @@ namespace skyline::gpu::interconnect {
return format::B10G11R11Float; return format::B10G11R11Float;
case maxwell3d::RenderTarget::ColorFormat::R32Float: case maxwell3d::RenderTarget::ColorFormat::R32Float:
return format::R32Float; return format::R32Float;
case maxwell3d::RenderTarget::ColorFormat::R8G8Unorm:
return format::R8G8Unorm;
case maxwell3d::RenderTarget::ColorFormat::R8G8Snorm: case maxwell3d::RenderTarget::ColorFormat::R8G8Snorm:
return format::R8G8Snorm; return format::R8G8Snorm;
case maxwell3d::RenderTarget::ColorFormat::R16Unorm:
return format::R16Unorm;
case maxwell3d::RenderTarget::ColorFormat::R16Float: case maxwell3d::RenderTarget::ColorFormat::R16Float:
return format::R16Float; return format::R16Float;
case maxwell3d::RenderTarget::ColorFormat::R8Unorm: case maxwell3d::RenderTarget::ColorFormat::R8Unorm:
@ -234,8 +244,8 @@ namespace skyline::gpu::interconnect {
if (scissor.extent.width == 0 || scissor.extent.height == 0) if (scissor.extent.width == 0 || scissor.extent.height == 0)
return; 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) { 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.AddClearSubpass(renderTarget, clearColorValue); executor.AddClearColorSubpass(renderTarget, clearColorValue);
} else { } else {
executor.AddSubpass([aspect, clearColorValue = clearColorValue, layerId = clear.layerId, scissor](vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &, GPU &) { executor.AddSubpass([aspect, clearColorValue = clearColorValue, layerId = clear.layerId, scissor](vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &, GPU &) {
commandBuffer.clearAttachments(vk::ClearAttachment{ commandBuffer.clearAttachments(vk::ClearAttachment{

View File

@ -32,8 +32,10 @@ namespace skyline::gpu {
env->DeleteGlobalRef(jSurface); env->DeleteGlobalRef(jSurface);
if (choreographerThread.joinable()) { if (choreographerThread.joinable()) {
if (choreographerLooper) if (choreographerLooper) {
choreographerStop = true;
ALooper_wake(choreographerLooper); ALooper_wake(choreographerLooper);
}
choreographerThread.join(); choreographerThread.join();
} }
} }
@ -62,7 +64,7 @@ namespace skyline::gpu {
signal::SetSignalHandler({SIGINT, SIGILL, SIGTRAP, SIGBUS, SIGFPE, SIGSEGV}, signal::ExceptionalSignalHandler); signal::SetSignalHandler({SIGINT, SIGILL, SIGTRAP, SIGBUS, SIGFPE, SIGSEGV}, signal::ExceptionalSignalHandler);
choreographerLooper = ALooper_prepare(0); choreographerLooper = ALooper_prepare(0);
AChoreographer_postFrameCallback64(AChoreographer_getInstance(), reinterpret_cast<AChoreographer_frameCallback64>(&ChoreographerCallback), this); 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) { } catch (const signal::SignalException &e) {
state.logger->Error("{}\nStack Trace:{}", e.what(), state.loader->GetStackTrace(e.frames)); state.logger->Error("{}\nStack Trace:{}", e.what(), state.loader->GetStackTrace(e.frames));
if (state.process) if (state.process)
@ -275,8 +277,7 @@ namespace skyline::gpu {
// We need to nullify the timestamp if it transitioned from being specified (non-zero) to unspecified (zero) // We need to nullify the timestamp if it transitioned from being specified (non-zero) to unspecified (zero)
timestamp = NativeWindowTimestampAuto; timestamp = NativeWindowTimestampAuto;
if (timestamp) if (timestamp && (result = window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP, timestamp)))
if (window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP, timestamp))
throw exception("Setting the buffer timestamp to {} failed with {}", timestamp, result); throw exception("Setting the buffer timestamp to {} failed with {}", timestamp, result);
if ((result = window->perform(window, NATIVE_WINDOW_GET_NEXT_FRAME_ID, &frameId))) if ((result = window->perform(window, NATIVE_WINDOW_GET_NEXT_FRAME_ID, &frameId)))

View File

@ -49,6 +49,7 @@ namespace skyline::gpu {
ALooper *choreographerLooper{}; ALooper *choreographerLooper{};
i64 lastChoreographerTime{}; //!< The timestamp of the last invocation of Choreographer::doFrame 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 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 * @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 R5G6B5Unorm{sizeof(u16), vkf::eR5G6B5UnormPack16};
constexpr Format A2B10G10R10Unorm{sizeof(u32), vkf::eA2B10G10R10UnormPack32}; constexpr Format A2B10G10R10Unorm{sizeof(u32), vkf::eA2B10G10R10UnormPack32};
constexpr Format A8B8G8R8Srgb{sizeof(u32), vkf::eA8B8G8R8SrgbPack32}; constexpr Format A8B8G8R8Srgb{sizeof(u32), vkf::eA8B8G8R8SrgbPack32};
constexpr Format A8B8G8R8Snorm{sizeof(u32), vkf::eA8B8G8R8SnormPack32};
constexpr Format R16G16Snorm{sizeof(u32), vkf::eR16G16Snorm}; constexpr Format R16G16Snorm{sizeof(u32), vkf::eR16G16Snorm};
constexpr Format R16G16Float{sizeof(u32), vkf::eR16G16Sfloat}; constexpr Format R16G16Float{sizeof(u32), vkf::eR16G16Sfloat};
constexpr Format B10G11R11Float{sizeof(u32), vkf::eB10G11R11UfloatPack32}; constexpr Format B10G11R11Float{sizeof(u32), vkf::eB10G11R11UfloatPack32};
constexpr Format R32Float{sizeof(u32), vkf::eR32Sfloat}; constexpr Format R32Float{sizeof(u32), vkf::eR32Sfloat};
constexpr Format R8G8Unorm{sizeof(u16), vkf::eR8G8Unorm};
constexpr Format R8G8Snorm{sizeof(u16), vkf::eR8G8Snorm}; constexpr Format R8G8Snorm{sizeof(u16), vkf::eR8G8Snorm};
constexpr Format R16Unorm{sizeof(u16), vkf::eR16Unorm};
constexpr Format R16Float{sizeof(u16), vkf::eR16Sfloat}; constexpr Format R16Float{sizeof(u16), vkf::eR16Sfloat};
constexpr Format R8Unorm{sizeof(u8), vkf::eR8Unorm}; constexpr Format R8Unorm{sizeof(u8), vkf::eR8Unorm};
constexpr Format R32B32G32A32Float{sizeof(u32) * 4, vkf::eR32G32B32A32Sfloat, .swizzle = { constexpr Format R32B32G32A32Float{sizeof(u32) * 4, vkf::eR32G32B32A32Sfloat, .swizzle = {
.blue = swc::Green, .blue = swc::Green,
.green = swc::Blue, .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}; constexpr Format R16G16B16A16Float{sizeof(u16) * 4, vkf::eR16G16B16A16Sfloat};
/** /**
@ -41,6 +46,8 @@ namespace skyline::gpu::format {
return A2B10G10R10Unorm; return A2B10G10R10Unorm;
case vk::Format::eA8B8G8R8SrgbPack32: case vk::Format::eA8B8G8R8SrgbPack32:
return A8B8G8R8Srgb; return A8B8G8R8Srgb;
case vk::Format::eA8B8G8R8SnormPack32:
return A8B8G8R8Snorm;
case vk::Format::eR16G16Snorm: case vk::Format::eR16G16Snorm:
return R16G16Snorm; return R16G16Snorm;
case vk::Format::eR16G16Sfloat: case vk::Format::eR16G16Sfloat:
@ -49,12 +56,20 @@ namespace skyline::gpu::format {
return B10G11R11Float; return B10G11R11Float;
case vk::Format::eR32Sfloat: case vk::Format::eR32Sfloat:
return format::R32Float; return format::R32Float;
case vk::Format::eR16Unorm:
return R16Unorm;
case vk::Format::eR16Sfloat: case vk::Format::eR16Sfloat:
return R16Float; return R16Float;
case vk::Format::eR8G8Unorm:
return R8G8Unorm;
case vk::Format::eR8G8Snorm: case vk::Format::eR8G8Snorm:
return R8G8Snorm; return R8G8Snorm;
case vk::Format::eR8Unorm: case vk::Format::eR8Unorm:
return R8Unorm; return R8Unorm;
case vk::Format::eR16G16B16A16Unorm:
return R16G16B16A16Unorm;
case vk::Format::eR16G16B16A16Uint:
return R16G16B16A16Uint;
case vk::Format::eR16G16B16A16Sfloat: case vk::Format::eR16G16B16A16Sfloat:
return R16G16B16A16Float; return R16G16B16A16Float;
default: default:

View File

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

View File

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

View File

@ -17,12 +17,34 @@ namespace skyline::service::am {
constexpr u32 LaunchParameterMagic{0xC79497CA}; //!< The magic of the application launch parameters constexpr u32 LaunchParameterMagic{0xC79497CA}; //!< The magic of the application launch parameters
constexpr size_t LaunchParameterSize{0x88}; //!< The size of the launch parameter IStorage 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>()};
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>(LaunchParameterMagic);
storageService->Push<u32>(1); storageService->Push<u32>(1);
storageService->Push(constant::DefaultUserId); 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); manager.RegisterService(storageService, session, response);
return {}; return {};
} }

View File

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

View File

@ -5,7 +5,7 @@
#include "IStorage.h" #include "IStorage.h"
namespace skyline::service::am { 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) { 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); 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) { Result IDirectory::Read(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
auto entries{backing->Read()}; 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{}; size_t i{};
for (; i < std::min(entries.size(), outputEntries.size()); i++) { for (; i < std::min(entries.size(), outputEntries.size()); i++) {

View File

@ -1,48 +1,11 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) // 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 "IPlatformServiceManager.h"
#include "shared_font_core.h"
namespace skyline::service::pl { namespace skyline::service::pl {
struct FontEntry { IPlatformServiceManager::IPlatformServiceManager(const DeviceState &state, ServiceManager &manager, SharedFontCore &core) : BaseService(state, manager), core(core) {}
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);
}
}
Result IPlatformServiceManager::GetLoadState(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { Result IPlatformServiceManager::GetLoadState(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
constexpr u32 FontLoaded{1}; //!< "All fonts have been loaded into memory" 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) { Result IPlatformServiceManager::GetSize(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
auto fontId{request.Pop<u32>()}; auto fontId{request.Pop<u32>()};
response.Push<u32>(fontTable.at(fontId).length); response.Push<u32>(core.fonts.at(fontId).length);
return {}; return {};
} }
Result IPlatformServiceManager::GetSharedMemoryAddressOffset(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { Result IPlatformServiceManager::GetSharedMemoryAddressOffset(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
auto fontId{request.Pop<u32>()}; auto fontId{request.Pop<u32>()};
response.Push<u32>(fontTable.at(fontId).offset); response.Push<u32>(core.fonts.at(fontId).offset);
return {}; return {};
} }
Result IPlatformServiceManager::GetSharedMemoryNativeHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { 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); response.copyHandles.push_back(handle);
return {}; return {};
} }

View File

@ -6,22 +6,19 @@
#include <kernel/types/KSharedMemory.h> #include <kernel/types/KSharedMemory.h>
#include <services/serviceman.h> #include <services/serviceman.h>
namespace skyline { namespace skyline::service::pl {
namespace constant { struct SharedFontCore;
constexpr u32 FontSharedMemSize{0x1100000}; //!< The total size of the font shared memory
}
namespace service::pl {
/** /**
* @brief IPlatformServiceManager is used to access shared fonts * @brief IPlatformServiceManager is used to access shared fonts
* @url https://switchbrew.org/wiki/Shared_Database_services#pl:u.2C_pl:s * @url https://switchbrew.org/wiki/Shared_Database_services#pl:u.2C_pl:s
*/ */
class IPlatformServiceManager : public BaseService { class IPlatformServiceManager : public BaseService {
private: private:
std::shared_ptr<kernel::type::KSharedMemory> fontSharedMem; //!< The KSharedMemory that stores the TTF data of all shared fonts SharedFontCore &core;
public: public:
IPlatformServiceManager(const DeviceState &state, ServiceManager &manager); IPlatformServiceManager(const DeviceState &state, ServiceManager &manager, SharedFontCore &core);
/** /**
* @brief Returns the loading state of the requested font * @brief Returns the loading state of the requested font
@ -55,4 +52,3 @@ namespace skyline {
) )
}; };
} }
}

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/ISystemRootService.h"
#include "visrv/IManagerRootService.h" #include "visrv/IManagerRootService.h"
#include "pl/IPlatformServiceManager.h" #include "pl/IPlatformServiceManager.h"
#include "pl/shared_font_core.h"
#include "aocsrv/IAddOnContentManager.h" #include "aocsrv/IAddOnContentManager.h"
#include "pctl/IParentalControlServiceFactory.h" #include "pctl/IParentalControlServiceFactory.h"
#include "lm/ILogService.h" #include "lm/ILogService.h"
@ -49,9 +50,10 @@
namespace skyline::service { namespace skyline::service {
struct GlobalServiceState { struct GlobalServiceState {
timesrv::core::TimeServiceObject timesrv; timesrv::core::TimeServiceObject timesrv;
pl::SharedFontCore sharedFontCore;
nvdrv::Driver nvdrv; 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)) {} 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::IApplicationRootService, "vi:u")
SERVICE_CASE(visrv::ISystemRootService, "vi:s") SERVICE_CASE(visrv::ISystemRootService, "vi:s")
SERVICE_CASE(visrv::IManagerRootService, "vi:m") 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(aocsrv::IAddOnContentManager, "aoc:u")
SERVICE_CASE(pctl::IParentalControlServiceFactory, "pctl") SERVICE_CASE(pctl::IParentalControlServiceFactory, "pctl")
SERVICE_CASE(pctl::IParentalControlServiceFactory, "pctl:a") SERVICE_CASE(pctl::IParentalControlServiceFactory, "pctl:a")

View File

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

View File

@ -95,7 +95,13 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
u32 compareMask; // 0x3D7 u32 compareMask; // 0x3D7
} stencilBackExtra; } stencilBackExtra;
u32 _pad7_[0x13]; // 0x3D8 u32 tiledCacheEnable; // 0x3D8
struct {
u16 width;
u16 height;
} tiledCacheSize; // 0x3D9
u32 _pad7_[0x11]; // 0x3DA
u32 rtSeparateFragData; // 0x3EB u32 rtSeparateFragData; // 0x3EB
u32 _pad8_[0x6C]; // 0x3EC u32 _pad8_[0x6C]; // 0x3EC
std::array<type::VertexAttribute, 0x20> vertexAttributeState; // 0x458 std::array<type::VertexAttribute, 0x20> vertexAttributeState; // 0x458

View File

@ -35,7 +35,7 @@ namespace skyline::vfs {
} nacpContents{}; } nacpContents{};
static_assert(sizeof(NacpData) == 0x4000); 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); NACP(const std::shared_ptr<vfs::Backing> &backing);

View File

@ -9,7 +9,7 @@
#include "os_filesystem.h" #include "os_filesystem.h"
namespace skyline::vfs { 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 (!DirectoryExists(basePath))
if (!CreateDirectory(basePath, true)) if (!CreateDirectory(basePath, true))
throw exception("Error creating the OS filesystem backing directory"); throw exception("Error creating the OS filesystem backing directory");