mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-21 12:32:40 +02:00
130 lines
3.3 KiB
C
130 lines
3.3 KiB
C
#include <malloc.h>
|
|
#include "types.h"
|
|
#include "result.h"
|
|
#include "kernel/svc.h"
|
|
#include "runtime/hosversion.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, NvChannelPriority prio)
|
|
{
|
|
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, prio);
|
|
|
|
if (R_FAILED(res))
|
|
nvGpuChannelClose(c);
|
|
|
|
return res;
|
|
}
|
|
|
|
void nvGpuChannelClose(NvGpuChannel* c)
|
|
{
|
|
if (!c->base.has_init)
|
|
return;
|
|
|
|
if (eventActive(&c->error_event)) {
|
|
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 (hosversionAtLeast(4,0,0))
|
|
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;
|
|
}
|