mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-21 12:32:40 +02:00
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:
parent
85a20f43dc
commit
5fe01c065a
@ -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
|
||||
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
@ -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);
|
||||
|
@ -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);
|
@ -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);
|
@ -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);
|
@ -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);
|
@ -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);
|
@ -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);
|
43
nx/include/switch/nvidia/gpu_channel.h
Normal file
43
nx/include/switch/nvidia/gpu_channel.h
Normal 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;
|
||||
}
|
34
nx/include/switch/nvidia/map.h
Normal file
34
nx/include/switch/nvidia/map.h
Normal 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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
@ -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());
|
||||
}
|
||||
|
@ -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
|
||||
}
|
@ -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];
|
||||
}
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
@ -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();
|
||||
}
|
@ -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);
|
||||
}
|
130
nx/source/nvidia/gpu_channel.c
Normal file
130
nx/source/nvidia/gpu_channel.c
Normal 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;
|
||||
}
|
@ -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
102
nx/source/nvidia/map.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user