diff options
author | gdkchan <gab.dark.100@gmail.com> | 2020-07-12 00:07:01 -0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-12 05:07:01 +0200 |
commit | 4d02a2d2c0451b4de1f6de3bbce54c457cacebe2 (patch) | |
tree | 120fe4fb8cfa1ac1c6ef4c97d92be47e955e8c0f /Ryujinx.Graphics.Device/DeviceState.cs | |
parent | 38b26cf4242999fa7d8c550993ac0940cd03d55f (diff) |
New NVDEC and VIC implementation (#1384)
* Initial NVDEC and VIC implementation
* Update FFmpeg.AutoGen to 4.3.0
* Add nvdec dependencies for Windows
* Unify some VP9 structures
* Rename VP9 structure fields
* Improvements to Video API
* XML docs for Common.Memory
* Remove now unused or redundant overloads from MemoryAccessor
* NVDEC UV surface read/write scalar paths
* Add FIXME comments about hacky things/stuff that will need to be fixed in the future
* Cleaned up VP9 memory allocation
* Remove some debug logs
* Rename some VP9 structs
* Remove unused struct
* No need to compile Ryujinx.Graphics.Host1x with unsafe anymore
* Name AsyncWorkQueue threads to make debugging easier
* Make Vp9PictureInfo a ref struct
* LayoutConverter no longer needs the depth argument (broken by rebase)
* Pooling of VP9 buffers, plus fix a memory leak on VP9
* Really wish VS could rename projects properly...
* Address feedback
* Remove using
* Catch OperationCanceledException
* Add licensing informations
* Add THIRDPARTY.md to release too
Co-authored-by: Thog <me@thog.eu>
Diffstat (limited to 'Ryujinx.Graphics.Device/DeviceState.cs')
-rw-r--r-- | Ryujinx.Graphics.Device/DeviceState.cs | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/Ryujinx.Graphics.Device/DeviceState.cs b/Ryujinx.Graphics.Device/DeviceState.cs new file mode 100644 index 00000000..ea6942ec --- /dev/null +++ b/Ryujinx.Graphics.Device/DeviceState.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; + +namespace Ryujinx.Graphics.Device +{ + public class DeviceState<TState> : IDeviceState where TState : unmanaged + { + private const int RegisterSize = sizeof(int); + + public TState State; + + private readonly BitArray _readableRegisters; + private readonly BitArray _writableRegisters; + + private readonly Dictionary<int, Func<int>> _readCallbacks; + private readonly Dictionary<int, Action<int>> _writeCallbacks; + + public DeviceState(IReadOnlyDictionary<string, RwCallback> callbacks = null) + { + int size = (Unsafe.SizeOf<TState>() + RegisterSize - 1) / RegisterSize; + + _readableRegisters = new BitArray(size); + _writableRegisters = new BitArray(size); + + _readCallbacks = new Dictionary<int, Func<int>>(); + _writeCallbacks = new Dictionary<int, Action<int>>(); + + var fields = typeof(TState).GetFields(); + int offset = 0; + + for (int fieldIndex = 0; fieldIndex < fields.Length; fieldIndex++) + { + var field = fields[fieldIndex]; + var regAttr = field.GetCustomAttributes<RegisterAttribute>(false).FirstOrDefault(); + + int sizeOfField = SizeCalculator.SizeOf(field.FieldType); + + for (int i = 0; i < ((sizeOfField + 3) & ~3); i += 4) + { + _readableRegisters[(offset + i) / RegisterSize] = regAttr?.AccessControl.HasFlag(AccessControl.ReadOnly) ?? true; + _writableRegisters[(offset + i) / RegisterSize] = regAttr?.AccessControl.HasFlag(AccessControl.WriteOnly) ?? true; + } + + if (callbacks != null && callbacks.TryGetValue(field.Name, out var cb)) + { + if (cb.Read != null) + { + _readCallbacks.Add(offset, cb.Read); + } + + if (cb.Write != null) + { + _writeCallbacks.Add(offset, cb.Write); + } + } + + offset += sizeOfField; + } + + Debug.Assert(offset == Unsafe.SizeOf<TState>()); + } + + public virtual int Read(int offset) + { + if (Check(offset) && _readableRegisters[offset / RegisterSize]) + { + int alignedOffset = Align(offset); + + if (_readCallbacks.TryGetValue(alignedOffset, out Func<int> read)) + { + return read(); + } + else + { + return GetRef<int>(alignedOffset); + } + } + + return 0; + } + + public virtual void Write(int offset, int data) + { + if (Check(offset) && _writableRegisters[offset / RegisterSize]) + { + int alignedOffset = Align(offset); + + if (_writeCallbacks.TryGetValue(alignedOffset, out Action<int> write)) + { + write(data); + } + else + { + GetRef<int>(alignedOffset) = data; + } + } + } + + private bool Check(int offset) + { + return (uint)Align(offset) < Unsafe.SizeOf<TState>(); + } + + public ref T GetRef<T>(int offset) where T : unmanaged + { + if ((uint)(offset + Unsafe.SizeOf<T>()) > Unsafe.SizeOf<TState>()) + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + + return ref Unsafe.As<TState, T>(ref Unsafe.AddByteOffset(ref State, (IntPtr)offset)); + } + + private static int Align(int offset) + { + return offset & ~(RegisterSize - 1); + } + } +} |