Compare commits

..

4 Commits

Author SHA1 Message Date
gdkchan
153b8bfc7c Implement support for masked stencil clears on Vulkan (#5589)
* Implement support for masked stencil clears on Vulkan

* PR feedback
2023-08-18 05:25:54 +00:00
Mary
c6a699414a infra: add missing quotes around @ developers in reviewers.yml 2023-08-17 19:34:48 +02:00
TSRBerry
2563f88de0 Convert app and installation ids to int (#5587) 2023-08-17 19:26:21 +02:00
Ac_K
b0b7843d5c mm: Migrate service in Horizon project (#5580)
* mm: Migrate service in Horizon project

This PR migrate the `mm:u` service to the Horizon project, things were checked by some RE aswell, that's why some vars are renamed, the logic should be the same as before.

Tests are welcome.

* Lock _sessionList instead

* Fix comment

* Fix Session fields order
2023-08-17 09:59:05 -03:00
19 changed files with 414 additions and 271 deletions

View File

@@ -29,4 +29,4 @@ infra:
- TSRBerry
default:
- @developers
- '@developers'

View File

@@ -62,9 +62,9 @@ if __name__ == "__main__":
sys.stderr.write("usage: <app_id> <private_key_env_name> <installation_id> <repo_path> <pr_id> <config_path>\n")
sys.exit(1)
app_id = sys.argv[1]
app_id = int(sys.argv[1])
private_key = os.environ[sys.argv[2]]
installation_id = sys.argv[3]
installation_id = int(sys.argv[3])
repo_path = sys.argv[4]
pr_id = int(sys.argv[5])
config_path = Path(sys.argv[6])

View File

@@ -148,6 +148,16 @@ namespace Ryujinx.Graphics.Vulkan
return _attachments[index];
}
public Auto<DisposableImageView> GetDepthStencilAttachment()
{
if (!HasDepthStencil)
{
return null;
}
return _attachments[AttachmentsCount - 1];
}
public ComponentType GetAttachmentComponentType(int index)
{
if (_colors != null && (uint)index < _colors.Length)

View File

@@ -38,6 +38,7 @@ namespace Ryujinx.Graphics.Vulkan
private readonly IProgram _programColorClearF;
private readonly IProgram _programColorClearSI;
private readonly IProgram _programColorClearUI;
private readonly IProgram _programDepthStencilClear;
private readonly IProgram _programStrideChange;
private readonly IProgram _programConvertD32S8ToD24S8;
private readonly IProgram _programConvertIndexBuffer;
@@ -105,6 +106,12 @@ namespace Ryujinx.Graphics.Vulkan
new ShaderSource(ReadSpirv("ColorClearUIFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
}, colorClearResourceLayout);
_programDepthStencilClear = gd.CreateProgramWithMinimalLayout(new[]
{
new ShaderSource(ReadSpirv("ColorClearVertex.spv"), ShaderStage.Vertex, TargetLanguage.Spirv),
new ShaderSource(ReadSpirv("DepthStencilClearFragment.spv"), ShaderStage.Fragment, TargetLanguage.Spirv),
}, colorClearResourceLayout);
var strideChangeResourceLayout = new ResourceLayoutBuilder()
.Add(ResourceStages.Compute, ResourceType.UniformBuffer, 0)
.Add(ResourceStages.Compute, ResourceType.StorageBuffer, 1)
@@ -446,10 +453,6 @@ namespace Ryujinx.Graphics.Vulkan
0f,
1f);
Span<Rectangle<int>> scissors = stackalloc Rectangle<int>[1];
scissors[0] = new Rectangle<int>(0, 0, dstWidth, dstHeight);
if (dstIsDepthOrStencil)
{
_pipeline.SetProgram(src.Info.Target.IsMultisample() ? _programDepthBlitMs : _programDepthBlit);
@@ -470,7 +473,7 @@ namespace Ryujinx.Graphics.Vulkan
_pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, (uint)dstSamples, dstIsDepthOrStencil, dstFormat);
_pipeline.SetRenderTargetColorMasks(new uint[] { 0xf });
_pipeline.SetScissors(scissors);
_pipeline.SetScissors(stackalloc Rectangle<int>[] { new Rectangle<int>(0, 0, dstWidth, dstHeight) });
if (clearAlpha)
{
@@ -547,12 +550,8 @@ namespace Ryujinx.Graphics.Vulkan
0f,
1f);
Span<Rectangle<int>> scissors = stackalloc Rectangle<int>[1];
scissors[0] = new Rectangle<int>(0, 0, dstWidth, dstHeight);
_pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, (uint)dstSamples, true, dstFormat);
_pipeline.SetScissors(scissors);
_pipeline.SetScissors(stackalloc Rectangle<int>[] { new Rectangle<int>(0, 0, dstWidth, dstHeight) });
_pipeline.SetViewports(viewports);
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
@@ -639,7 +638,11 @@ namespace Ryujinx.Graphics.Vulkan
}
}
private static StencilTestDescriptor CreateStencilTestDescriptor(bool enabled)
private static StencilTestDescriptor CreateStencilTestDescriptor(
bool enabled,
int refValue = 0,
int compareMask = 0xff,
int writeMask = 0xff)
{
return new StencilTestDescriptor(
enabled,
@@ -647,16 +650,16 @@ namespace Ryujinx.Graphics.Vulkan
StencilOp.Replace,
StencilOp.Replace,
StencilOp.Replace,
0,
0xff,
0xff,
refValue,
compareMask,
writeMask,
CompareOp.Always,
StencilOp.Replace,
StencilOp.Replace,
StencilOp.Replace,
0,
0xff,
0xff);
refValue,
compareMask,
writeMask);
}
public void Clear(
@@ -695,10 +698,6 @@ namespace Ryujinx.Graphics.Vulkan
0f,
1f);
Span<Rectangle<int>> scissors = stackalloc Rectangle<int>[1];
scissors[0] = scissor;
IProgram program;
if (type == ComponentType.SignedInteger)
@@ -718,7 +717,7 @@ namespace Ryujinx.Graphics.Vulkan
_pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, false, dstFormat);
_pipeline.SetRenderTargetColorMasks(new[] { componentMask });
_pipeline.SetViewports(viewports);
_pipeline.SetScissors(scissors);
_pipeline.SetScissors(stackalloc Rectangle<int>[] { scissor });
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
_pipeline.Draw(4, 1, 0, 0);
_pipeline.Finish();
@@ -726,6 +725,56 @@ namespace Ryujinx.Graphics.Vulkan
gd.BufferManager.Delete(bufferHandle);
}
public void Clear(
VulkanRenderer gd,
Auto<DisposableImageView> dst,
float depthValue,
bool depthMask,
int stencilValue,
int stencilMask,
int dstWidth,
int dstHeight,
VkFormat dstFormat,
Rectangle<int> scissor)
{
const int ClearColorBufferSize = 16;
gd.FlushAllCommands();
using var cbs = gd.CommandBufferPool.Rent();
_pipeline.SetCommandBuffer(cbs);
var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ClearColorBufferSize);
gd.BufferManager.SetData<float>(bufferHandle, 0, stackalloc float[] { depthValue });
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, new BufferRange(bufferHandle, 0, ClearColorBufferSize)) });
Span<Viewport> viewports = stackalloc Viewport[1];
viewports[0] = new Viewport(
new Rectangle<float>(0, 0, dstWidth, dstHeight),
ViewportSwizzle.PositiveX,
ViewportSwizzle.PositiveY,
ViewportSwizzle.PositiveZ,
ViewportSwizzle.PositiveW,
0f,
1f);
_pipeline.SetProgram(_programDepthStencilClear);
_pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, true, dstFormat);
_pipeline.SetViewports(viewports);
_pipeline.SetScissors(stackalloc Rectangle<int>[] { scissor });
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
_pipeline.SetDepthTest(new DepthTestDescriptor(true, depthMask, CompareOp.Always));
_pipeline.SetStencilTest(CreateStencilTestDescriptor(stencilMask != 0, stencilValue, 0xff, stencilMask));
_pipeline.Draw(4, 1, 0, 0);
_pipeline.Finish();
gd.BufferManager.Delete(bufferHandle);
}
public void DrawTexture(
VulkanRenderer gd,
PipelineBase pipeline,
@@ -778,8 +827,6 @@ namespace Ryujinx.Graphics.Vulkan
0f,
1f);
Span<Rectangle<int>> scissors = stackalloc Rectangle<int>[1];
pipeline.SetProgram(_programColorBlit);
pipeline.SetViewports(viewports);
pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
@@ -1119,11 +1166,7 @@ namespace Ryujinx.Graphics.Vulkan
0f,
1f);
Span<Rectangle<int>> scissors = stackalloc Rectangle<int>[1];
scissors[0] = new Rectangle<int>(0, 0, dst.Width, dst.Height);
_pipeline.SetScissors(scissors);
_pipeline.SetScissors(stackalloc Rectangle<int>[] { new Rectangle<int>(0, 0, dst.Width, dst.Height) });
_pipeline.SetViewports(viewports);
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
@@ -1251,12 +1294,8 @@ namespace Ryujinx.Graphics.Vulkan
0f,
1f);
Span<Rectangle<int>> scissors = stackalloc Rectangle<int>[1];
scissors[0] = new Rectangle<int>(0, 0, dst.Width, dst.Height);
_pipeline.SetRenderTargetColorMasks(new uint[] { 0xf });
_pipeline.SetScissors(scissors);
_pipeline.SetScissors(stackalloc Rectangle<int>[] { new Rectangle<int>(0, 0, dst.Width, dst.Height) });
_pipeline.SetViewports(viewports);
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
@@ -1731,6 +1770,7 @@ namespace Ryujinx.Graphics.Vulkan
_programColorClearF.Dispose();
_programColorClearSI.Dispose();
_programColorClearUI.Dispose();
_programDepthStencilClear.Dispose();
_programStrideChange.Dispose();
_programConvertIndexBuffer.Dispose();
_programConvertIndirectData.Dispose();

View File

@@ -243,10 +243,8 @@ namespace Ryujinx.Graphics.Vulkan
Gd.Api.CmdClearAttachments(CommandBuffer, 1, &attachment, 1, &clearRect);
}
public unsafe void ClearRenderTargetDepthStencil(int layer, int layerCount, float depthValue, bool depthMask, int stencilValue, int stencilMask)
public unsafe void ClearRenderTargetDepthStencil(int layer, int layerCount, float depthValue, bool depthMask, int stencilValue, bool stencilMask)
{
// TODO: Use stencilMask (fully).
if (FramebufferParams == null || !FramebufferParams.HasDepthStencil)
{
return;
@@ -255,7 +253,7 @@ namespace Ryujinx.Graphics.Vulkan
var clearValue = new ClearValue(null, new ClearDepthStencilValue(depthValue, (uint)stencilValue));
var flags = depthMask ? ImageAspectFlags.DepthBit : 0;
if (stencilMask != 0)
if (stencilMask)
{
flags |= ImageAspectFlags.StencilBit;
}

View File

@@ -81,6 +81,42 @@ namespace Ryujinx.Graphics.Vulkan
}
}
public void ClearRenderTargetDepthStencil(int layer, int layerCount, float depthValue, bool depthMask, int stencilValue, int stencilMask)
{
if (FramebufferParams == null)
{
return;
}
if (stencilMask != 0 && stencilMask != 0xff)
{
// We can't use CmdClearAttachments if not clearing all (mask is all ones, 0xFF) or none (mask is 0) of the stencil bits,
// because on Vulkan, the pipeline state does not affect clears.
var dstTexture = FramebufferParams.GetDepthStencilAttachment();
if (dstTexture == null)
{
return;
}
// TODO: Clear only the specified layer.
Gd.HelperShader.Clear(
Gd,
dstTexture,
depthValue,
depthMask,
stencilValue,
stencilMask,
(int)FramebufferParams.Width,
(int)FramebufferParams.Height,
FramebufferParams.AttachmentFormats[FramebufferParams.AttachmentsCount - 1],
ClearScissor);
}
else
{
ClearRenderTargetDepthStencil(layer, layerCount, depthValue, depthMask, stencilValue, stencilMask != 0);
}
}
public void EndHostConditionalRendering()
{
if (Gd.Capabilities.SupportsConditionalRendering)

View File

@@ -42,6 +42,7 @@
<EmbeddedResource Include="Shaders\SpirvBinaries\DepthBlitMsFragment.spv" />
<EmbeddedResource Include="Shaders\SpirvBinaries\DepthDrawToMsFragment.spv" />
<EmbeddedResource Include="Shaders\SpirvBinaries\DepthDrawToNonMsFragment.spv" />
<EmbeddedResource Include="Shaders\SpirvBinaries\DepthStencilClearFragment.spv" />
<EmbeddedResource Include="Shaders\SpirvBinaries\StencilBlitFragment.spv" />
<EmbeddedResource Include="Shaders\SpirvBinaries\StencilBlitMsFragment.spv" />
<EmbeddedResource Include="Shaders\SpirvBinaries\StencilDrawToMsFragment.spv" />

View File

@@ -0,0 +1,8 @@
#version 450 core
layout (location = 0) in vec4 clear_colour;
void main()
{
gl_FragDepth = clear_colour.x;
}

View File

@@ -1,196 +0,0 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Services.Mm.Types;
using System.Collections.Generic;
namespace Ryujinx.HLE.HOS.Services.Mm
{
[Service("mm:u")]
class IRequest : IpcService
{
private readonly object _sessionListLock = new();
private readonly List<MultiMediaSession> _sessionList = new();
private uint _uniqueId = 1;
public IRequest(ServiceCtx context) { }
[CommandCmif(0)]
// InitializeOld(u32, u32, u32)
public ResultCode InitializeOld(ServiceCtx context)
{
MultiMediaOperationType operationType = (MultiMediaOperationType)context.RequestData.ReadUInt32();
int fgmId = context.RequestData.ReadInt32();
bool isAutoClearEvent = context.RequestData.ReadInt32() != 0;
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { operationType, fgmId, isAutoClearEvent });
Register(operationType, fgmId, isAutoClearEvent);
return ResultCode.Success;
}
[CommandCmif(1)]
// FinalizeOld(u32)
public ResultCode FinalizeOld(ServiceCtx context)
{
MultiMediaOperationType operationType = (MultiMediaOperationType)context.RequestData.ReadUInt32();
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { operationType });
lock (_sessionListLock)
{
_sessionList.Remove(GetSessionByType(operationType));
}
return ResultCode.Success;
}
[CommandCmif(2)]
// SetAndWaitOld(u32, u32, u32)
public ResultCode SetAndWaitOld(ServiceCtx context)
{
MultiMediaOperationType operationType = (MultiMediaOperationType)context.RequestData.ReadUInt32();
uint frequenceHz = context.RequestData.ReadUInt32();
int timeout = context.RequestData.ReadInt32();
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { operationType, frequenceHz, timeout });
lock (_sessionListLock)
{
GetSessionByType(operationType)?.SetAndWait(frequenceHz, timeout);
}
return ResultCode.Success;
}
[CommandCmif(3)]
// GetOld(u32) -> u32
public ResultCode GetOld(ServiceCtx context)
{
MultiMediaOperationType operationType = (MultiMediaOperationType)context.RequestData.ReadUInt32();
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { operationType });
lock (_sessionListLock)
{
MultiMediaSession session = GetSessionByType(operationType);
uint currentValue = session == null ? 0 : session.CurrentValue;
context.ResponseData.Write(currentValue);
}
return ResultCode.Success;
}
[CommandCmif(4)]
// Initialize(u32, u32, u32) -> u32
public ResultCode Initialize(ServiceCtx context)
{
MultiMediaOperationType operationType = (MultiMediaOperationType)context.RequestData.ReadUInt32();
int fgmId = context.RequestData.ReadInt32();
bool isAutoClearEvent = context.RequestData.ReadInt32() != 0;
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { operationType, fgmId, isAutoClearEvent });
uint id = Register(operationType, fgmId, isAutoClearEvent);
context.ResponseData.Write(id);
return ResultCode.Success;
}
[CommandCmif(5)]
// Finalize(u32)
public ResultCode Finalize(ServiceCtx context)
{
uint id = context.RequestData.ReadUInt32();
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { id });
lock (_sessionListLock)
{
_sessionList.Remove(GetSessionById(id));
}
return ResultCode.Success;
}
[CommandCmif(6)]
// SetAndWait(u32, u32, u32)
public ResultCode SetAndWait(ServiceCtx context)
{
uint id = context.RequestData.ReadUInt32();
uint frequenceHz = context.RequestData.ReadUInt32();
int timeout = context.RequestData.ReadInt32();
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { id, frequenceHz, timeout });
lock (_sessionListLock)
{
GetSessionById(id)?.SetAndWait(frequenceHz, timeout);
}
return ResultCode.Success;
}
[CommandCmif(7)]
// Get(u32) -> u32
public ResultCode Get(ServiceCtx context)
{
uint id = context.RequestData.ReadUInt32();
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { id });
lock (_sessionListLock)
{
MultiMediaSession session = GetSessionById(id);
uint currentValue = session == null ? 0 : session.CurrentValue;
context.ResponseData.Write(currentValue);
}
return ResultCode.Success;
}
private MultiMediaSession GetSessionById(uint id)
{
foreach (MultiMediaSession session in _sessionList)
{
if (session.Id == id)
{
return session;
}
}
return null;
}
private MultiMediaSession GetSessionByType(MultiMediaOperationType type)
{
foreach (MultiMediaSession session in _sessionList)
{
if (session.Type == type)
{
return session;
}
}
return null;
}
private uint Register(MultiMediaOperationType type, int fgmId, bool isAutoClearEvent)
{
lock (_sessionListLock)
{
// Nintendo ignore the fgm id as the other interfaces were deprecated.
MultiMediaSession session = new(_uniqueId++, type, isAutoClearEvent);
_sessionList.Add(session);
return session.Id;
}
}
}
}

View File

@@ -1,10 +0,0 @@
namespace Ryujinx.HLE.HOS.Services.Mm.Types
{
enum MultiMediaOperationType : uint
{
Ram = 2,
NvEnc = 5,
NvDec = 6,
NvJpg = 7,
}
}

View File

@@ -1,24 +0,0 @@
namespace Ryujinx.HLE.HOS.Services.Mm.Types
{
class MultiMediaSession
{
public MultiMediaOperationType Type { get; }
public bool IsAutoClearEvent { get; }
public uint Id { get; }
public uint CurrentValue { get; private set; }
public MultiMediaSession(uint id, MultiMediaOperationType type, bool isAutoClearEvent)
{
Type = type;
Id = id;
IsAutoClearEvent = isAutoClearEvent;
CurrentValue = 0;
}
public void SetAndWait(uint value, int timeout)
{
CurrentValue = value;
}
}
}

View File

@@ -0,0 +1,160 @@
using Ryujinx.Common.Logging;
using Ryujinx.Horizon.Common;
using Ryujinx.Horizon.Sdk.MmNv;
using Ryujinx.Horizon.Sdk.Sf;
using System.Collections.Generic;
namespace Ryujinx.Horizon.MmNv.Ipc
{
partial class Request : IRequest
{
private readonly List<Session> _sessionList = new();
private uint _uniqueId = 1;
[CmifCommand(0)]
public Result InitializeOld(Module module, uint fgmPriority, uint autoClearEvent)
{
bool isAutoClearEvent = autoClearEvent != 0;
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { module, fgmPriority, isAutoClearEvent });
Register(module, fgmPriority, isAutoClearEvent);
return Result.Success;
}
[CmifCommand(1)]
public Result FinalizeOld(Module module)
{
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { module });
lock (_sessionList)
{
_sessionList.Remove(GetSessionByModule(module));
}
return Result.Success;
}
[CmifCommand(2)]
public Result SetAndWaitOld(Module module, uint clockRateMin, int clockRateMax)
{
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { module, clockRateMin, clockRateMax });
lock (_sessionList)
{
GetSessionByModule(module)?.SetAndWait(clockRateMin, clockRateMax);
}
return Result.Success;
}
[CmifCommand(3)]
public Result GetOld(out uint clockRateActual, Module module)
{
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { module });
lock (_sessionList)
{
Session session = GetSessionByModule(module);
clockRateActual = session == null ? 0 : session.ClockRateMin;
}
return Result.Success;
}
[CmifCommand(4)]
public Result Initialize(out uint requestId, Module module, uint fgmPriority, uint autoClearEvent)
{
bool isAutoClearEvent = autoClearEvent != 0;
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { module, fgmPriority, isAutoClearEvent });
requestId = Register(module, fgmPriority, isAutoClearEvent);
return Result.Success;
}
[CmifCommand(5)]
public Result Finalize(uint requestId)
{
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { requestId });
lock (_sessionList)
{
_sessionList.Remove(GetSessionById(requestId));
}
return Result.Success;
}
[CmifCommand(6)]
public Result SetAndWait(uint requestId, uint clockRateMin, int clockRateMax)
{
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { requestId, clockRateMin, clockRateMax });
lock (_sessionList)
{
GetSessionById(requestId)?.SetAndWait(clockRateMin, clockRateMax);
}
return Result.Success;
}
[CmifCommand(7)]
public Result Get(out uint clockRateActual, uint requestId)
{
Logger.Stub?.PrintStub(LogClass.ServiceMm, new { requestId });
lock (_sessionList)
{
Session session = GetSessionById(requestId);
clockRateActual = session == null ? 0 : session.ClockRateMin;
}
return Result.Success;
}
private Session GetSessionById(uint id)
{
foreach (Session session in _sessionList)
{
if (session.Id == id)
{
return session;
}
}
return null;
}
private Session GetSessionByModule(Module module)
{
foreach (Session session in _sessionList)
{
if (session.Module == module)
{
return session;
}
}
return null;
}
private uint Register(Module module, uint fgmPriority, bool isAutoClearEvent)
{
lock (_sessionList)
{
// Nintendo ignores the fgm priority as the other services were deprecated.
Session session = new(_uniqueId++, module, isAutoClearEvent);
_sessionList.Add(session);
return session.Id;
}
}
}
}

View File

@@ -0,0 +1,43 @@
using Ryujinx.Horizon.MmNv.Ipc;
using Ryujinx.Horizon.Sdk.Sf.Hipc;
using Ryujinx.Horizon.Sdk.Sm;
namespace Ryujinx.Horizon.MmNv
{
class MmNvIpcServer
{
private const int MmNvMaxSessionsCount = 9;
private const int PointerBufferSize = 0;
private const int MaxDomains = 0;
private const int MaxDomainObjects = 0;
private const int MaxPortsCount = 1;
private static readonly ManagerOptions _mmNvOptions = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false);
private SmApi _sm;
private ServerManager _serverManager;
public void Initialize()
{
HeapAllocator allocator = new();
_sm = new SmApi();
_sm.Initialize().AbortOnFailure();
_serverManager = new ServerManager(allocator, _sm, MaxPortsCount, _mmNvOptions, MmNvMaxSessionsCount);
_serverManager.RegisterObjectForServer(new Request(), ServiceName.Encode("mm:u"), MmNvMaxSessionsCount);
}
public void ServiceRequests()
{
_serverManager.ServiceRequests();
}
public void Shutdown()
{
_serverManager.Dispose();
}
}
}

View File

@@ -0,0 +1,17 @@
namespace Ryujinx.Horizon.MmNv
{
class MmNvMain : IService
{
public static void Main(ServiceTable serviceTable)
{
MmNvIpcServer ipcServer = new();
ipcServer.Initialize();
serviceTable.SignalServiceReady();
ipcServer.ServiceRequests();
ipcServer.Shutdown();
}
}
}

View File

@@ -0,0 +1,17 @@
using Ryujinx.Horizon.Common;
using Ryujinx.Horizon.Sdk.Sf;
namespace Ryujinx.Horizon.Sdk.MmNv
{
interface IRequest : IServiceObject
{
Result InitializeOld(Module module, uint fgmPriority, uint autoClearEvent);
Result FinalizeOld(Module module);
Result SetAndWaitOld(Module module, uint clockRateMin, int clockRateMax);
Result GetOld(out uint clockRateActual, Module module);
Result Initialize(out uint requestId, Module module, uint fgmPriority, uint autoClearEvent);
Result Finalize(uint requestId);
Result SetAndWait(uint requestId, uint clockRateMin, int clockRateMax);
Result Get(out uint clockRateActual, uint requestId);
}
}

View File

@@ -0,0 +1,15 @@
namespace Ryujinx.Horizon.Sdk.MmNv
{
enum Module : uint
{
Cpu,
Gpu,
Emc,
SysBus,
MSelect,
NvDec,
NvEnc,
NvJpg,
Test,
}
}

View File

@@ -0,0 +1,26 @@
namespace Ryujinx.Horizon.Sdk.MmNv
{
class Session
{
public Module Module { get; }
public uint Id { get; }
public bool IsAutoClearEvent { get; }
public uint ClockRateMin { get; private set; }
public int ClockRateMax { get; private set; }
public Session(uint id, Module module, bool isAutoClearEvent)
{
Module = module;
Id = id;
IsAutoClearEvent = isAutoClearEvent;
ClockRateMin = 0;
ClockRateMax = -1;
}
public void SetAndWait(uint clockRateMin, int clockRateMax)
{
ClockRateMin = clockRateMin;
ClockRateMax = clockRateMax;
}
}
}

View File

@@ -1,5 +1,6 @@
using Ryujinx.Horizon.Bcat;
using Ryujinx.Horizon.LogManager;
using Ryujinx.Horizon.MmNv;
using Ryujinx.Horizon.Prepo;
using System.Collections.Generic;
using System.Threading;
@@ -25,6 +26,7 @@ namespace Ryujinx.Horizon
RegisterService<LmMain>();
RegisterService<PrepoMain>();
RegisterService<BcatMain>();
RegisterService<MmNvMain>();
_totalServices = entries.Count;