diff --git a/nx/Makefile b/nx/Makefile index 2b8159db..2aed2ada 100644 --- a/nx/Makefile +++ b/nx/Makefile @@ -24,7 +24,7 @@ VERSION := $(LIBNX_MAJOR).$(LIBNX_MINOR).$(LIBNX_PATCH) #--------------------------------------------------------------------------------- TARGET := nx #BUILD := build -SOURCES := source/system source/kernel source/services source/devices +SOURCES := source/system source/kernel source/services source/devices source/gfx DATA := data INCLUDES := include diff --git a/nx/include/switch.h b/nx/include/switch.h index 27dff05c..ab9cba0c 100644 --- a/nx/include/switch.h +++ b/nx/include/switch.h @@ -31,6 +31,8 @@ extern "C" { #include +#include + #ifdef __cplusplus } #endif diff --git a/nx/include/switch/gfx/gfx.h b/nx/include/switch/gfx/gfx.h new file mode 100644 index 00000000..9e81e2e0 --- /dev/null +++ b/nx/include/switch/gfx/gfx.h @@ -0,0 +1,3 @@ +/// Do not use viInitialize/viExit when using these. +void gfxInitDefault(void); +void gfxExit(void); diff --git a/nx/include/switch/services/applet.h b/nx/include/switch/services/applet.h index 3eeadf5f..a38f1c75 100644 --- a/nx/include/switch/services/applet.h +++ b/nx/include/switch/services/applet.h @@ -12,3 +12,5 @@ typedef enum Result appletInitialize(void); void appletExit(void); Result appletGetAppletResourceUserId(u64 *out); + +Result appletCreateManagedDisplayLayer(u64 *out); diff --git a/nx/include/switch/services/vi.h b/nx/include/switch/services/vi.h index 0cdd2057..4465fc7e 100644 --- a/nx/include/switch/services/vi.h +++ b/nx/include/switch/services/vi.h @@ -1,11 +1,27 @@ -typedef enum -{ +typedef struct { + u64 DisplayId; + char DisplayName[0x40]; + bool initialized; +} viDisplay; + +typedef struct { + u64 LayerId; + bool StrayLayer; + bool initialized; +} viLayer; + +typedef enum { VISERVTYPE_Default = -1, VISERVTYPE_Application = 0, VISERVTYPE_System = 1, VISERVTYPE_Manager = 2, } viServiceType; +/// Used by viOpenLayer when CreateStrayLayer is used internally. +typedef enum { + VILAYERFLAGS_Default = 0x1, +} viLayerFlags; + Result viInitialize(viServiceType servicetype); void viExit(void); Handle viGetSessionService(void); @@ -14,3 +30,8 @@ Handle viGetSession_IHOSBinderDriverRelay(void); Handle viGetSession_ISystemDisplayService(void); Handle viGetSession_IManagerDisplayService(void); Handle viGetSession_IHOSBinderDriverIndirect(void); + +Result viOpenDisplay(const char *DisplayName, viDisplay *display); +Result viCloseDisplay(viDisplay *display); +Result viOpenLayer(u8 NativeWindow[0x100], u64 *NativeWindow_Size, const viDisplay *display, viLayer *layer, u32 LayerFlags, u64 LayerId); +Result viCloseLayer(viLayer *layer); diff --git a/nx/source/gfx/gfx.c b/nx/source/gfx/gfx.c new file mode 100644 index 00000000..6d90b2da --- /dev/null +++ b/nx/source/gfx/gfx.c @@ -0,0 +1,47 @@ +#include +#include + +static bool g_gfxInitialized = 0; +static viDisplay g_gfxDisplay; +static viLayer g_gfxLayer; +static u8 g_gfxNativeWindow[0x100]; +static u64 g_gfxNativeWindow_Size; + +static Result _gfxInit(viServiceType servicetype, const char *DisplayName, u32 LayerFlags, u64 LayerId) { + Result rc=0; + + if(g_gfxInitialized)return 0; + + rc = viInitialize(servicetype); + if (R_FAILED(rc)) return rc; + + rc = viOpenDisplay(DisplayName, &g_gfxDisplay); + + if (R_SUCCEEDED(rc)) rc = viOpenLayer(g_gfxNativeWindow, &g_gfxNativeWindow_Size, &g_gfxDisplay, &g_gfxLayer, LayerFlags, LayerId); + + if (R_FAILED(rc)) { + viCloseDisplay(&g_gfxDisplay); + viExit(); + } + + if (R_SUCCEEDED(rc)) g_gfxInitialized = 1; + + return 0; +} + +void gfxInitDefault(void) { + Result rc = _gfxInit(VILAYERFLAGS_Default, "Default", VILAYERFLAGS_Default, 0); + if (R_FAILED(rc)) fatalSimple(rc); +} + +void gfxExit(void) { + if(!g_gfxInitialized)return; + + viCloseLayer(&g_gfxLayer); + viCloseDisplay(&g_gfxDisplay); + + viExit(); + + g_gfxInitialized = 0; +} + diff --git a/nx/source/services/applet.c b/nx/source/services/applet.c index abe5bebd..f60c6a8e 100644 --- a/nx/source/services/applet.c +++ b/nx/source/services/applet.c @@ -309,3 +309,39 @@ static Result _appletNotifyRunning(u8 *out) { return rc; } +Result appletCreateManagedDisplayLayer(u64 *out) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 40; + + Result rc = ipcDispatch(g_appletISelfController); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&r); + + struct { + u64 magic; + u64 result; + u64 out; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + *out = resp->out; + } + } + + return rc; +} + diff --git a/nx/source/services/vi.c b/nx/source/services/vi.c index b4098521..a897327b 100644 --- a/nx/source/services/vi.c +++ b/nx/source/services/vi.c @@ -163,3 +163,233 @@ static Result _viGetSessionNoParams(Handle sessionhandle, Handle* handle_out, u6 return _viGetSession(sessionhandle, handle_out, &raw, sizeof(raw)); } +Result viOpenDisplay(const char *DisplayName, viDisplay *display) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + char DisplayName[0x40]; + } *raw; + + memset(display, 0, sizeof(viDisplay)); + + raw = ipcPrepareHeader(&c, sizeof(raw)); + raw->magic = SFCI_MAGIC; + raw->cmd_id = 1010; + + strncpy(display->DisplayName, DisplayName, sizeof(display->DisplayName)-1); + memcpy(raw->DisplayName, display->DisplayName, sizeof(display->DisplayName)); + + Result rc = ipcDispatch(g_viIApplicationDisplayService); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&r); + + struct { + u64 magic; + u64 result; + u64 DisplayId; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + display->DisplayId = resp->DisplayId; + display->initialized = 1; + } + } + + return rc; +} + +Result viCloseDisplay(viDisplay *display) { + IpcCommand c; + ipcInitialize(&c); + + if(!display->initialized)return 0; + + struct { + u64 magic; + u64 cmd_id; + u64 DisplayId; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(raw)); + raw->magic = SFCI_MAGIC; + raw->cmd_id = 1020; + raw->DisplayId = display->DisplayId; + + Result rc = ipcDispatch(g_viIApplicationDisplayService); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&r); + + struct { + u64 magic; + u64 result; + } *resp = r.Raw; + + rc = resp->result; + + display->initialized = 0; + } + + return rc; +} + +static Result _viOpenLayer(u8 NativeWindow[0x100], u64 *NativeWindow_Size, const viDisplay *display, u64 LayerId, u64 AppletResourceUserId) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + char DisplayName[0x40]; + u64 LayerId; + u64 AppletResourceUserId; + } *raw; + + ipcSendPid(&c); + ipcAddRecvBuffer(&c, NativeWindow, 0x100, 0); + + raw = ipcPrepareHeader(&c, sizeof(raw)); + raw->magic = SFCI_MAGIC; + raw->cmd_id = 2020; + + memcpy(raw->DisplayName, display->DisplayName, sizeof(display->DisplayName)); + + raw->LayerId = LayerId; + raw->AppletResourceUserId = AppletResourceUserId; + + Result rc = ipcDispatch(g_viIApplicationDisplayService); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&r); + + struct { + u64 magic; + u64 result; + u64 NativeWindow_Size; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + *NativeWindow_Size = resp->NativeWindow_Size; + } + } + + return rc; +} + +static Result _viCreateStrayLayer(u8 NativeWindow[0x100], u64 *NativeWindow_Size, const viDisplay *display, u32 LayerFlags, u64 *LayerId) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u32 LayerFlags; + u32 pad; + u64 DisplayId; + } *raw; + + ipcAddRecvBuffer(&c, NativeWindow, 0x100, 0); + + raw = ipcPrepareHeader(&c, sizeof(raw)); + raw->magic = SFCI_MAGIC; + raw->cmd_id = 2030; + raw->LayerFlags = LayerFlags; + raw->DisplayId = display->DisplayId; + + Result rc = ipcDispatch(g_viIApplicationDisplayService); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&r); + + struct { + u64 magic; + u64 result; + u64 LayerId; + u64 NativeWindow_Size; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + *LayerId = resp->LayerId; + *NativeWindow_Size = resp->NativeWindow_Size; + } + } + + return rc; +} + +Result viOpenLayer(u8 NativeWindow[0x100], u64 *NativeWindow_Size, const viDisplay *display, viLayer *layer, u32 LayerFlags, u64 LayerId) { + Result rc = 0; + u64 AppletResourceUserId = 0; + + memset(layer, 0, sizeof(viLayer)); + + if (LayerId==0) rc = appletGetAppletResourceUserId(&AppletResourceUserId); + if (LayerId==0 && (R_FAILED(rc) || AppletResourceUserId == 0)) { + rc = _viCreateStrayLayer(NativeWindow, NativeWindow_Size, display, LayerFlags, &layer->LayerId); + } + else { + if (LayerId==0) { + rc = appletCreateManagedDisplayLayer(&LayerId); + if (R_FAILED(rc)) return rc; + } + + rc = _viOpenLayer(NativeWindow, NativeWindow_Size, display, LayerId, AppletResourceUserId); + + if (R_SUCCEEDED(rc)) layer->LayerId = LayerId; + } + + if (R_SUCCEEDED(rc)) layer->initialized = 1; + + return rc; +} + +Result viCloseLayer(viLayer *layer) { + IpcCommand c; + ipcInitialize(&c); + + if(!layer->initialized)return 0; + + struct { + u64 magic; + u64 cmd_id; + u64 LayerId; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(raw)); + raw->magic = SFCI_MAGIC; + raw->cmd_id = layer->StrayLayer==0 ? 2021 : 2031; + raw->LayerId = layer->LayerId; + + Result rc = ipcDispatch(g_viIApplicationDisplayService); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&r); + + struct { + u64 magic; + u64 result; + } *resp = r.Raw; + + rc = resp->result; + + memset(layer, 0, sizeof(viLayer)); + } + + return rc; +} +