mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-18 01:46:47 +00:00
fatal: wip (pending libnx pr) update for new sf semantics
This commit is contained in:
parent
ed7c0605f9
commit
402e4d1adb
7 changed files with 191 additions and 28 deletions
|
@ -28,6 +28,31 @@ namespace ams::fatal::srv {
|
||||||
u64 lr;
|
u64 lr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr inline size_t MaxThreads = 0x60;
|
||||||
|
|
||||||
|
constinit std::pair<u64, u64> g_thread_id_to_tls_map[MaxThreads];
|
||||||
|
constinit size_t g_tls_map_index = 0;
|
||||||
|
|
||||||
|
void ResetThreadTlsMap() {
|
||||||
|
g_tls_map_index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetThreadTls(u64 thread_id, u64 tls) {
|
||||||
|
if (g_tls_map_index < MaxThreads) {
|
||||||
|
g_thread_id_to_tls_map[g_tls_map_index++] = std::make_pair(thread_id, tls);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetThreadTls(u64 *out, u64 thread_id) {
|
||||||
|
for (size_t i = 0; i < g_tls_map_index; ++i) {
|
||||||
|
if (g_thread_id_to_tls_map[i].first == thread_id) {
|
||||||
|
*out = g_thread_id_to_tls_map[i].second;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool IsThreadFatalCaller(Result result, u32 debug_handle, u64 thread_id, u64 thread_tls_addr, ThreadContext *thread_ctx) {
|
bool IsThreadFatalCaller(Result result, u32 debug_handle, u64 thread_id, u64 thread_tls_addr, ThreadContext *thread_ctx) {
|
||||||
/* Verify that the thread is running or waiting. */
|
/* Verify that the thread is running or waiting. */
|
||||||
{
|
{
|
||||||
|
@ -177,7 +202,7 @@ namespace ams::fatal::srv {
|
||||||
ON_SCOPE_EXIT { R_ABORT_UNLESS(svc::CloseHandle(debug_handle)); };
|
ON_SCOPE_EXIT { R_ABORT_UNLESS(svc::CloseHandle(debug_handle)); };
|
||||||
|
|
||||||
/* First things first, check if process is 64 bits, and get list of thread infos. */
|
/* First things first, check if process is 64 bits, and get list of thread infos. */
|
||||||
std::unordered_map<u64, u64> thread_id_to_tls;
|
ResetThreadTlsMap();
|
||||||
{
|
{
|
||||||
bool got_create_process = false;
|
bool got_create_process = false;
|
||||||
svc::DebugEventInfo d;
|
svc::DebugEventInfo d;
|
||||||
|
@ -189,7 +214,7 @@ namespace ams::fatal::srv {
|
||||||
got_create_process = true;
|
got_create_process = true;
|
||||||
break;
|
break;
|
||||||
case svc::DebugEvent_CreateThread:
|
case svc::DebugEvent_CreateThread:
|
||||||
thread_id_to_tls[d.info.create_thread.thread_id] = d.info.create_thread.tls_address;
|
SetThreadTls(d.info.create_thread.thread_id, d.info.create_thread.tls_address);
|
||||||
break;
|
break;
|
||||||
case svc::DebugEvent_Exception:
|
case svc::DebugEvent_Exception:
|
||||||
case svc::DebugEvent_ExitProcess:
|
case svc::DebugEvent_ExitProcess:
|
||||||
|
@ -224,13 +249,14 @@ namespace ams::fatal::srv {
|
||||||
/* We need to locate the thread that's called fatal. */
|
/* We need to locate the thread that's called fatal. */
|
||||||
for (s32 i = 0; i < thread_count; i++) {
|
for (s32 i = 0; i < thread_count; i++) {
|
||||||
const u64 cur_thread_id = thread_ids[i];
|
const u64 cur_thread_id = thread_ids[i];
|
||||||
if (thread_id_to_tls.find(cur_thread_id) == thread_id_to_tls.end()) {
|
u64 cur_thread_tls;
|
||||||
|
if (!GetThreadTls(std::addressof(cur_thread_tls), cur_thread_id)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsThreadFatalCaller(ctx->result, debug_handle, cur_thread_id, thread_id_to_tls[cur_thread_id], &thread_ctx)) {
|
if (IsThreadFatalCaller(ctx->result, debug_handle, cur_thread_id, cur_thread_tls, &thread_ctx)) {
|
||||||
thread_id = cur_thread_id;
|
thread_id = cur_thread_id;
|
||||||
thread_tls = thread_id_to_tls[thread_id];
|
thread_tls = cur_thread_tls;
|
||||||
found_fatal_caller = true;
|
found_fatal_caller = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,41 @@
|
||||||
#include "fatal_config.hpp"
|
#include "fatal_config.hpp"
|
||||||
#include "fatal_font.hpp"
|
#include "fatal_font.hpp"
|
||||||
|
|
||||||
|
namespace ams::fatal::srv::font {
|
||||||
|
|
||||||
|
constinit lmem::HeapHandle g_font_heap_handle;
|
||||||
|
|
||||||
|
void SetHeapMemory(void *memory, size_t memory_size) {
|
||||||
|
g_font_heap_handle = lmem::CreateExpHeap(memory, memory_size, lmem::CreateOption_None);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *AllocateForFont(size_t size) {
|
||||||
|
return lmem::AllocateFromExpHeap(g_font_heap_handle, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeallocateForFont(void *p) {
|
||||||
|
if (p != nullptr) {
|
||||||
|
return lmem::FreeToExpHeap(g_font_heap_handle, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#define STBTT_assert(x) AMS_ASSERT(x)
|
||||||
|
#define STBTT_malloc(x,u) ((void)(u),ams::fatal::srv::font::AllocateForFont(x))
|
||||||
|
#define STBTT_free(x,u) ((void)(u),ams::fatal::srv::font::DeallocateForFont(x))
|
||||||
|
|
||||||
#define STBTT_STATIC
|
#define STBTT_STATIC
|
||||||
#define STB_TRUETYPE_IMPLEMENTATION
|
#define STB_TRUETYPE_IMPLEMENTATION
|
||||||
#include "stb_truetype.h"
|
#include "stb_truetype.h"
|
||||||
#undef STBTT_STATIC
|
#undef STBTT_STATIC
|
||||||
#undef STB_TRUETYPE_IMPLEMENTATION
|
#undef STB_TRUETYPE_IMPLEMENTATION
|
||||||
|
|
||||||
|
#undef STBTT_malloc
|
||||||
|
#undef STBTT_free
|
||||||
|
#undef STBTT_assert
|
||||||
|
|
||||||
/* Define color conversion macros. */
|
/* Define color conversion macros. */
|
||||||
#define RGB888_TO_RGB565(r, g, b) ((((r >> 3) << 11) & 0xF800) | (((g >> 2) << 5) & 0x7E0) | ((b >> 3) & 0x1F))
|
#define RGB888_TO_RGB565(r, g, b) ((((r >> 3) << 11) & 0xF800) | (((g >> 2) << 5) & 0x7E0) | ((b >> 3) & 0x1F))
|
||||||
#define RGB565_GET_R8(c) ((((c >> 11) & 0x1F) << 3) | ((c >> 13) & 7))
|
#define RGB565_GET_R8(c) ((((c >> 11) & 0x1F) << 3) | ((c >> 13) & 7))
|
||||||
|
@ -66,7 +95,7 @@ namespace ams::fatal::srv::font {
|
||||||
void DrawCodePoint(u32 codepoint, u32 x, u32 y) {
|
void DrawCodePoint(u32 codepoint, u32 x, u32 y) {
|
||||||
int width = 0, height = 0;
|
int width = 0, height = 0;
|
||||||
u8* imageptr = stbtt_GetCodepointBitmap(&g_stb_font, g_font_size, g_font_size, codepoint, &width, &height, 0, 0);
|
u8* imageptr = stbtt_GetCodepointBitmap(&g_stb_font, g_font_size, g_font_size, codepoint, &width, &height, 0, 0);
|
||||||
ON_SCOPE_EXIT { std::free(imageptr); };
|
ON_SCOPE_EXIT { DeallocateForFont(imageptr); };
|
||||||
|
|
||||||
for (int tmpy = 0; tmpy < height; tmpy++) {
|
for (int tmpy = 0; tmpy < height; tmpy++) {
|
||||||
for (int tmpx = 0; tmpx < width; tmpx++) {
|
for (int tmpx = 0; tmpx < width; tmpx++) {
|
||||||
|
|
|
@ -20,6 +20,7 @@ namespace ams::fatal::srv::font {
|
||||||
|
|
||||||
Result InitializeSharedFont();
|
Result InitializeSharedFont();
|
||||||
void ConfigureFontFramebuffer(u16 *fb, u32 (*unswizzle_func)(u32, u32));
|
void ConfigureFontFramebuffer(u16 *fb, u32 (*unswizzle_func)(u32, u32));
|
||||||
|
void SetHeapMemory(void *memory, size_t memory_size);
|
||||||
|
|
||||||
void SetFontColor(u16 color);
|
void SetFontColor(u16 color);
|
||||||
void SetPosition(u32 x, u32 y);
|
void SetPosition(u32 x, u32 y);
|
||||||
|
|
|
@ -25,7 +25,7 @@ extern "C" {
|
||||||
u32 __nx_applet_type = AppletType_None;
|
u32 __nx_applet_type = AppletType_None;
|
||||||
u32 __nx_fs_num_sessions = 1;
|
u32 __nx_fs_num_sessions = 1;
|
||||||
|
|
||||||
#define INNER_HEAP_SIZE 0x240000
|
#define INNER_HEAP_SIZE 0x0
|
||||||
size_t nx_inner_heap_size = INNER_HEAP_SIZE;
|
size_t nx_inner_heap_size = INNER_HEAP_SIZE;
|
||||||
char nx_inner_heap[INNER_HEAP_SIZE];
|
char nx_inner_heap[INNER_HEAP_SIZE];
|
||||||
|
|
||||||
|
@ -40,6 +40,9 @@ extern "C" {
|
||||||
alignas(16) u8 __nx_exception_stack[ams::os::MemoryPageSize];
|
alignas(16) u8 __nx_exception_stack[ams::os::MemoryPageSize];
|
||||||
u64 __nx_exception_stack_size = sizeof(__nx_exception_stack);
|
u64 __nx_exception_stack_size = sizeof(__nx_exception_stack);
|
||||||
void __libnx_exception_handler(ThreadExceptionDump *ctx);
|
void __libnx_exception_handler(ThreadExceptionDump *ctx);
|
||||||
|
|
||||||
|
void *__libnx_thread_alloc(size_t size);
|
||||||
|
void __libnx_thread_free(void *mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ams {
|
namespace ams {
|
||||||
|
@ -56,6 +59,29 @@ namespace ams {
|
||||||
|
|
||||||
using namespace ams;
|
using namespace ams;
|
||||||
|
|
||||||
|
namespace ams::fatal {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constinit u8 g_fs_heap_memory[2_KB];
|
||||||
|
lmem::HeapHandle g_fs_heap_handle;
|
||||||
|
|
||||||
|
void *AllocateForFs(size_t size) {
|
||||||
|
return lmem::AllocateFromExpHeap(g_fs_heap_handle, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeallocateForFs(void *p, size_t size) {
|
||||||
|
return lmem::FreeToExpHeap(g_fs_heap_handle, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeFsHeap() {
|
||||||
|
g_fs_heap_handle = lmem::CreateExpHeap(g_fs_heap_memory, sizeof(g_fs_heap_memory), lmem::CreateOption_ThreadSafe);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void __libnx_exception_handler(ThreadExceptionDump *ctx) {
|
void __libnx_exception_handler(ThreadExceptionDump *ctx) {
|
||||||
ams::CrashHandler(ctx);
|
ams::CrashHandler(ctx);
|
||||||
}
|
}
|
||||||
|
@ -75,6 +101,9 @@ void __libnx_initheap(void) {
|
||||||
void __appInit(void) {
|
void __appInit(void) {
|
||||||
hos::InitializeForStratosphere();
|
hos::InitializeForStratosphere();
|
||||||
|
|
||||||
|
fatal::InitializeFsHeap();
|
||||||
|
fs::SetAllocator(fatal::AllocateForFs, fatal::DeallocateForFs);
|
||||||
|
|
||||||
sm::DoWithSession([&]() {
|
sm::DoWithSession([&]() {
|
||||||
R_ABORT_UNLESS(setInitialize());
|
R_ABORT_UNLESS(setInitialize());
|
||||||
R_ABORT_UNLESS(setsysInitialize());
|
R_ABORT_UNLESS(setsysInitialize());
|
||||||
|
@ -137,8 +166,38 @@ namespace {
|
||||||
|
|
||||||
sf::hipc::ServerManager<NumServers, ServerOptions, NumSessions> g_server_manager;
|
sf::hipc::ServerManager<NumServers, ServerOptions, NumSessions> g_server_manager;
|
||||||
|
|
||||||
|
constinit sf::UnmanagedServiceObject<fatal::impl::IService, fatal::srv::Service> g_user_service_object;
|
||||||
|
constinit sf::UnmanagedServiceObject<fatal::impl::IPrivateService, fatal::srv::Service> g_private_service_object;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace ams {
|
||||||
|
|
||||||
|
void *Malloc(size_t size) {
|
||||||
|
AMS_ABORT("ams::Malloc was called");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Free(void *ptr) {
|
||||||
|
AMS_ABORT("ams::Free was called");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void *operator new(size_t size) {
|
||||||
|
AMS_ABORT("operator new(size_t) was called");
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator delete(void *p) {
|
||||||
|
AMS_ABORT("operator delete(void *) was called");
|
||||||
|
}
|
||||||
|
|
||||||
|
void *__libnx_thread_alloc(size_t size) {
|
||||||
|
AMS_ABORT("__libnx_thread_alloc was called");
|
||||||
|
}
|
||||||
|
|
||||||
|
void __libnx_thread_free(void *mem) {
|
||||||
|
AMS_ABORT("__libnx_thread_free was called");
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
@ -156,8 +215,8 @@ int main(int argc, char **argv)
|
||||||
fatal::srv::CheckRepairStatus();
|
fatal::srv::CheckRepairStatus();
|
||||||
|
|
||||||
/* Create services. */
|
/* Create services. */
|
||||||
R_ABORT_UNLESS((g_server_manager.RegisterServer<fatal::impl::IPrivateService, fatal::srv::PrivateService>(PrivateServiceName, PrivateMaxSessions)));
|
R_ABORT_UNLESS(g_server_manager.RegisterObjectForServer(g_user_service_object.GetShared(), UserServiceName, UserMaxSessions));
|
||||||
R_ABORT_UNLESS((g_server_manager.RegisterServer<fatal::impl::IService, fatal::srv::Service>(UserServiceName, UserMaxSessions)));
|
R_ABORT_UNLESS(g_server_manager.RegisterObjectForServer(g_private_service_object.GetShared(), PrivateServiceName, PrivateMaxSessions));
|
||||||
|
|
||||||
/* Add dirty event holder. */
|
/* Add dirty event holder. */
|
||||||
auto *dirty_event_holder = ams::fatal::srv::GetFatalDirtyWaitableHolder();
|
auto *dirty_event_holder = ams::fatal::srv::GetFatalDirtyWaitableHolder();
|
||||||
|
|
|
@ -145,7 +145,7 @@ namespace ams::fatal::srv {
|
||||||
return g_context.ThrowFatalWithCpuContext(result, client_pid.GetValue(), policy, cpu_ctx);
|
return g_context.ThrowFatalWithCpuContext(result, client_pid.GetValue(), policy, cpu_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result PrivateService::GetFatalEvent(sf::OutCopyHandle out_h) {
|
Result Service::GetFatalEvent(sf::OutCopyHandle out_h) {
|
||||||
const os::SystemEventType *event;
|
const os::SystemEventType *event;
|
||||||
R_TRY(g_context.GetEvent(std::addressof(event)));
|
R_TRY(g_context.GetEvent(std::addressof(event)));
|
||||||
out_h.SetValue(os::GetReadableHandleOfSystemEvent(event));
|
out_h.SetValue(os::GetReadableHandleOfSystemEvent(event));
|
||||||
|
|
|
@ -18,19 +18,15 @@
|
||||||
|
|
||||||
namespace ams::fatal::srv {
|
namespace ams::fatal::srv {
|
||||||
|
|
||||||
class Service final {
|
class Service {
|
||||||
public:
|
public:
|
||||||
Result ThrowFatal(Result error, const sf::ClientProcessId &client_pid);
|
Result ThrowFatal(Result error, const sf::ClientProcessId &client_pid);
|
||||||
Result ThrowFatalWithPolicy(Result error, const sf::ClientProcessId &client_pid, FatalPolicy policy);
|
Result ThrowFatalWithPolicy(Result error, const sf::ClientProcessId &client_pid, FatalPolicy policy);
|
||||||
Result ThrowFatalWithCpuContext(Result error, const sf::ClientProcessId &client_pid, FatalPolicy policy, const CpuContext &cpu_ctx);
|
Result ThrowFatalWithCpuContext(Result error, const sf::ClientProcessId &client_pid, FatalPolicy policy, const CpuContext &cpu_ctx);
|
||||||
};
|
|
||||||
static_assert(fatal::impl::IsIService<Service>);
|
|
||||||
|
|
||||||
class PrivateService final {
|
|
||||||
public:
|
|
||||||
Result GetFatalEvent(sf::OutCopyHandle out_h);
|
Result GetFatalEvent(sf::OutCopyHandle out_h);
|
||||||
};
|
};
|
||||||
static_assert(fatal::impl::IsIPrivateService<PrivateService>);
|
static_assert(fatal::impl::IsIService<Service>);
|
||||||
|
static_assert(fatal::impl::IsIPrivateService<Service>);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
namespace ams::fatal::srv {
|
namespace ams::fatal::srv {
|
||||||
|
|
||||||
/* Include Atmosphere logo into its own anonymous namespace. */
|
/* Include Atmosphere logo into its own anonymous namespace. */
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
#include "fatal_ams_logo.inc"
|
#include "fatal_ams_logo.inc"
|
||||||
|
@ -39,6 +38,44 @@ namespace ams::fatal::srv {
|
||||||
constexpr u32 FatalScreenWidthAlignedBytes = (FatalScreenWidth * FatalScreenBpp + 63) & ~63;
|
constexpr u32 FatalScreenWidthAlignedBytes = (FatalScreenWidth * FatalScreenBpp + 63) & ~63;
|
||||||
constexpr u32 FatalScreenWidthAligned = FatalScreenWidthAlignedBytes / FatalScreenBpp;
|
constexpr u32 FatalScreenWidthAligned = FatalScreenWidthAlignedBytes / FatalScreenBpp;
|
||||||
|
|
||||||
|
/* There should only be a single transfer memory (for nv). */
|
||||||
|
alignas(os::MemoryPageSize) constinit u8 g_nv_transfer_memory[0x40000];
|
||||||
|
|
||||||
|
/* There should only be a single (1280*768) framebuffer. */
|
||||||
|
alignas(os::MemoryPageSize) constinit u8 g_framebuffer_memory[FatalScreenWidthAlignedBytes * util::AlignUp(FatalScreenHeight, 128)];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void *__libnx_tmem_alloc(size_t size) {
|
||||||
|
return ams::fatal::srv::g_nv_transfer_memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void __libnx_tmem_free(void *mem) {
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void *__libnx_framebuffer_alloc(size_t size) {
|
||||||
|
return ams::fatal::srv::g_framebuffer_memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void __libnx_framebuffer_free(void *mem) {
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void *__libnx_framebuffer_linear_alloc(size_t size) {
|
||||||
|
AMS_ABORT("__libnx_framebuffer_linear_alloc was called");
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void __libnx_framebuffer_linear_free(void *mem) {
|
||||||
|
AMS_ABORT("__libnx_framebuffer_linear_free was called");
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ams::fatal::srv {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
/* Pixel calculation helper. */
|
/* Pixel calculation helper. */
|
||||||
constexpr u32 GetPixelOffset(u32 x, u32 y) {
|
constexpr u32 GetPixelOffset(u32 x, u32 y) {
|
||||||
u32 tmp_pos = ((y & 127) / 16) + (x/32*8) + ((y/16/8)*(((FatalScreenWidthAligned/2)/16*8)));
|
u32 tmp_pos = ((y & 127) / 16) + (x/32*8) + ((y/16/8)*(((FatalScreenWidthAligned/2)/16*8)));
|
||||||
|
@ -60,6 +97,7 @@ namespace ams::fatal::srv {
|
||||||
Result SetupDisplayInternal();
|
Result SetupDisplayInternal();
|
||||||
Result SetupDisplayExternal();
|
Result SetupDisplayExternal();
|
||||||
Result PrepareScreenForDrawing();
|
Result PrepareScreenForDrawing();
|
||||||
|
void PreRenderFrameBuffer();
|
||||||
Result ShowFatal();
|
Result ShowFatal();
|
||||||
public:
|
public:
|
||||||
virtual Result Run() override;
|
virtual Result Run() override;
|
||||||
|
@ -178,24 +216,22 @@ namespace ams::fatal::srv {
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result ShowFatalTask::ShowFatal() {
|
void ShowFatalTask::PreRenderFrameBuffer() {
|
||||||
const FatalConfig &config = GetFatalConfig();
|
const FatalConfig &config = GetFatalConfig();
|
||||||
|
|
||||||
/* Prepare screen for drawing. */
|
/* Pre-render the image into the static framebuffer. */
|
||||||
sm::DoWithSession([&]() {
|
u16 *tiled_buf = reinterpret_cast<u16 *>(g_framebuffer_memory);
|
||||||
R_ABORT_UNLESS(PrepareScreenForDrawing());
|
|
||||||
});
|
|
||||||
|
|
||||||
/* Dequeue a buffer. */
|
/* Temporarily use the NV transfer memory as font backing heap. */
|
||||||
u16 *tiled_buf = reinterpret_cast<u16 *>(framebufferBegin(&this->fb, NULL));
|
font::SetHeapMemory(g_nv_transfer_memory, sizeof(g_nv_transfer_memory));
|
||||||
R_UNLESS(tiled_buf != nullptr, ResultNullGraphicsBuffer());
|
ON_SCOPE_EXIT { std::memset(g_nv_transfer_memory, 0, sizeof(g_nv_transfer_memory)); };
|
||||||
|
|
||||||
/* Let the font manager know about our framebuffer. */
|
/* Let the font manager know about our framebuffer. */
|
||||||
font::ConfigureFontFramebuffer(tiled_buf, GetPixelOffset);
|
font::ConfigureFontFramebuffer(tiled_buf, GetPixelOffset);
|
||||||
font::SetFontColor(0xFFFF);
|
font::SetFontColor(0xFFFF);
|
||||||
|
|
||||||
/* Draw a background. */
|
/* Draw a background. */
|
||||||
for (size_t i = 0; i < this->fb.fb_size / sizeof(*tiled_buf); i++) {
|
for (size_t i = 0; i < sizeof(g_framebuffer_memory) / sizeof(*tiled_buf); i++) {
|
||||||
tiled_buf[i] = 0x39C9;
|
tiled_buf[i] = 0x39C9;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -412,6 +448,22 @@ namespace ams::fatal::srv {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result ShowFatalTask::ShowFatal() {
|
||||||
|
/* Pre-render the framebuffer. */
|
||||||
|
PreRenderFrameBuffer();
|
||||||
|
|
||||||
|
/* Prepare screen for drawing. */
|
||||||
|
sm::DoWithSession([&]() {
|
||||||
|
R_ABORT_UNLESS(PrepareScreenForDrawing());
|
||||||
|
});
|
||||||
|
|
||||||
|
/* Dequeue a buffer. */
|
||||||
|
R_UNLESS(framebufferBegin(&this->fb, NULL) != nullptr, ResultNullGraphicsBuffer());
|
||||||
|
|
||||||
|
/* We've already pre-rendered the frame into the static buffer. */
|
||||||
|
/* ... */
|
||||||
|
|
||||||
/* Enqueue the buffer. */
|
/* Enqueue the buffer. */
|
||||||
framebufferEnd(&fb);
|
framebufferEnd(&fb);
|
||||||
|
|
Loading…
Reference in a new issue