github.com/racerxdl/gonx@v0.0.0-20210103083128-c5afc43bcbd2/services/gpu/buffer.go (about)

     1  package gpu
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/racerxdl/gonx/nx/nxerrors"
     6  	"github.com/racerxdl/gonx/nx/nxtypes"
     7  	"github.com/racerxdl/gonx/services/nv"
     8  	"github.com/racerxdl/gonx/svc"
     9  	"unsafe"
    10  )
    11  
    12  type Buffer struct {
    13  	NvMapHandle uint32
    14  	Size        uintptr
    15  	Alignment   uint32
    16  	Kind        uint8
    17  }
    18  
    19  func InitializeFromId(id uint32) (*Buffer, error) {
    20  	if gpuInitializations <= 0 {
    21  		return nil, nxerrors.GPUNotInitialized
    22  	}
    23  
    24  	buff := &Buffer{}
    25  
    26  	nvIocFromIdArgs := nvmapIocGetIdArgs{
    27  		id: id,
    28  	}
    29  
    30  	handle, err := nv.Ioctl(nvmapFd, NVMAP_IOC_FROM_ID, unsafe.Pointer(&nvIocFromIdArgs), unsafe.Sizeof(nvIocFromIdArgs))
    31  	if err != nil {
    32  		return nil, err
    33  	}
    34  
    35  	if handle != 0 {
    36  		return nil, nxerrors.IPCError{
    37  			Message: "error calling NVMAP_IOC_FROM_ID",
    38  			Result:  uint64(handle),
    39  		}
    40  	}
    41  
    42  	buff.NvMapHandle = nvIocFromIdArgs.handle
    43  
    44  	nvParam := nvmapIocParamArgs{
    45  		handle: buff.NvMapHandle,
    46  		param:  1, // SIZE
    47  	}
    48  
    49  	handle, err = nv.Ioctl(nvmapFd, NVMAP_IOC_PARAM, unsafe.Pointer(&nvParam), unsafe.Sizeof(nvParam))
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  
    54  	if handle != 0 {
    55  		return nil, nxerrors.IPCError{
    56  			Message: "error calling NVMAP_IOC_PARAM",
    57  			Result:  uint64(handle),
    58  		}
    59  	}
    60  
    61  	buff.Size = uintptr(nvParam.value)
    62  
    63  	nvParam.param = 2 // ALIGNMENT
    64  	handle, err = nv.Ioctl(nvmapFd, NVMAP_IOC_PARAM, unsafe.Pointer(&nvParam), unsafe.Sizeof(nvParam))
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  
    69  	if handle != 0 {
    70  		return nil, nxerrors.IPCError{
    71  			Message: "error calling NVMAP_IOC_PARAM",
    72  			Result:  uint64(handle),
    73  		}
    74  	}
    75  
    76  	buff.Alignment = nvParam.value
    77  
    78  	nvParam.param = 5 // KIND
    79  	handle, err = nv.Ioctl(nvmapFd, NVMAP_IOC_PARAM, unsafe.Pointer(&nvParam), unsafe.Sizeof(nvParam))
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  
    84  	if handle != 0 {
    85  		return nil, nxerrors.IPCError{
    86  			Message: "error calling NVMAP_IOC_PARAM",
    87  			Result:  uint64(handle),
    88  		}
    89  	}
    90  
    91  	buff.Kind = uint8(nvParam.value)
    92  
    93  	return buff, nil
    94  }
    95  
    96  func (b *Buffer) GetID() (id uint32, err error) {
    97  	if gpuInitializations <= 0 {
    98  		return 0, nxerrors.GPUNotInitialized
    99  	}
   100  
   101  	nvIdArgs := nvmapIocGetIdArgs{
   102  		handle: b.NvMapHandle,
   103  	}
   104  
   105  	handle, err := nv.Ioctl(nvmapFd, NVMAP_IOC_GET_ID, unsafe.Pointer(&nvIdArgs), unsafe.Sizeof(nvIdArgs))
   106  
   107  	if err != nil {
   108  		return 0, err
   109  	}
   110  
   111  	if handle != 0 {
   112  		return 0, nxerrors.IPCError{
   113  			Message: "error calling NVMAP_IOC_GET_ID",
   114  			Result:  uint64(handle),
   115  		}
   116  	}
   117  	return nvIdArgs.id, nil
   118  }
   119  
   120  func (b *Buffer) Destroy() (refCount uint32, flags uint32, err error) {
   121  	if gpuInitializations <= 0 {
   122  		return 0, 0, nxerrors.GPUNotInitialized
   123  	}
   124  
   125  	nvmFree := nvmapIocFreeArgs{
   126  		handle: b.NvMapHandle,
   127  	}
   128  
   129  	handle, err := nv.Ioctl(nvmapFd, NVMAP_IOC_FREE, unsafe.Pointer(&nvmFree), unsafe.Sizeof(nvmFree))
   130  
   131  	if err != nil {
   132  		return 0, 0, err
   133  	}
   134  
   135  	if handle != 0 {
   136  		return 0, 0, nxerrors.IPCError{
   137  			Message: "error calling NVMAP_IOC_FREE",
   138  			Result:  uint64(handle),
   139  		}
   140  	}
   141  
   142  	return uint32(nvmFree.refcount), nvmFree.flags, nil
   143  }
   144  
   145  // CreateBuffer creates a buffer in GPU
   146  // equivalent to nvMapCreate on libnx
   147  func CreateBuffer(addr unsafe.Pointer, size uintptr, heapMask, alignment uint32, kind nv.Kind) (*Buffer, error) {
   148  	if gpuInitializations <= 0 {
   149  		return nil, nxerrors.GPUNotInitialized
   150  	}
   151  
   152  	if alignment < 0x1000 {
   153  		alignment = 0x1000
   154  	}
   155  
   156  	uaddr := uintptr(addr)
   157  
   158  	if uint64(uaddr)&(uint64(alignment)-1) != 0 {
   159  		// GPU Driver crashes if this is not checked
   160  		fmt.Println("A")
   161  		return nil, nxerrors.GPUBufferUnaligned
   162  	}
   163  
   164  	if size == 0 || (size&0xFFF > 0) {
   165  		// GPU Driver crashes if this is not checked
   166  		fmt.Println("B")
   167  		return nil, nxerrors.GPUBufferUnaligned
   168  	}
   169  
   170  	if addr == nil || (uintptr(addr)&0xFFF > 0) {
   171  		// GPU Driver crashes if this is not checked
   172  		fmt.Println("C")
   173  		return nil, nxerrors.GPUBufferUnaligned
   174  	}
   175  
   176  	gpuB := &Buffer{
   177  		Size:      size,
   178  		Kind:      uint8(kind),
   179  		Alignment: alignment,
   180  	}
   181  
   182  	nvmCreate := nvmapIocCreateArgs{
   183  		size: uint32(size),
   184  	}
   185  
   186  	handle, err := nv.Ioctl(nvmapFd, NVMAP_IOC_CREATE, unsafe.Pointer(&nvmCreate), unsafe.Sizeof(nvmCreate))
   187  	if err != nil {
   188  		return nil, err
   189  	}
   190  	if handle != 0 {
   191  		return nil, nxerrors.IPCError{
   192  			Message: "error calling NVMAP_IOC_CREATE",
   193  			Result:  uint64(handle),
   194  		}
   195  	}
   196  
   197  	gpuB.NvMapHandle = nvmCreate.handle
   198  
   199  	err = nvmapAlloc(nvmCreate.handle, heapMask, 0, alignment, uint32(kind), uintptr(addr))
   200  	if err != nil {
   201  		return nil, err
   202  	}
   203  
   204  	r := svc.SetMemoryAttribute(uintptr(addr), uintptr(size), 0x8, 0x8)
   205  	if r != nxtypes.ResultOK {
   206  		return nil, nxerrors.CannotSetMemoryAttributes
   207  	}
   208  
   209  	return gpuB, nil
   210  }
   211  
   212  func nvmapAlloc(nvmapHandle, heapMask, flags, align, kind uint32, addr uintptr) error {
   213  	nvmAlloc := nvmapIocAllocArgs{
   214  		handle:   nvmapHandle,
   215  		heapmask: heapMask,
   216  		flags:    flags,
   217  		align:    align,
   218  		kind:     uint8(kind),
   219  		addr:     uint64(addr),
   220  	}
   221  
   222  	handle, err := nv.Ioctl(nvmapFd, NVMAP_IOC_ALLOC, unsafe.Pointer(&nvmAlloc), unsafe.Sizeof(nvmAlloc))
   223  	if err != nil {
   224  		return err
   225  	}
   226  	if handle != 0 {
   227  		return nxerrors.IPCError{
   228  			Message: "error calling NVMAP_IOC_ALLOC",
   229  			Result:  uint64(handle),
   230  		}
   231  	}
   232  
   233  	return nil
   234  }