Major refactor and redesign of nvidia wrapper objects, see details:

- NvBuffer replaced with NvMap, which only manages the creation of
  raw nvmap objects. Users must map these objects manually to
  address spaces.
- nvAddressSpaceBindToChannel removed.
- nvChannelSetNvmapFd is now automatic and has been removed.
- Nv3DContext, NvCmdList, NvErrorNotifier, NvGpfifo, NvGpu and
  NvZcullContext have all been removed.
- Introduced NvGpuChannel, which provides all functionality that was
  part of said removed objects.
- Other miscellaneous changes and fixes.
This commit is contained in:
fincs 2018-11-08 01:05:21 +01:00 committed by fincs
parent 85a20f43dc
commit 5fe01c065a
25 changed files with 318 additions and 630 deletions

View File

@ -24,7 +24,7 @@ VERSION := $(LIBNX_MAJOR).$(LIBNX_MINOR).$(LIBNX_PATCH)
#---------------------------------------------------------------------------------
TARGET := nx
#BUILD := build
SOURCES := source/arm source/kernel source/services source/nvidia source/nvidia/ioctl source/nvidia/gpu source/display source/audio source/runtime source/runtime/devices source/runtime/util/utf
SOURCES := source/arm source/kernel source/services source/nvidia source/nvidia/ioctl source/display source/audio source/runtime source/runtime/devices source/runtime/util/utf
DATA := data
INCLUDES := include external/bsd/include

View File

@ -89,17 +89,12 @@ extern "C" {
#include "switch/display/nvgfx.h"
#include "switch/nvidia/ioctl.h"
#include "switch/nvidia/buffer.h"
#include "switch/nvidia/map.h"
#include "switch/nvidia/address_space.h"
#include "switch/nvidia/channel.h"
#include "switch/nvidia/info.h"
#include "switch/nvidia/fence.h"
#include "switch/nvidia/gpu/cmd_list.h"
#include "switch/nvidia/gpu/gpfifo.h"
#include "switch/nvidia/gpu/zcull_ctx.h"
#include "switch/nvidia/gpu/3d_ctx.h"
#include "switch/nvidia/gpu/error_notifier.h"
#include "switch/nvidia/gpu/gpu.h"
#include "switch/nvidia/gpu_channel.h"
#include "switch/audio/driver.h"

View File

@ -1,5 +1,6 @@
#pragma once
#include "types.h"
#include "ioctl.h"
typedef struct NvAddressSpace {
u32 fd;
@ -18,6 +19,3 @@ Result nvAddressSpaceMap(NvAddressSpace* a, u32 nvmap_handle, bool is_gpu_cachea
Result nvAddressSpaceMapFixed(NvAddressSpace* a, u32 nvmap_handle, bool is_gpu_cacheable, NvKind kind, iova_t iova);
Result nvAddressSpaceModify(NvAddressSpace* a, iova_t iova, u64 offset, u64 size, NvKind kind);
Result nvAddressSpaceUnmap(NvAddressSpace* a, iova_t iova);
struct NvChannel;
Result nvAddressSpaceBindToChannel(NvAddressSpace* a, struct NvChannel* channel);

View File

@ -1,31 +0,0 @@
#pragma once
#include "types.h"
#include "address_space.h"
typedef struct NvAddressSpace NvAddressSpace;
typedef struct NvBuffer {
u32 fd;
u32 size;
void* cpu_addr;
iova_t gpu_addr;
iova_t gpu_addr_texture;
NvAddressSpace* addr_space;
NvKind kind;
bool has_init;
bool is_cpu_cacheable;
bool is_gpu_cacheable;
} NvBuffer;
Result nvBufferInit(void);
u32 nvBufferGetNvmapFd(void);
void nvBufferExit(void);
Result nvBufferCreate(NvBuffer* m, size_t size, u32 align, bool is_cpu_cacheable, bool is_gpu_cacheable, NvKind kind, NvAddressSpace* as);
void nvBufferFree(NvBuffer* m);
void* nvBufferGetCpuAddr(NvBuffer* m);
iova_t nvBufferGetGpuAddr(NvBuffer* m);
Result nvBufferMapAsTexture(NvBuffer* m, NvKind kind);
iova_t nvBufferGetGpuAddrTexture(NvBuffer* m);

View File

@ -1,5 +1,6 @@
#pragma once
#include "types.h"
#include "ioctl.h"
typedef struct NvChannel {
u32 fd;
@ -11,4 +12,3 @@ void nvChannelClose(NvChannel* c);
Result nvChannelSetPriority(NvChannel* c, NvChannelPriority prio);
Result nvChannelSetTimeout(NvChannel* c, u32 timeout);
Result nvChannelSetNvmapFd(NvChannel* c);

View File

@ -1,11 +0,0 @@
#pragma once
typedef struct NvGpu NvGpu;
typedef struct {
NvGpu* parent;
u64 obj_id;
} Nv3DContext;
Result nv3DContextCreate(Nv3DContext* t, NvGpu* parent);
void nv3DContextClose(Nv3DContext* t);

View File

@ -1,20 +0,0 @@
#pragma once
typedef struct NvGpu NvGpu;
typedef struct {
NvBuffer buffer;
size_t offset;
size_t num_cmds;
size_t max_cmds;
NvGpu* parent;
} NvCmdList;
Result nvCmdListCreate(NvCmdList* c, NvGpu* parent, size_t max_cmds);
void nvCmdListClose(NvCmdList* c);
iova_t nvCmdListGetGpuAddr(NvCmdList* c);
u64 nvCmdListGetListSize(NvCmdList* c);
void nvCmdListReset(NvCmdList* c);
u32* nvCmdListInsert(NvCmdList* c, size_t num_cmds);

View File

@ -1,14 +0,0 @@
#pragma once
typedef struct NvGpu NvGpu;
typedef struct {
NvGpu* parent;
Event event;
bool has_init;
} NvErrorNotifier;
Result nvErrorNotifierCreate(NvErrorNotifier* t, NvGpu* parent);
void nvErrorNotifierClose(NvErrorNotifier* t);
Result nvErrorNotifierWait(NvErrorNotifier* t, u64 timeout);
Result nvErrorNotifierGetError(NvErrorNotifier* t, NvError* out);

View File

@ -1,19 +0,0 @@
#pragma once
#define GPFIFO_QUEUE_SIZE 0x800
#define GPFIFO_ENTRY_NOT_MAIN BIT(9)
#define GPFIFO_ENTRY_NO_PREFETCH BIT(31)
typedef struct {
NvChannel* parent;
u32 syncpt_id;
u32 num_entries;
nvioctl_gpfifo_entry entries[GPFIFO_QUEUE_SIZE];
} NvGpfifo;
Result nvGpfifoCreate(NvGpfifo* f, NvChannel* parent);
void nvGpfifoClose(NvGpfifo* f);
Result nvGpfifoAppendEntry(NvGpfifo* f, iova_t start, size_t num_cmds, u32 flags);
Result nvGpfifoAppendCmdList(NvGpfifo* f, NvCmdList* cmd_list, u32 flags);
Result nvGpfifoFlush(NvGpfifo* f, u32 fence_incr, NvFence* fence_out);

View File

@ -1,13 +0,0 @@
#pragma once
typedef struct NvGpu {
NvAddressSpace addr_space;
NvChannel gpu_channel;
NvGpfifo gpfifo;
NvZcullContext zcull_ctx;
Nv3DContext _3d_ctx;
NvErrorNotifier error_notifier;
} NvGpu;
Result nvGpuCreate(NvGpu* g);
void nvGpuClose(NvGpu* g);

View File

@ -1,11 +0,0 @@
#pragma once
typedef struct NvGpu NvGpu;
typedef struct {
NvGpu* parent;
NvBuffer ctx_buf;
} NvZcullContext;
Result nvZcullContextCreate(NvZcullContext* z, NvGpu* parent);
void nvZcullContextClose(NvZcullContext* z);

View File

@ -0,0 +1,43 @@
#pragma once
#include "../kernel/event.h"
#include "channel.h"
#include "fence.h"
#define GPFIFO_QUEUE_SIZE 0x800
#define GPFIFO_ENTRY_NOT_MAIN BIT(9)
#define GPFIFO_ENTRY_NO_PREFETCH BIT(31)
typedef struct NvGpuChannel
{
NvChannel base;
Event error_event;
u64 object_id;
NvFence fence;
u32 fence_incr;
nvioctl_gpfifo_entry entries[GPFIFO_QUEUE_SIZE];
u32 num_entries;
} NvGpuChannel;
Result nvGpuChannelCreate(NvGpuChannel* c, struct NvAddressSpace* as);
void nvGpuChannelClose(NvGpuChannel* c);
Result nvGpuChannelZcullBind(NvGpuChannel* c, iova_t iova);
Result nvGpuChannelAppendEntry(NvGpuChannel* c, iova_t start, size_t num_cmds, u32 flags, u32 flush_threshold);
Result nvGpuChannelKickoff(NvGpuChannel* c);
Result nvGpuChannelGetErrorNotification(NvGpuChannel* c, NvError* error);
static inline u32 nvGpuChannelGetSyncpointId(NvGpuChannel* c)
{
return c->fence.id;
}
static inline void nvGpuChannelGetFence(NvGpuChannel* c, NvFence* fence_out)
{
fence_out->id = c->fence.id;
fence_out->value = c->fence.value + c->fence_incr;
}
static inline void nvGpuChannelIncrFence(NvGpuChannel* c)
{
++c->fence_incr;
}

View File

@ -0,0 +1,34 @@
#pragma once
#include "types.h"
typedef struct NvMap {
u32 handle;
u32 id;
u32 size;
void* cpu_addr;
NvKind kind;
bool has_init;
bool is_cpu_cacheable;
} NvMap;
Result nvMapInit(void);
u32 nvMapGetFd(void);
void nvMapExit(void);
Result nvMapCreate(NvMap* m, void* cpu_addr, u32 size, u32 align, NvKind kind, bool is_cpu_cacheable);
void nvMapFree(NvMap* m);
static inline u32 nvMapGetHandle(NvMap* m)
{
return m->handle;
}
static inline u32 nvMapGetId(NvMap* m)
{
return m->id;
}
static inline void* nvMapGetCpuAddr(NvMap* m)
{
return m->cpu_addr;
}

View File

@ -5,8 +5,6 @@
#include "kernel/svc.h"
#include "services/nv.h"
#include "nvidia/ioctl.h"
#include "nvidia/buffer.h"
#include "nvidia/channel.h"
#include "nvidia/address_space.h"
Result nvAddressSpaceCreate(NvAddressSpace* a, u32 page_size)
@ -96,8 +94,3 @@ Result nvAddressSpaceUnmap(NvAddressSpace* a, iova_t iova)
{
return nvioctlNvhostAsGpu_UnmapBuffer(a->fd, iova);
}
Result nvAddressSpaceBindToChannel(NvAddressSpace* a, NvChannel* channel)
{
return nvioctlNvhostAsGpu_BindChannel(a->fd, channel->fd);
}

View File

@ -1,132 +0,0 @@
#include <malloc.h>
#include "types.h"
#include "result.h"
#include "arm/atomics.h"
#include "arm/cache.h"
#include "kernel/svc.h"
#include "services/nv.h"
#include "nvidia/ioctl.h"
#include "nvidia/buffer.h"
#include "nvidia/address_space.h"
static u32 g_nvmap_fd = -1;
static u64 g_refCnt;
Result nvBufferInit(void)
{
Result rc;
if (atomicIncrement64(&g_refCnt) > 0)
return 0;
rc = nvOpen(&g_nvmap_fd, "/dev/nvmap");
if (R_FAILED(rc))
atomicDecrement64(&g_refCnt);
return rc;
}
void nvBufferExit(void)
{
if (atomicDecrement64(&g_refCnt) == 0)
{
if (g_nvmap_fd != -1)
nvClose(g_nvmap_fd);
g_nvmap_fd = -1;
}
}
u32 nvBufferGetNvmapFd(void) {
return g_nvmap_fd;
}
Result nvBufferCreate(
NvBuffer* m, size_t size, u32 align, bool is_cpu_cacheable, bool is_gpu_cacheable, NvKind kind,
NvAddressSpace* as)
{
Result rc;
size = (size + align - 1) & ~(align - 1);
m->has_init = true;
m->is_cpu_cacheable = is_cpu_cacheable;
m->is_gpu_cacheable = is_gpu_cacheable;
m->size = size;
m->fd = -1;
m->cpu_addr = memalign(align, size);
m->gpu_addr = 0;
m->gpu_addr_texture = 0;
m->addr_space = as;
m->kind = kind;
if (m->cpu_addr == NULL)
return MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
rc = nvioctlNvmap_Create(g_nvmap_fd, size, &m->fd);
if (R_SUCCEEDED(rc))
rc = nvioctlNvmap_Alloc(g_nvmap_fd, m->fd,
0, is_cpu_cacheable ? 1 : 0, align, kind, m->cpu_addr);
if (R_SUCCEEDED(rc) && !is_cpu_cacheable) {
armDCacheFlush(m->cpu_addr, m->size);
svcSetMemoryAttribute(m->cpu_addr, m->size, 8, 8);
}
if (R_SUCCEEDED(rc))
rc = nvAddressSpaceMap(as, m->fd, is_gpu_cacheable, NvKind_Pitch, &m->gpu_addr);
if (R_FAILED(rc))
nvBufferFree(m);
return rc;
}
void nvBufferFree(NvBuffer* m)
{
if (!m->has_init)
return;
if (m->gpu_addr_texture) {
nvAddressSpaceUnmap(m->addr_space, m->gpu_addr_texture);
m->gpu_addr_texture = 0;
}
if (m->gpu_addr) {
nvAddressSpaceUnmap(m->addr_space, m->gpu_addr);
m->gpu_addr = 0;
}
if (m->fd != -1) {
nvioctlNvmap_Free(g_nvmap_fd, m->fd);
m->fd = -1;
}
if (m->cpu_addr) {
if (!m->is_cpu_cacheable)
svcSetMemoryAttribute(m->cpu_addr, m->size, 8, 0);
free(m->cpu_addr);
m->cpu_addr = NULL;
}
m->has_init = false;
}
void* nvBufferGetCpuAddr(NvBuffer* m) {
return m->cpu_addr;
}
iova_t nvBufferGetGpuAddr(NvBuffer* m) {
return m->gpu_addr;
}
Result nvBufferMapAsTexture(NvBuffer* m, NvKind kind) {
return nvAddressSpaceMap(m->addr_space, m->fd, m->is_gpu_cacheable, kind, &m->gpu_addr_texture);
}
iova_t nvBufferGetGpuAddrTexture(NvBuffer* m) {
return m->gpu_addr_texture;
}

View File

@ -5,7 +5,7 @@
#include "kernel/svc.h"
#include "services/nv.h"
#include "nvidia/ioctl.h"
#include "nvidia/buffer.h"
#include "nvidia/map.h"
#include "nvidia/channel.h"
Result nvChannelCreate(NvChannel* c, const char* dev)
@ -19,6 +19,9 @@ Result nvChannelCreate(NvChannel* c, const char* dev)
if (R_FAILED(rc))
c->fd = -1;
if (R_SUCCEEDED(rc))
rc = nvioctlChannel_SetNvmapFd(c->fd, nvMapGetFd());
if (R_FAILED(rc))
nvChannelClose(c);
@ -43,7 +46,3 @@ Result nvChannelSetPriority(NvChannel* c, NvChannelPriority prio) {
Result nvChannelSetTimeout(NvChannel* c, u32 timeout) {
return nvioctlChannel_SetTimeout(c->fd, timeout);
}
Result nvChannelSetNvmapFd(NvChannel* c) {
return nvioctlChannel_SetNvmapFd(c->fd, nvBufferGetNvmapFd());
}

View File

@ -1,30 +0,0 @@
#include <malloc.h>
#include "types.h"
#include "result.h"
#include "arm/atomics.h"
#include "kernel/svc.h"
#include "kernel/event.h"
#include "services/nv.h"
#include "nvidia/ioctl.h"
#include "nvidia/buffer.h"
#include "nvidia/address_space.h"
#include "nvidia/channel.h"
#include "nvidia/fence.h"
#include "nvidia/gpu/cmd_list.h"
#include "nvidia/gpu/gpfifo.h"
#include "nvidia/gpu/zcull_ctx.h"
#include "nvidia/gpu/3d_ctx.h"
#include "nvidia/gpu/error_notifier.h"
#include "nvidia/gpu/gpu.h"
Result nv3DContextCreate(Nv3DContext* t, NvGpu* parent)
{
t->parent = parent;
return nvioctlChannel_AllocObjCtx(
parent->gpu_channel.fd, NvClassNumber_3D, 0, &t->obj_id);
}
void nv3DContextClose(Nv3DContext* t) {
// Empty
}

View File

@ -1,65 +0,0 @@
#include <malloc.h>
#include "types.h"
#include "result.h"
#include "arm/atomics.h"
#include "kernel/svc.h"
#include "kernel/event.h"
#include "services/nv.h"
#include "nvidia/ioctl.h"
#include "nvidia/buffer.h"
#include "nvidia/address_space.h"
#include "nvidia/channel.h"
#include "nvidia/fence.h"
#include "nvidia/gpu/cmd_list.h"
#include "nvidia/gpu/gpfifo.h"
#include "nvidia/gpu/zcull_ctx.h"
#include "nvidia/gpu/3d_ctx.h"
#include "nvidia/gpu/error_notifier.h"
#include "nvidia/gpu/gpu.h"
Result nvCmdListCreate(NvCmdList* c, NvGpu* parent, size_t max_cmds)
{
Result rc;
rc = nvBufferCreate(
&c->buffer, max_cmds * 4, 0x1000, NvKind_Pitch, false, false,
&parent->addr_space);
if (R_SUCCEEDED(rc)) {
c->offset = 0;
c->num_cmds = 0;
c->max_cmds = max_cmds;
c->parent = parent;
}
return rc;
}
void nvCmdListClose(NvCmdList* c) {
nvBufferFree(&c->buffer);
}
iova_t nvCmdListGetGpuAddr(NvCmdList* c) {
return nvBufferGetGpuAddr(&c->buffer);
}
u64 nvCmdListGetListSize(NvCmdList* c) {
return c->num_cmds;
}
void nvCmdListReset(NvCmdList* c) {
c->offset = 0;
c->num_cmds = 0;
}
u32* nvCmdListInsert(NvCmdList* c, size_t num_cmds)
{
// Has enough space?
if ((c->offset + c->num_cmds + num_cmds) > c->max_cmds)
return NULL;
c->num_cmds += num_cmds;
u32* list = (u32*) nvBufferGetCpuAddr(&c->buffer);
return &list[c->offset + c->num_cmds - num_cmds];
}

View File

@ -1,52 +0,0 @@
#include <malloc.h>
#include "types.h"
#include "result.h"
#include "arm/atomics.h"
#include "kernel/svc.h"
#include "kernel/event.h"
#include "services/nv.h"
#include "nvidia/ioctl.h"
#include "nvidia/buffer.h"
#include "nvidia/address_space.h"
#include "nvidia/channel.h"
#include "nvidia/fence.h"
#include "nvidia/gpu/cmd_list.h"
#include "nvidia/gpu/gpfifo.h"
#include "nvidia/gpu/zcull_ctx.h"
#include "nvidia/gpu/3d_ctx.h"
#include "nvidia/gpu/error_notifier.h"
#include "nvidia/gpu/gpu.h"
Result nvErrorNotifierCreate(NvErrorNotifier* t, NvGpu* parent)
{
Result rc;
rc = nvQueryEvent(parent->gpu_channel.fd, NvEventId_Gpu_ErrorNotifier, &t->event);
if (R_SUCCEEDED(rc))
rc = nvioctlChannel_SetErrorNotifier(parent->gpu_channel.fd, 1);
if (R_SUCCEEDED(rc)) {
t->parent = parent;
t->has_init = true;
}
return rc;
}
void nvErrorNotifierClose(NvErrorNotifier* t)
{
if (!t->has_init)
return;
nvioctlChannel_SetErrorNotifier(t->parent->gpu_channel.fd, 0);
eventClose(&t->event);
}
Result nvErrorNotifierWait(NvErrorNotifier* t, u64 timeout) {
return eventWait(&t->event, timeout);
}
Result nvErrorNotifierGetError(NvErrorNotifier* t, NvError* out) {
return nvioctlChannel_GetErrorNotification(t->parent->gpu_channel.fd, out);
}

View File

@ -1,90 +0,0 @@
#include <malloc.h>
#include "types.h"
#include "result.h"
#include "arm/atomics.h"
#include "kernel/svc.h"
#include "kernel/event.h"
#include "kernel/detect.h"
#include "services/nv.h"
#include "nvidia/ioctl.h"
#include "nvidia/buffer.h"
#include "nvidia/address_space.h"
#include "nvidia/channel.h"
#include "nvidia/fence.h"
#include "nvidia/info.h"
#include "nvidia/gpu/cmd_list.h"
#include "nvidia/gpu/gpfifo.h"
#include "nvidia/gpu/zcull_ctx.h"
#include "nvidia/gpu/3d_ctx.h"
#include "nvidia/gpu/error_notifier.h"
#include "nvidia/gpu/gpu.h"
Result nvGpfifoCreate(NvGpfifo* f, NvChannel* parent)
{
f->parent = parent;
NvFence fence;
Result res = nvioctlChannel_AllocGpfifoEx2(parent->fd, GPFIFO_QUEUE_SIZE, 1, 0, 0, 0, 0, &fence);
f->syncpt_id = fence.id;
return res;
}
void nvGpfifoClose(NvGpfifo* f) {
/**/
}
Result nvGpfifoAppendEntry(NvGpfifo* f, iova_t start, size_t num_cmds, u32 flags)
{
if (f->num_entries >= GPFIFO_QUEUE_SIZE)
return MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
nvioctl_gpfifo_entry* entry = &f->entries[f->num_entries++];
entry->desc = start;
entry->desc32[1] |= flags | (num_cmds << 10);
return 0;
}
Result nvGpfifoAppendCmdList(NvGpfifo* f, NvCmdList* cmd_list, u32 flags)
{
Result rc = nvGpfifoAppendEntry(f,
nvCmdListGetGpuAddr(cmd_list) + 4*cmd_list->offset,
cmd_list->num_cmds,
flags);
if (R_SUCCEEDED(rc)) {
cmd_list->offset += cmd_list->num_cmds;
cmd_list->num_cmds = 0;
}
return rc;
}
Result nvGpfifoFlush(NvGpfifo* f, u32 fence_incr, NvFence* fence_out)
{
Result rc;
NvFence fence;
if (!f->num_entries)
return MAKERESULT(Module_Libnx, LibnxError_NotFound);
fence.id = 0;
fence.value = fence_incr;
u32 flags = BIT(2);
if (fence_incr)
flags |= BIT(8);
if (kernelAbove400())
rc = nvioctlChannel_KickoffPb(f->parent->fd, f->entries, f->num_entries, flags, &fence);
else
rc = nvioctlChannel_SubmitGpfifo(f->parent->fd, f->entries, f->num_entries, flags, &fence);
if (R_SUCCEEDED(rc)) {
f->num_entries = 0;
if (fence_out)
*fence_out = fence;
}
return rc;
}

View File

@ -1,76 +0,0 @@
#include <malloc.h>
#include "types.h"
#include "result.h"
#include "arm/atomics.h"
#include "kernel/svc.h"
#include "kernel/event.h"
#include "services/nv.h"
#include "nvidia/ioctl.h"
#include "nvidia/buffer.h"
#include "nvidia/address_space.h"
#include "nvidia/channel.h"
#include "nvidia/fence.h"
#include "nvidia/info.h"
#include "nvidia/gpu/cmd_list.h"
#include "nvidia/gpu/gpfifo.h"
#include "nvidia/gpu/zcull_ctx.h"
#include "nvidia/gpu/3d_ctx.h"
#include "nvidia/gpu/error_notifier.h"
#include "nvidia/gpu/gpu.h"
Result nvGpuCreate(NvGpu* g)
{
Result rc;
if (R_FAILED(nvInfoInit()))
return MAKERESULT(Module_Libnx, LibnxError_NvinfoFailedToInitialize);
if (R_FAILED(nvBufferInit())) {
nvInfoExit();
return MAKERESULT(Module_Libnx, LibnxError_NvbufFailedToInitialize);
}
rc = nvChannelCreate(&g->gpu_channel, "/dev/nvhost-gpu");
if (R_SUCCEEDED(rc))
rc = nvAddressSpaceCreate(&g->addr_space, nvInfoGetGpuCharacteristics()->big_page_size);
if (R_SUCCEEDED(rc))
rc = nvAddressSpaceBindToChannel(&g->addr_space, &g->gpu_channel);
if (R_SUCCEEDED(rc))
rc = nvChannelSetNvmapFd(&g->gpu_channel);
if (R_SUCCEEDED(rc))
rc = nvGpfifoCreate(&g->gpfifo, &g->gpu_channel);
if (R_SUCCEEDED(rc))
rc = nv3DContextCreate(&g->_3d_ctx, g);
if (R_SUCCEEDED(rc))
rc = nvErrorNotifierCreate(&g->error_notifier, g);
if (R_SUCCEEDED(rc))
rc = nvChannelSetPriority(&g->gpu_channel, NvChannelPriority_Medium);
if (R_SUCCEEDED(rc))
rc = nvZcullContextCreate(&g->zcull_ctx, g);
if (R_FAILED(rc))
nvGpuClose(g);
return rc;
}
void nvGpuClose(NvGpu* g)
{
nvErrorNotifierClose(&g->error_notifier);
nvChannelClose(&g->gpu_channel);
nvZcullContextClose(&g->zcull_ctx);
nv3DContextClose(&g->_3d_ctx);
nvGpfifoClose(&g->gpfifo);
nvAddressSpaceClose(&g->addr_space);
nvBufferExit();
nvInfoExit();
}

View File

@ -1,41 +0,0 @@
#include <malloc.h>
#include "types.h"
#include "result.h"
#include "arm/atomics.h"
#include "kernel/svc.h"
#include "kernel/event.h"
#include "services/nv.h"
#include "nvidia/ioctl.h"
#include "nvidia/buffer.h"
#include "nvidia/address_space.h"
#include "nvidia/channel.h"
#include "nvidia/fence.h"
#include "nvidia/info.h"
#include "nvidia/gpu/cmd_list.h"
#include "nvidia/gpu/gpfifo.h"
#include "nvidia/gpu/zcull_ctx.h"
#include "nvidia/gpu/3d_ctx.h"
#include "nvidia/gpu/error_notifier.h"
#include "nvidia/gpu/gpu.h"
Result nvZcullContextCreate(NvZcullContext* z, NvGpu* parent)
{
Result rc;
z->parent = parent;
rc = nvBufferCreate(
&z->ctx_buf, nvInfoGetZcullCtxSize(), 0x20000, NvKind_Pitch, false, true,
&parent->addr_space);
if (R_SUCCEEDED(rc))
rc = nvioctlChannel_ZCullBind(
parent->gpu_channel.fd, nvBufferGetGpuAddr(&z->ctx_buf),
NvZcullConfig_SeparateBuffer);
return rc;
}
void nvZcullContextClose(NvZcullContext* z) {
nvBufferFree(&z->ctx_buf);
}

View File

@ -0,0 +1,130 @@
#include <malloc.h>
#include "types.h"
#include "result.h"
#include "arm/atomics.h"
#include "kernel/svc.h"
#include "kernel/detect.h"
#include "services/nv.h"
#include "nvidia/ioctl.h"
#include "nvidia/map.h"
#include "nvidia/address_space.h"
#include "nvidia/fence.h"
#include "nvidia/gpu_channel.h"
Result nvGpuChannelCreate(NvGpuChannel* c, struct NvAddressSpace* as)
{
Result res;
res = nvChannelCreate(&c->base, "/dev/nvhost-gpu");
if (R_FAILED(res))
return res;
c->fence_incr = 0;
c->num_entries = 0;
res = nvioctlNvhostAsGpu_BindChannel(as->fd, c->base.fd);
if (R_SUCCEEDED(res))
res = nvioctlChannel_AllocGpfifoEx2(c->base.fd, GPFIFO_QUEUE_SIZE, 1, 0, 0, 0, 0, &c->fence);
if (R_SUCCEEDED(res))
res = nvioctlChannel_AllocObjCtx(c->base.fd, NvClassNumber_3D, 0, &c->object_id);
if (R_SUCCEEDED(res))
res = nvQueryEvent(c->base.fd, NvEventId_Gpu_ErrorNotifier, &c->error_event);
if (R_SUCCEEDED(res))
res = nvioctlChannel_SetErrorNotifier(c->base.fd, 1);
if (R_SUCCEEDED(res))
res = nvChannelSetPriority(&c->base, NvChannelPriority_Medium);
if (R_FAILED(res))
nvGpuChannelClose(c);
return res;
}
void nvGpuChannelClose(NvGpuChannel* c)
{
if (!c->base.has_init)
return;
if (c->error_event.revent != INVALID_HANDLE) {
nvioctlChannel_SetErrorNotifier(c->base.fd, 0);
eventClose(&c->error_event);
}
nvChannelClose(&c->base);
}
Result nvGpuChannelZcullBind(NvGpuChannel* c, iova_t iova)
{
return nvioctlChannel_ZCullBind(c->base.fd, iova, NvZcullConfig_SeparateBuffer);
}
Result nvGpuChannelAppendEntry(NvGpuChannel* c, iova_t start, size_t num_cmds, u32 flags, u32 flush_threshold)
{
Result res;
if (flush_threshold >= GPFIFO_QUEUE_SIZE)
return MAKERESULT(Module_Libnx, LibnxError_BadInput);
if (c->num_entries >= (GPFIFO_QUEUE_SIZE-flush_threshold)) {
res = nvGpuChannelKickoff(c);
if (R_FAILED(res))
return res;
}
if (c->num_entries >= GPFIFO_QUEUE_SIZE)
return MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
nvioctl_gpfifo_entry* entry = &c->entries[c->num_entries++];
entry->desc = start;
entry->desc32[1] |= flags | (num_cmds << 10);
return 0;
}
static Result _nvGpuChannelKickoffRaw(NvGpuChannel* c, u32 flags)
{
NvFence fence;
fence.id = 0;
fence.value = c->fence_incr;
if (kernelAbove400())
return nvioctlChannel_KickoffPb(c->base.fd, c->entries, c->num_entries, flags, &fence);
else
return nvioctlChannel_SubmitGpfifo(c->base.fd, c->entries, c->num_entries, flags, &fence);
}
Result nvGpuChannelKickoff(NvGpuChannel* c)
{
if (!c->num_entries)
return 0;
u32 flags = BIT(2);
if (c->fence_incr)
flags |= BIT(8);
Result res;
for (;;)
{
res = _nvGpuChannelKickoffRaw(c, flags);
if (res != MAKERESULT(Module_LibnxNvidia, LibnxNvidiaError_Busy))
break;
svcSleepThread(100000000);
}
if (R_SUCCEEDED(res)) {
c->fence.value += c->fence_incr;
c->fence_incr = 0;
c->num_entries = 0;
}
return res;
}
Result nvGpuChannelGetErrorNotification(NvGpuChannel* c, NvError* error)
{
Result res = eventWait(&c->error_event, 0);
if (R_SUCCEEDED(res))
res = nvioctlChannel_GetErrorNotification(c->base.fd, error);
return res;
}

View File

@ -5,7 +5,6 @@
#include "kernel/svc.h"
#include "services/nv.h"
#include "nvidia/ioctl.h"
#include "nvidia/buffer.h"
#include "nvidia/info.h"
static u32 g_ctrlgpu_fd = -1;

102
nx/source/nvidia/map.c Normal file
View File

@ -0,0 +1,102 @@
#include <malloc.h>
#include "types.h"
#include "result.h"
#include "arm/atomics.h"
#include "arm/cache.h"
#include "kernel/svc.h"
#include "services/nv.h"
#include "nvidia/ioctl.h"
#include "nvidia/map.h"
static u32 g_nvmap_fd = -1;
static u64 g_refCnt;
Result nvMapInit(void)
{
Result rc;
if (atomicIncrement64(&g_refCnt) > 0)
return 0;
rc = nvOpen(&g_nvmap_fd, "/dev/nvmap");
if (R_FAILED(rc))
atomicDecrement64(&g_refCnt);
return rc;
}
void nvMapExit(void)
{
if (atomicDecrement64(&g_refCnt) == 0)
{
if (g_nvmap_fd != -1)
nvClose(g_nvmap_fd);
g_nvmap_fd = -1;
}
}
u32 nvMapGetFd(void)
{
return g_nvmap_fd;
}
Result nvMapCreate(NvMap* m, void* cpu_addr, u32 size, u32 align, NvKind kind, bool is_cpu_cacheable)
{
Result rc;
if (align < 0x1000)
align = 0x1000;
if (align & (align-1))
return MAKERESULT(Module_Libnx, LibnxError_BadInput);
if (!size || (size & 0xFFF))
return MAKERESULT(Module_Libnx, LibnxError_BadInput);
if (!cpu_addr || ((uintptr_t)cpu_addr & 0xFFF))
return MAKERESULT(Module_Libnx, LibnxError_BadInput);
m->has_init = true;
m->is_cpu_cacheable = is_cpu_cacheable;
m->size = size;
m->handle = -1;
m->cpu_addr = cpu_addr;
m->kind = kind;
rc = nvioctlNvmap_Create(g_nvmap_fd, size, &m->handle);
if (R_SUCCEEDED(rc))
rc = nvioctlNvmap_Alloc(g_nvmap_fd, m->handle,
0, is_cpu_cacheable ? 1 : 0, align, kind, m->cpu_addr);
if (R_SUCCEEDED(rc) && !is_cpu_cacheable) {
armDCacheFlush(m->cpu_addr, m->size);
svcSetMemoryAttribute(m->cpu_addr, m->size, 8, 8);
}
if (R_SUCCEEDED(rc))
rc = nvioctlNvmap_GetId(g_nvmap_fd, m->handle, &m->id);
if (R_FAILED(rc))
nvMapFree(m);
return rc;
}
void nvMapFree(NvMap* m)
{
if (!m->has_init)
return;
if (m->handle != -1) {
nvioctlNvmap_Free(g_nvmap_fd, m->handle);
m->handle = -1;
}
if (m->cpu_addr) {
if (!m->is_cpu_cacheable)
svcSetMemoryAttribute(m->cpu_addr, m->size, 8, 0);
m->cpu_addr = NULL;
}
m->has_init = false;
}