mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-28 08:15:29 +03:00
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:
parent
95a08627e5
commit
f8acc1e131
@ -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"
|
||||
|
BIN
app/src/main/assets/fonts/FontChineseSimplified.ttf
Normal file
BIN
app/src/main/assets/fonts/FontChineseSimplified.ttf
Normal file
Binary file not shown.
BIN
app/src/main/assets/fonts/FontChineseTraditional.ttf
Normal file
BIN
app/src/main/assets/fonts/FontChineseTraditional.ttf
Normal file
Binary file not shown.
BIN
app/src/main/assets/fonts/FontExtendedChineseSimplified.ttf
Normal file
BIN
app/src/main/assets/fonts/FontExtendedChineseSimplified.ttf
Normal file
Binary file not shown.
BIN
app/src/main/assets/fonts/FontKorean.ttf
Normal file
BIN
app/src/main/assets/fonts/FontKorean.ttf
Normal file
Binary file not shown.
BIN
app/src/main/assets/fonts/FontNintendoExtended.ttf
Normal file
BIN
app/src/main/assets/fonts/FontNintendoExtended.ttf
Normal file
Binary file not shown.
BIN
app/src/main/assets/fonts/FontStandard.ttf
Normal file
BIN
app/src/main/assets/fonts/FontStandard.ttf
Normal file
Binary file not shown.
4
app/src/main/assets/fonts/README.md
Normal file
4
app/src/main/assets/fonts/README.md
Normal 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)
|
@ -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));
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
/**
|
||||
@ -41,4 +41,4 @@
|
||||
cases \
|
||||
default: \
|
||||
return defaultValue; \
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
})};
|
||||
|
@ -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
|
||||
|
@ -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{
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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{
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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 {};
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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++) {
|
||||
|
@ -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 {};
|
||||
}
|
||||
|
@ -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
@ -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)
|
59
app/src/main/cpp/skyline/services/pl/shared_font_core.h
Normal file
59
app/src/main/cpp/skyline/services/pl/shared_font_core.h
Normal 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);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
@ -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")
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user