| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596 |
- using System;
- using System.Collections.Generic;
- namespace Ryujinx.Graphics.Gpu.Shader.HashTable
- {
- /// <summary>
- /// Smart data accessor that can cache data and hashes to avoid reading and re-hashing the same memory regions.
- /// </summary>
- ref struct SmartDataAccessor
- {
- private readonly IDataAccessor _dataAccessor;
- private ReadOnlySpan<byte> _data;
- private readonly SortedList<int, HashState> _cachedHashes;
- /// <summary>
- /// Creates a new smart data accessor.
- /// </summary>
- /// <param name="dataAccessor">Data accessor</param>
- public SmartDataAccessor(IDataAccessor dataAccessor)
- {
- _dataAccessor = dataAccessor;
- _data = ReadOnlySpan<byte>.Empty;
- _cachedHashes = new SortedList<int, HashState>();
- }
- /// <summary>
- /// Get a spans of a given size.
- /// </summary>
- /// <remarks>
- /// The actual length of the span returned depends on the <see cref="IDataAccessor"/>
- /// and might be less than requested.
- /// </remarks>
- /// <param name="length">Size in bytes</param>
- /// <returns>Span with the requested size</returns>
- public ReadOnlySpan<byte> GetSpan(int length)
- {
- if (_data.Length < length)
- {
- _data = _dataAccessor.GetSpan(0, length);
- }
- else if (_data.Length > length)
- {
- return _data.Slice(0, length);
- }
- return _data;
- }
- /// <summary>
- /// Gets a span of the requested size, and a hash of its data.
- /// </summary>
- /// <param name="length">Length of the span</param>
- /// <param name="hash">Hash of the span data</param>
- /// <returns>Span of data</returns>
- public ReadOnlySpan<byte> GetSpanAndHash(int length, out uint hash)
- {
- ReadOnlySpan<byte> data = GetSpan(length);
- hash = data.Length == length ? CalcHashCached(data) : 0;
- return data;
- }
- /// <summary>
- /// Calculates the hash for a requested span.
- /// This will try to use a cached hash if the data was already accessed before, to avoid re-hashing.
- /// </summary>
- /// <param name="data">Data to be hashed</param>
- /// <returns>Hash of the data</returns>
- private uint CalcHashCached(ReadOnlySpan<byte> data)
- {
- HashState state = default;
- bool found = false;
- for (int i = _cachedHashes.Count - 1; i >= 0; i--)
- {
- int cachedHashSize = _cachedHashes.Keys[i];
- if (cachedHashSize < data.Length)
- {
- state = _cachedHashes.Values[i];
- found = true;
- break;
- }
- }
- if (!found)
- {
- state = new HashState();
- state.Initialize();
- }
- state.Continue(data);
- _cachedHashes[data.Length & ~7] = state;
- return state.Finalize(data);
- }
- }
- }
|