private NvInternalResult MapCommandBuffer(Span <byte> arguments) { int headerSize = Unsafe.SizeOf <MapCommandBufferArguments>(); MapCommandBufferArguments commandBufferHeader = MemoryMarshal.Cast <byte, MapCommandBufferArguments>(arguments)[0]; Span <CommandBufferHandle> commandBufferEntries = MemoryMarshal.Cast <byte, CommandBufferHandle>(arguments.Slice(headerSize)).Slice(0, commandBufferHeader.NumEntries); MemoryManager gmm = NvHostAsGpuDeviceFile.GetAddressSpaceContext(Context).Gmm; foreach (ref CommandBufferHandle commandBufferEntry in commandBufferEntries) { NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, commandBufferEntry.MapHandle); if (map == null) { Logger.Warning?.Print(LogClass.ServiceNv, $"Invalid handle 0x{commandBufferEntry.MapHandle:x8}!"); return(NvInternalResult.InvalidInput); } lock (map) { if (map.DmaMapAddress == 0) { ulong va = _memoryAllocator.GetFreeAddress((ulong)map.Size, out ulong freeAddressStartPosition, 1, MemoryManager.PageSize); if (va != NvMemoryAllocator.PteUnmapped && va <= uint.MaxValue && (va + (uint)map.Size) <= uint.MaxValue) { _memoryAllocator.AllocateRange(va, (uint)map.Size, freeAddressStartPosition); gmm.Map((ulong)map.Address, va, (uint)map.Size); map.DmaMapAddress = (long)va; } else { map.DmaMapAddress = unchecked ((long)NvMemoryAllocator.PteUnmapped); } } commandBufferEntry.MapAddress = (int)map.DmaMapAddress; } } return(NvInternalResult.Success); }
private NvInternalResult Submit(Span <byte> arguments) { SubmitArguments submitHeader = GetSpanAndSkip <SubmitArguments>(ref arguments, 1)[0]; Span <CommandBuffer> commandBuffers = GetSpanAndSkip <CommandBuffer>(ref arguments, submitHeader.CmdBufsCount); Span <Reloc> relocs = GetSpanAndSkip <Reloc>(ref arguments, submitHeader.RelocsCount); Span <uint> relocShifts = GetSpanAndSkip <uint>(ref arguments, submitHeader.RelocsCount); Span <SyncptIncr> syncptIncrs = GetSpanAndSkip <SyncptIncr>(ref arguments, submitHeader.SyncptIncrsCount); Span <SyncptIncr> waitChecks = GetSpanAndSkip <SyncptIncr>(ref arguments, submitHeader.SyncptIncrsCount); // ? Span <Fence> fences = GetSpanAndSkip <Fence>(ref arguments, submitHeader.FencesCount); lock (_device) { for (int i = 0; i < syncptIncrs.Length; i++) { SyncptIncr syncptIncr = syncptIncrs[i]; uint id = syncptIncr.Id; fences[i].Id = id; fences[i].Thresh = Context.Device.System.HostSyncpoint.IncrementSyncpointMax(id, syncptIncr.Incrs); } foreach (CommandBuffer commandBuffer in commandBuffers) { NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, commandBuffer.Mem); var data = _memory.GetSpan((ulong)map.Address + commandBuffer.Offset, commandBuffer.WordsCount * 4); _device.Host1x.Submit(MemoryMarshal.Cast <byte, int>(data)); } } fences[0].Thresh = Context.Device.System.HostSyncpoint.IncrementSyncpointMax(fences[0].Id, 1); Span <int> tmpCmdBuff = stackalloc int[1]; tmpCmdBuff[0] = (4 << 28) | (int)fences[0].Id; _device.Host1x.Submit(tmpCmdBuff); return(NvInternalResult.Success); }
private static int Remap(ServiceCtx Context) { long InputPosition = Context.Request.GetBufferType0x21().Position; NvGpuASRemap Args = AMemoryHelper.Read <NvGpuASRemap>(Context.Memory, InputPosition); NvGpuVmm Vmm = GetVmm(Context); NvMapHandle Map = NvMapIoctl.GetNvMapWithFb(Context, Args.NvMapHandle); if (Map == null) { Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{Args.NvMapHandle:x8}!"); return(NvResult.InvalidInput); } //FIXME: This is most likely wrong... Vmm.Map(Map.Address, (long)(uint)Args.Offset << 16, (long)(uint)Args.Pages << 16); return(NvResult.Success); }
private NvInternalResult Submit(Span <byte> arguments) { int headerSize = Unsafe.SizeOf <SubmitArguments>(); SubmitArguments submitHeader = MemoryMarshal.Cast <byte, SubmitArguments>(arguments)[0]; Span <CommandBuffer> commandBufferEntries = MemoryMarshal.Cast <byte, CommandBuffer>(arguments.Slice(headerSize)).Slice(0, submitHeader.CmdBufsCount); MemoryManager gmm = NvHostAsGpuDeviceFile.GetAddressSpaceContext(Context).Gmm; foreach (CommandBuffer commandBufferEntry in commandBufferEntries) { NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, commandBufferEntry.MemoryId); int[] commandBufferData = new int[commandBufferEntry.WordsCount]; for (int offset = 0; offset < commandBufferData.Length; offset++) { commandBufferData[offset] = _memory.ReadInt32(map.Address + commandBufferEntry.Offset + offset * 4); } // TODO: Submit command to engines. } return(NvInternalResult.Success); }
private NvInternalResult MapBufferEx(ref MapBufferExArguments arguments) { const string mapErrorMsg = "Failed to map fixed buffer with offset 0x{0:x16}, size 0x{1:x16} and alignment 0x{2:x16}!"; AddressSpaceContext addressSpaceContext = GetAddressSpaceContext(Context); ulong physicalAddress; if ((arguments.Flags & AddressSpaceFlags.RemapSubRange) != 0) { lock (addressSpaceContext) { if (addressSpaceContext.TryGetMapPhysicalAddress(arguments.Offset, out physicalAddress)) { ulong virtualAddress = arguments.Offset + arguments.BufferOffset; physicalAddress += arguments.BufferOffset; addressSpaceContext.Gmm.Map(physicalAddress, virtualAddress, arguments.MappingSize); return(NvInternalResult.Success); } else { Logger.Warning?.Print(LogClass.ServiceNv, $"Address 0x{arguments.Offset:x16} not mapped!"); return(NvInternalResult.InvalidInput); } } } NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, arguments.NvMapHandle); if (map == null) { Logger.Warning?.Print(LogClass.ServiceNv, $"Invalid NvMap handle 0x{arguments.NvMapHandle:x8}!"); return(NvInternalResult.InvalidInput); } ulong pageSize = (ulong)arguments.PageSize; if (pageSize == 0) { pageSize = (ulong)map.Align; } physicalAddress = map.Address + arguments.BufferOffset; ulong size = arguments.MappingSize; if (size == 0) { size = (uint)map.Size; } NvInternalResult result = NvInternalResult.Success; lock (addressSpaceContext) { // Note: When the fixed offset flag is not set, // the Offset field holds the alignment size instead. bool virtualAddressAllocated = (arguments.Flags & AddressSpaceFlags.FixedOffset) == 0; if (!virtualAddressAllocated) { if (addressSpaceContext.ValidateFixedBuffer(arguments.Offset, size, pageSize)) { addressSpaceContext.Gmm.Map(physicalAddress, arguments.Offset, size); } else { string message = string.Format(mapErrorMsg, arguments.Offset, size, pageSize); Logger.Warning?.Print(LogClass.ServiceNv, message); result = NvInternalResult.InvalidInput; } } else { ulong va = _memoryAllocator.GetFreeAddress(size, out ulong freeAddressStartPosition, pageSize); if (va != NvMemoryAllocator.PteUnmapped) { _memoryAllocator.AllocateRange(va, size, freeAddressStartPosition); } addressSpaceContext.Gmm.Map(physicalAddress, va, size); arguments.Offset = va; } if (arguments.Offset == NvMemoryAllocator.PteUnmapped) { arguments.Offset = 0; Logger.Warning?.Print(LogClass.ServiceNv, $"Failed to map size 0x{size:x16}!"); result = NvInternalResult.InvalidInput; } else { addressSpaceContext.AddMap(arguments.Offset, size, physicalAddress, virtualAddressAllocated); } } return(result); }
private void PostFrameBuffer(Layer layer, BufferItem item) { int frameBufferWidth = item.GraphicBuffer.Object.Width; int frameBufferHeight = item.GraphicBuffer.Object.Height; int nvMapHandle = item.GraphicBuffer.Object.Buffer.Surfaces[0].NvMapHandle; if (nvMapHandle == 0) { nvMapHandle = item.GraphicBuffer.Object.Buffer.NvMapId; } ulong bufferOffset = (ulong)item.GraphicBuffer.Object.Buffer.Surfaces[0].Offset; NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(layer.Owner, nvMapHandle); ulong frameBufferAddress = map.Address + bufferOffset; Format format = ConvertColorFormat(item.GraphicBuffer.Object.Buffer.Surfaces[0].ColorFormat); int bytesPerPixel = format == Format.B5G6R5Unorm || format == Format.R4G4B4A4Unorm ? 2 : 4; int gobBlocksInY = 1 << item.GraphicBuffer.Object.Buffer.Surfaces[0].BlockHeightLog2; // Note: Rotation is being ignored. Rect cropRect = item.Crop; bool flipX = item.Transform.HasFlag(NativeWindowTransform.FlipX); bool flipY = item.Transform.HasFlag(NativeWindowTransform.FlipY); AspectRatio aspectRatio = _device.Configuration.AspectRatio; bool isStretched = aspectRatio == AspectRatio.Stretched; ImageCrop crop = new ImageCrop( cropRect.Left, cropRect.Right, cropRect.Top, cropRect.Bottom, flipX, flipY, isStretched, aspectRatio.ToFloatX(), aspectRatio.ToFloatY()); TextureCallbackInformation textureCallbackInformation = new TextureCallbackInformation { Layer = layer, Item = item }; _device.Gpu.Window.EnqueueFrameThreadSafe( layer.Owner, frameBufferAddress, frameBufferWidth, frameBufferHeight, 0, false, gobBlocksInY, format, bytesPerPixel, crop, AcquireBuffer, ReleaseBuffer, textureCallbackInformation); if (item.Fence.FenceCount == 0) { _device.Gpu.Window.SignalFrameReady(); _device.Gpu.GPFifo.Interrupt(); } else { item.Fence.RegisterCallback(_device.Gpu, (x) => { _device.Gpu.Window.SignalFrameReady(); _device.Gpu.GPFifo.Interrupt(); }); } }
private void PostFrameBuffer(Layer layer, BufferItem item) { int frameBufferWidth = item.GraphicBuffer.Object.Width; int frameBufferHeight = item.GraphicBuffer.Object.Height; int nvMapHandle = item.GraphicBuffer.Object.Buffer.Surfaces[0].NvMapHandle; if (nvMapHandle == 0) { nvMapHandle = item.GraphicBuffer.Object.Buffer.NvMapId; } int bufferOffset = item.GraphicBuffer.Object.Buffer.Surfaces[0].Offset; NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(layer.Owner, nvMapHandle); ulong frameBufferAddress = (ulong)(map.Address + bufferOffset); Format format = ConvertColorFormat(item.GraphicBuffer.Object.Buffer.Surfaces[0].ColorFormat); int bytesPerPixel = format == Format.B5G6R5Unorm || format == Format.R4G4B4A4Unorm ? 2 : 4; int gobBlocksInY = 1 << item.GraphicBuffer.Object.Buffer.Surfaces[0].BlockHeightLog2; // Note: Rotation is being ignored. Rect cropRect = item.Crop; bool flipX = item.Transform.HasFlag(NativeWindowTransform.FlipX); bool flipY = item.Transform.HasFlag(NativeWindowTransform.FlipY); ImageCrop crop = new ImageCrop( cropRect.Left, cropRect.Right, cropRect.Top, cropRect.Bottom, flipX, flipY); // Enforce that dequeueBuffer wait for the next vblank _vblankFence.NvFences[0].Value++; TextureCallbackInformation textureCallbackInformation = new TextureCallbackInformation { Layer = layer, Item = item, Fence = _vblankFence }; _device.Gpu.Window.EnqueueFrameThreadSafe( frameBufferAddress, frameBufferWidth, frameBufferHeight, 0, false, gobBlocksInY, format, bytesPerPixel, crop, AcquireBuffer, ReleaseBuffer, textureCallbackInformation); }
private static int MapBufferEx(ServiceCtx Context) { const string MapErrorMsg = "Failed to map fixed buffer with offset 0x{0:x16} and size 0x{1:x16}!"; long InputPosition = Context.Request.GetBufferType0x21().Position; long OutputPosition = Context.Request.GetBufferType0x22().Position; NvGpuASMapBufferEx Args = AMemoryHelper.Read <NvGpuASMapBufferEx>(Context.Memory, InputPosition); NvGpuASCtx ASCtx = GetASCtx(Context); NvMapHandle Map = NvMapIoctl.GetNvMapWithFb(Context, Args.NvMapHandle); if (Map == null) { Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{Args.NvMapHandle:x8}!"); return(NvResult.InvalidInput); } long PA; if ((Args.Flags & FlagRemapSubRange) != 0) { lock (ASCtx) { if (ASCtx.TryGetMapPhysicalAddress(Args.Offset, out PA)) { long VA = Args.Offset + Args.BufferOffset; PA += Args.BufferOffset; if (ASCtx.Vmm.Map(PA, VA, Args.MappingSize) < 0) { string Msg = string.Format(MapErrorMsg, VA, Args.MappingSize); Context.Ns.Log.PrintWarning(LogClass.ServiceNv, Msg); return(NvResult.InvalidInput); } return(NvResult.Success); } else { Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Address 0x{Args.Offset:x16} not mapped!"); return(NvResult.InvalidInput); } } } PA = Map.Address + Args.BufferOffset; long Size = Args.MappingSize; if (Size == 0) { Size = (uint)Map.Size; } int Result = NvResult.Success; lock (ASCtx) { //Note: When the fixed offset flag is not set, //the Offset field holds the alignment size instead. bool VaAllocated = (Args.Flags & FlagFixedOffset) == 0; if (!VaAllocated) { if (ASCtx.ValidateFixedBuffer(Args.Offset, Size)) { Args.Offset = ASCtx.Vmm.Map(PA, Args.Offset, Size); } else { string Msg = string.Format(MapErrorMsg, Args.Offset, Size); Context.Ns.Log.PrintWarning(LogClass.ServiceNv, Msg); Result = NvResult.InvalidInput; } } else { Args.Offset = ASCtx.Vmm.Map(PA, Size); } if (Args.Offset < 0) { Args.Offset = 0; Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Failed to map size 0x{Size:x16}!"); Result = NvResult.InvalidInput; } else { ASCtx.AddMap(Args.Offset, Size, PA, VaAllocated); } } AMemoryHelper.Write(Context.Memory, OutputPosition, Args); return(Result); }
private static int MapBufferEx(ServiceCtx Context) { long InputPosition = Context.Request.GetBufferType0x21().Position; long OutputPosition = Context.Request.GetBufferType0x22().Position; NvGpuASMapBufferEx Args = AMemoryHelper.Read <NvGpuASMapBufferEx>(Context.Memory, InputPosition); NvGpuVmm Vmm = GetVmm(Context); NvMapHandle Map = NvMapIoctl.GetNvMapWithFb(Context, Args.NvMapHandle); if (Map == null) { Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{Args.NvMapHandle:x8}!"); return(NvResult.InvalidInput); } long PA = Map.Address + Args.BufferOffset; long Size = Args.MappingSize; if (Size == 0) { Size = (uint)Map.Size; } int Result = NvResult.Success; //Note: When the fixed offset flag is not set, //the Offset field holds the alignment size instead. if ((Args.Flags & FlagFixedOffset) != 0) { long MapEnd = Args.Offset + Args.MappingSize; if ((ulong)MapEnd <= (ulong)Args.Offset) { Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Offset 0x{Args.Offset:x16} and size 0x{Args.MappingSize:x16} results in a overflow!"); return(NvResult.InvalidInput); } if ((Args.Offset & NvGpuVmm.PageMask) != 0) { Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"Offset 0x{Args.Offset:x16} is not page aligned!"); return(NvResult.InvalidInput); } Args.Offset = Vmm.Map(PA, Args.Offset, Size); } else { Args.Offset = Vmm.Map(PA, Size); if (Args.Offset < 0) { Args.Offset = 0; Context.Ns.Log.PrintWarning(LogClass.ServiceNv, $"No memory to map size {Args.MappingSize:x16}!"); Result = NvResult.InvalidInput; } } AMemoryHelper.Write(Context.Memory, OutputPosition, Args); return(Result); }
private static int MapBufferEx(ServiceCtx context) { const string mapErrorMsg = "Failed to map fixed buffer with offset 0x{0:x16} and size 0x{1:x16}!"; long inputPosition = context.Request.GetBufferType0x21().Position; long outputPosition = context.Request.GetBufferType0x22().Position; NvGpuASMapBufferEx args = MemoryHelper.Read <NvGpuASMapBufferEx>(context.Memory, inputPosition); NvGpuASCtx asCtx = GetASCtx(context); NvMapHandle map = NvMapIoctl.GetNvMapWithFb(context, args.NvMapHandle); if (map == null) { Logger.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{args.NvMapHandle:x8}!"); return(NvResult.InvalidInput); } long pa; if ((args.Flags & FlagRemapSubRange) != 0) { lock (asCtx) { if (asCtx.TryGetMapPhysicalAddress(args.Offset, out pa)) { long va = args.Offset + args.BufferOffset; pa += args.BufferOffset; if (asCtx.Vmm.Map(pa, va, args.MappingSize) < 0) { string msg = string.Format(mapErrorMsg, va, args.MappingSize); Logger.PrintWarning(LogClass.ServiceNv, msg); return(NvResult.InvalidInput); } return(NvResult.Success); } else { Logger.PrintWarning(LogClass.ServiceNv, $"Address 0x{args.Offset:x16} not mapped!"); return(NvResult.InvalidInput); } } } pa = map.Address + args.BufferOffset; long size = args.MappingSize; if (size == 0) { size = (uint)map.Size; } int result = NvResult.Success; lock (asCtx) { // Note: When the fixed offset flag is not set, // the Offset field holds the alignment size instead. bool vaAllocated = (args.Flags & FlagFixedOffset) == 0; if (!vaAllocated) { if (asCtx.ValidateFixedBuffer(args.Offset, size)) { args.Offset = asCtx.Vmm.Map(pa, args.Offset, size); } else { string msg = string.Format(mapErrorMsg, args.Offset, size); Logger.PrintWarning(LogClass.ServiceNv, msg); result = NvResult.InvalidInput; } } else { args.Offset = asCtx.Vmm.Map(pa, size); } if (args.Offset < 0) { args.Offset = 0; Logger.PrintWarning(LogClass.ServiceNv, $"Failed to map size 0x{size:x16}!"); result = NvResult.InvalidInput; } else { asCtx.AddMap(args.Offset, size, pa, vaAllocated); } } MemoryHelper.Write(context.Memory, outputPosition, args); return(result); }
private NvInternalResult MapBufferEx(ref MapBufferExArguments arguments) { const string mapErrorMsg = "Failed to map fixed buffer with offset 0x{0:x16} and size 0x{1:x16}!"; AddressSpaceContext addressSpaceContext = GetAddressSpaceContext(Owner); NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(Owner, arguments.NvMapHandle, true); if (map == null) { Logger.PrintWarning(LogClass.ServiceNv, $"Invalid NvMap handle 0x{arguments.NvMapHandle:x8}!"); return(NvInternalResult.InvalidInput); } long physicalAddress; if ((arguments.Flags & AddressSpaceFlags.RemapSubRange) != 0) { lock (addressSpaceContext) { if (addressSpaceContext.TryGetMapPhysicalAddress(arguments.Offset, out physicalAddress)) { long virtualAddress = arguments.Offset + arguments.BufferOffset; physicalAddress += arguments.BufferOffset; if (addressSpaceContext.Vmm.Map(physicalAddress, virtualAddress, arguments.MappingSize) < 0) { string message = string.Format(mapErrorMsg, virtualAddress, arguments.MappingSize); Logger.PrintWarning(LogClass.ServiceNv, message); return(NvInternalResult.InvalidInput); } return(NvInternalResult.Success); } else { Logger.PrintWarning(LogClass.ServiceNv, $"Address 0x{arguments.Offset:x16} not mapped!"); return(NvInternalResult.InvalidInput); } } } physicalAddress = map.Address + arguments.BufferOffset; long size = arguments.MappingSize; if (size == 0) { size = (uint)map.Size; } NvInternalResult result = NvInternalResult.Success; lock (addressSpaceContext) { // Note: When the fixed offset flag is not set, // the Offset field holds the alignment size instead. bool virtualAddressAllocated = (arguments.Flags & AddressSpaceFlags.FixedOffset) == 0; if (!virtualAddressAllocated) { if (addressSpaceContext.ValidateFixedBuffer(arguments.Offset, size)) { arguments.Offset = addressSpaceContext.Vmm.Map(physicalAddress, arguments.Offset, size); } else { string message = string.Format(mapErrorMsg, arguments.Offset, size); Logger.PrintWarning(LogClass.ServiceNv, message); result = NvInternalResult.InvalidInput; } } else { arguments.Offset = addressSpaceContext.Vmm.Map(physicalAddress, size); } if (arguments.Offset < 0) { arguments.Offset = 0; Logger.PrintWarning(LogClass.ServiceNv, $"Failed to map size 0x{size:x16}!"); result = NvInternalResult.InvalidInput; } else { addressSpaceContext.AddMap(arguments.Offset, size, physicalAddress, virtualAddressAllocated); } } return(result); }