aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Horizon/Sdk/Sf/Cmif/DomainServiceObjectProcessor.cs
blob: 796b8a7898f2497a7b150d1d8420fc01cb735268 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
using Ryujinx.Horizon.Common;
using Ryujinx.Horizon.Sdk.Sf.Hipc;
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace Ryujinx.Horizon.Sdk.Sf.Cmif
{
    class DomainServiceObjectProcessor : ServerMessageProcessor
    {
        public const int MaximumObjects = 8;

        private ServerMessageProcessor _implProcessor;
        private readonly ServerDomainBase _domain;
        private int _outObjectIdsOffset;
        private readonly int[] _inObjectIds;
        private readonly int[] _reservedObjectIds;
        private ServerMessageRuntimeMetadata _implMetadata;

        private int InObjectsCount => _inObjectIds.Length;
        private int OutObjectsCount => _implMetadata.OutObjectsCount;
        private int ImplOutHeadersSize => _implMetadata.OutHeadersSize;
        private int ImplOutDataTotalSize => _implMetadata.OutDataSize + _implMetadata.OutHeadersSize;

        public DomainServiceObjectProcessor(ServerDomainBase domain, int[] inObjectIds)
        {
            _domain = domain;
            _inObjectIds = inObjectIds;
            _reservedObjectIds = new int[MaximumObjects];
        }

        public override void SetImplementationProcessor(ServerMessageProcessor impl)
        {
            if (_implProcessor == null)
            {
                _implProcessor = impl;
            }
            else
            {
                _implProcessor.SetImplementationProcessor(impl);
            }

            _implMetadata = _implProcessor.GetRuntimeMetadata();
        }

        public override ServerMessageRuntimeMetadata GetRuntimeMetadata()
        {
            var runtimeMetadata = _implProcessor.GetRuntimeMetadata();

            return new ServerMessageRuntimeMetadata(
                (ushort)(runtimeMetadata.InDataSize + runtimeMetadata.InObjectsCount * sizeof(int)),
                (ushort)(runtimeMetadata.OutDataSize + runtimeMetadata.OutObjectsCount * sizeof(int)),
                (byte)(runtimeMetadata.InHeadersSize + Unsafe.SizeOf<CmifDomainInHeader>()),
                (byte)(runtimeMetadata.OutHeadersSize + Unsafe.SizeOf<CmifDomainOutHeader>()),
                0,
                0);
        }

        public override Result PrepareForProcess(ref ServiceDispatchContext context, ServerMessageRuntimeMetadata runtimeMetadata)
        {
            if (_implMetadata.InObjectsCount != InObjectsCount)
            {
                return SfResult.InvalidInObjectsCount;
            }

            Result result = _domain.ReserveIds(new Span<int>(_reservedObjectIds)[..OutObjectsCount]);

            if (result.IsFailure)
            {
                return result;
            }

            return _implProcessor.PrepareForProcess(ref context, runtimeMetadata);
        }

        public override Result GetInObjects(Span<ServiceObjectHolder> inObjects)
        {
            for (int i = 0; i < InObjectsCount; i++)
            {
                inObjects[i] = _domain.GetObject(_inObjectIds[i]);
            }

            return Result.Success;
        }

        public override HipcMessageData PrepareForReply(scoped ref ServiceDispatchContext context, out Span<byte> outRawData, ServerMessageRuntimeMetadata runtimeMetadata)
        {
            var response = _implProcessor.PrepareForReply(ref context, out outRawData, runtimeMetadata);

            int outHeaderSize = Unsafe.SizeOf<CmifDomainOutHeader>();
            int implOutDataTotalSize = ImplOutDataTotalSize;

            DebugUtil.Assert(outHeaderSize + implOutDataTotalSize + OutObjectsCount * sizeof(int) <= outRawData.Length);

            outRawData = outRawData[outHeaderSize..];
            _outObjectIdsOffset = (response.DataWords.Length * sizeof(uint) - outRawData.Length) + implOutDataTotalSize;

            return response;
        }

        public override void PrepareForErrorReply(scoped ref ServiceDispatchContext context, out Span<byte> outRawData, ServerMessageRuntimeMetadata runtimeMetadata)
        {
            _implProcessor.PrepareForErrorReply(ref context, out outRawData, runtimeMetadata);

            int outHeaderSize = Unsafe.SizeOf<CmifDomainOutHeader>();
            int implOutDataTotalSize = ImplOutDataTotalSize;

            DebugUtil.Assert(outHeaderSize + implOutDataTotalSize <= outRawData.Length);

            outRawData = outRawData[outHeaderSize..];

            _domain.UnreserveIds(new Span<int>(_reservedObjectIds)[..OutObjectsCount]);
        }

        public override void SetOutObjects(scoped ref ServiceDispatchContext context, HipcMessageData response, Span<ServiceObjectHolder> outObjects)
        {
            int outObjectsCount = OutObjectsCount;
            Span<int> objectIds = _reservedObjectIds;

            for (int i = 0; i < outObjectsCount; i++)
            {
                if (outObjects[i] == null)
                {
                    _domain.UnreserveIds(objectIds.Slice(i, 1));
                    objectIds[i] = 0;
                    continue;
                }

                _domain.RegisterObject(objectIds[i], outObjects[i]);
            }

            Span<int> outObjectIds = MemoryMarshal.Cast<byte, int>(MemoryMarshal.Cast<uint, byte>(response.DataWords)[_outObjectIdsOffset..]);

            for (int i = 0; i < outObjectsCount; i++)
            {
                outObjectIds[i] = objectIds[i];
            }
        }
    }
}