diff --git a/nx/include/switch/gfx/nvioctl.h b/nx/include/switch/gfx/nvioctl.h index 1e1a7f2e..f3695d66 100644 --- a/nx/include/switch/gfx/nvioctl.h +++ b/nx/include/switch/gfx/nvioctl.h @@ -38,3 +38,10 @@ typedef struct { Result nvioctlNvhostCtrlGpu_GetCharacteristics(u32 fd, gpu_characteristics *out); +Result nvioctlNvhostAsGpu_AllocSpace(u32 fd, u32 pages, u32 page_size, u32 flags, u64 align, u64 *offset); +Result nvioctlNvhostAsGpu_MapBufferEx(u32 fd, u32 flags, u32 kind, u32 nvmap_handle, u32 page_size, u64 buffer_offset, u64 mapping_size, u64 *offset); +Result nvioctlNvhostAsGpu_InitializeEx(u32 fd, u32 big_page_size); + +Result nvioctlNvmap_Create(u32 fd, u32 size, u32 *nvmap_handle); +Result nvioctlNvmap_Alloc(u32 fd, u32 nvmap_handle, u32 heapmask, u32 flags, u32 align, u8 kind, void* addr); + diff --git a/nx/source/gfx/nvgfx.c b/nx/source/gfx/nvgfx.c index 5ca015b8..0066734d 100644 --- a/nx/source/gfx/nvgfx.c +++ b/nx/source/gfx/nvgfx.c @@ -1,29 +1,75 @@ #include +#include #include static bool g_nvgfxInitialized = 0; static u32 g_nvgfx_fd_nvhostctrlgpu; +static u32 g_nvgfx_fd_nvhostasgpu; +static u32 g_nvgfx_fd_nvmap; +static u32 g_nvgfx_nvmapobj; static gpu_characteristics g_nvgfx_gpu_characteristics; +static u64 g_nvgfx_nvhostasgpu_allocspace_offset; + +static u8 *g_nvgfx_nvmap_mem; +size_t g_nvgfx_nvmap_mem_size; Result nvgfxInitialize(void) { Result rc=0; if(g_nvgfxInitialized)return 0; g_nvgfx_fd_nvhostctrlgpu = 0; + g_nvgfx_fd_nvhostasgpu = 0; + g_nvgfx_fd_nvmap = 0; + g_nvgfx_nvmapobj = 0; memset(&g_nvgfx_gpu_characteristics, 0, sizeof(gpu_characteristics)); + g_nvgfx_nvhostasgpu_allocspace_offset = 0; + + g_nvgfx_nvmap_mem_size = 0x10000; + + if (R_SUCCEEDED(rc)) { + g_nvgfx_nvmap_mem = memalign(0x1000, g_nvgfx_nvmap_mem_size); + if (g_nvgfx_nvmap_mem==NULL) rc = MAKERESULT(MODULE_LIBNX, LIBNX_OUTOFMEM); + } //Officially NVHOST_IOCTL_CTRL_GET_CONFIG is used a lot (here and later), skip that. - rc = nvOpen(&g_nvgfx_fd_nvhostctrlgpu, "/dev/nvhost-ctrl-gpu"); - if (R_SUCCEEDED(rc)) { - rc = nvioctlNvhostCtrlGpu_GetCharacteristics(g_nvgfx_fd_nvhostctrlgpu, &g_nvgfx_gpu_characteristics); - //TODO: What is the above output officially used for? - } + if (R_SUCCEEDED(rc)) rc = nvOpen(&g_nvgfx_fd_nvhostctrlgpu, "/dev/nvhost-ctrl-gpu"); + if (R_SUCCEEDED(rc)) rc = nvioctlNvhostCtrlGpu_GetCharacteristics(g_nvgfx_fd_nvhostctrlgpu, &g_nvgfx_gpu_characteristics); + //Officially NVGPU_GPU_IOCTL_GET_TPC_MASKS is used here. + + //Officially NVGPU_GPU_IOCTL_ZCULL_GET_CTX_SIZE and NVGPU_GPU_IOCTL_ZCULL_GET_INFO are used here. + + if (R_SUCCEEDED(rc)) rc = nvOpen(&g_nvgfx_fd_nvhostasgpu, "/dev/nvhost-as-gpu"); + + if (R_SUCCEEDED(rc)) rc = nvioctlNvhostAsGpu_InitializeEx(g_nvgfx_fd_nvhostasgpu, 1); + + //NVGPU_AS_IOCTL_GET_VA_REGIONS twice + + if (R_SUCCEEDED(rc)) rc = nvioctlNvhostAsGpu_AllocSpace(g_nvgfx_fd_nvhostasgpu, 0x10000, 0x1000, 0, 0x1000, &g_nvgfx_nvhostasgpu_allocspace_offset); + + if (R_SUCCEEDED(rc)) rc = nvOpen(&g_nvgfx_fd_nvmap, "/dev/nvmap"); + + if (R_SUCCEEDED(rc)) rc = nvioctlNvmap_Create(g_nvgfx_fd_nvmap, g_nvgfx_nvmap_mem_size, &g_nvgfx_nvmapobj); + + if (R_SUCCEEDED(rc)) rc = nvioctlNvmap_Alloc(g_nvgfx_fd_nvmap, g_nvgfx_nvmapobj, 0, 0, 0x20000, 0, g_nvgfx_nvmap_mem); + + //Currently broken. + if (R_SUCCEEDED(rc)) rc = nvioctlNvhostAsGpu_MapBufferEx(g_nvgfx_fd_nvhostasgpu, 4, 0, g_nvgfx_nvmapobj, 0x1000, 0, g_nvgfx_nvmap_mem_size, NULL); + if (R_SUCCEEDED(rc)) rc = -1; + if (R_SUCCEEDED(rc)) rc = nvioctlNvhostAsGpu_MapBufferEx(g_nvgfx_fd_nvhostasgpu, 4, 0xfe, g_nvgfx_nvmapobj, 0x1000, 0, g_nvgfx_nvmap_mem_size, NULL); + + if (R_FAILED(rc)) nvClose(g_nvgfx_fd_nvmap); + if (R_FAILED(rc)) nvClose(g_nvgfx_fd_nvhostasgpu); if (R_FAILED(rc)) nvClose(g_nvgfx_fd_nvhostctrlgpu); + if (g_nvgfx_nvmap_mem) { + free(g_nvgfx_nvmap_mem); + g_nvgfx_nvmap_mem = NULL; + } + if (R_SUCCEEDED(rc)) g_nvgfxInitialized = 1; return rc; @@ -32,9 +78,18 @@ Result nvgfxInitialize(void) { void nvgfxExit(void) { if(!g_nvgfxInitialized)return; + nvClose(g_nvgfx_fd_nvmap); + nvClose(g_nvgfx_fd_nvhostasgpu); nvClose(g_nvgfx_fd_nvhostctrlgpu); + g_nvgfx_fd_nvmap = 0; + g_nvgfx_fd_nvhostasgpu = 0; g_nvgfx_fd_nvhostctrlgpu = 0; + if (g_nvgfx_nvmap_mem) { + free(g_nvgfx_nvmap_mem); + g_nvgfx_nvmap_mem = NULL; + } + g_nvgfxInitialized = 0; } diff --git a/nx/source/gfx/nvioctl.c b/nx/source/gfx/nvioctl.c index 166fb115..7cdd6c25 100644 --- a/nx/source/gfx/nvioctl.c +++ b/nx/source/gfx/nvioctl.c @@ -22,3 +22,119 @@ Result nvioctlNvhostCtrlGpu_GetCharacteristics(u32 fd, gpu_characteristics *out) return rc; } +Result nvioctlNvhostAsGpu_AllocSpace(u32 fd, u32 pages, u32 page_size, u32 flags, u64 align, u64 *offset) { + Result rc=0; + + struct { + u32 pages;//in + u32 page_size;//in + u32 flags;//in + u32 pad; + union { + u64 offset;//out + u64 align;//in + }; + } data; + + memset(&data, 0, sizeof(data)); + data.pages = pages; + data.page_size = page_size; + data.flags = flags; + data.align = align; + + rc = nvIoctl(fd, _IOWR(0x41, 0x02, data), &data); + if (R_FAILED(rc)) return rc; + + *offset = data.offset; + + return rc; +} + +Result nvioctlNvhostAsGpu_MapBufferEx(u32 fd, u32 flags, u32 kind, u32 nvmap_handle, u32 page_size, u64 buffer_offset, u64 mapping_size, u64 *offset) { + Result rc=0; + + struct { + u32 flags; // in bit0: fixed_offset, bit2: cacheable + u32 kind; // in -1 is default + u32 nvmap_handle; // in + u32 page_size; // inout 0 means don't care + u64 buffer_offset; // in + u64 mapping_size; // in + u64 offset; // out + } data; + + memset(&data, 0, sizeof(data)); + data.flags = flags; + data.kind = kind; + data.nvmap_handle = nvmap_handle; + data.page_size = page_size; + data.buffer_offset = buffer_offset; + data.mapping_size = mapping_size; + + rc = nvIoctl(fd, _IOW(0x41, 0x06, data), &data); + if (R_FAILED(rc)) return rc; + + if (offset) *offset = data.offset; + + return rc; +} + +Result nvioctlNvhostAsGpu_InitializeEx(u32 fd, u32 big_page_size) { + struct { + u32 big_page_size; // depends on GPU's available_big_page_sizes; 0=default + s32 as_fd; // ignored; passes 0 + u32 flags; // ignored; passes 0 + u32 reserved; // ignored; passes 0 + u64 unk0; + u64 unk1; + u64 unk2; + } data; + + memset(&data, 0, sizeof(data)); + data.big_page_size = big_page_size; + + return nvIoctl(fd, _IOW(0x41, 0x09, data), &data); + +} + +Result nvioctlNvmap_Create(u32 fd, u32 size, u32 *nvmap_handle) { + Result rc=0; + + struct { + u32 size;//in + u32 handle;//out + } data; + + memset(&data, 0, sizeof(data)); + data.size = size; + + rc = nvIoctl(fd, _IOWR(0x01, 0x01, data), &data); + if (R_FAILED(rc)) return rc; + + *nvmap_handle = data.handle; + + return rc; +} + +Result nvioctlNvmap_Alloc(u32 fd, u32 nvmap_handle, u32 heapmask, u32 flags, u32 align, u8 kind, void* addr) { + struct { + u32 handle;//in + u32 heapmask;//in + u32 flags; //in (0=read-only, 1=read-write) + u32 align;//in + u8 kind;//in + u8 pad[7]; + u64 addr;//in + } data; + + memset(&data, 0, sizeof(data)); + data.handle = nvmap_handle; + data.heapmask = heapmask; + data.flags = flags; + data.align = align; + data.kind = kind; + data.addr = (u64)addr; + + return nvIoctl(fd, _IOWR(0x01, 0x04, data), &data); +} +