mirror of
https://github.com/Ryujinx/Ryujinx.git
synced 2024-08-18 06:38:42 +02:00
Restride vertex buffer when stride causes attributes to misalign in Vulkan. (#3679)
* Vertex Buffer Alignment part 1 * Update CacheByRange * Add Stride Change compute shader, fix storage buffers in helpers * An AMD exclusive * Reword * Change rules - stride conversion when attrs misalign * Fix stupid mistake * Fix background pipeline compile * Improve a few things. * Fix some feedback * Address Feedback (the shader binary didn't change when i changed the source to use the subgroup size) * Fix bug where rewritten buffer would be disposed instantly.
This commit is contained in:
parent
ee1825219b
commit
c6d82209ab
18 changed files with 1069 additions and 120 deletions
|
@ -151,6 +151,190 @@ namespace Ryujinx.Graphics.GAL
|
||||||
|
|
||||||
public static class FormatExtensions
|
public static class FormatExtensions
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The largest scalar size for a buffer format.
|
||||||
|
/// </summary>
|
||||||
|
public const int MaxBufferFormatScalarSize = 4;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the byte size for a single component of this format, or its packed size.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="format">Texture format</param>
|
||||||
|
/// <returns>Byte size for a single component, or packed size</returns>
|
||||||
|
public static int GetScalarSize(this Format format)
|
||||||
|
{
|
||||||
|
switch (format)
|
||||||
|
{
|
||||||
|
case Format.R8Unorm:
|
||||||
|
case Format.R8Snorm:
|
||||||
|
case Format.R8Uint:
|
||||||
|
case Format.R8Sint:
|
||||||
|
case Format.R8G8Unorm:
|
||||||
|
case Format.R8G8Snorm:
|
||||||
|
case Format.R8G8Uint:
|
||||||
|
case Format.R8G8Sint:
|
||||||
|
case Format.R8G8B8Unorm:
|
||||||
|
case Format.R8G8B8Snorm:
|
||||||
|
case Format.R8G8B8Uint:
|
||||||
|
case Format.R8G8B8Sint:
|
||||||
|
case Format.R8G8B8A8Unorm:
|
||||||
|
case Format.R8G8B8A8Snorm:
|
||||||
|
case Format.R8G8B8A8Uint:
|
||||||
|
case Format.R8G8B8A8Sint:
|
||||||
|
case Format.R8G8B8A8Srgb:
|
||||||
|
case Format.R4G4Unorm:
|
||||||
|
case Format.R8Uscaled:
|
||||||
|
case Format.R8Sscaled:
|
||||||
|
case Format.R8G8Uscaled:
|
||||||
|
case Format.R8G8Sscaled:
|
||||||
|
case Format.R8G8B8Uscaled:
|
||||||
|
case Format.R8G8B8Sscaled:
|
||||||
|
case Format.R8G8B8A8Uscaled:
|
||||||
|
case Format.R8G8B8A8Sscaled:
|
||||||
|
case Format.B8G8R8A8Unorm:
|
||||||
|
case Format.B8G8R8A8Srgb:
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case Format.R16Float:
|
||||||
|
case Format.R16Unorm:
|
||||||
|
case Format.R16Snorm:
|
||||||
|
case Format.R16Uint:
|
||||||
|
case Format.R16Sint:
|
||||||
|
case Format.R16G16Float:
|
||||||
|
case Format.R16G16Unorm:
|
||||||
|
case Format.R16G16Snorm:
|
||||||
|
case Format.R16G16Uint:
|
||||||
|
case Format.R16G16Sint:
|
||||||
|
case Format.R16G16B16Float:
|
||||||
|
case Format.R16G16B16Unorm:
|
||||||
|
case Format.R16G16B16Snorm:
|
||||||
|
case Format.R16G16B16Uint:
|
||||||
|
case Format.R16G16B16Sint:
|
||||||
|
case Format.R16G16B16A16Float:
|
||||||
|
case Format.R16G16B16A16Unorm:
|
||||||
|
case Format.R16G16B16A16Snorm:
|
||||||
|
case Format.R16G16B16A16Uint:
|
||||||
|
case Format.R16G16B16A16Sint:
|
||||||
|
case Format.R4G4B4A4Unorm:
|
||||||
|
case Format.R5G5B5X1Unorm:
|
||||||
|
case Format.R5G5B5A1Unorm:
|
||||||
|
case Format.R5G6B5Unorm:
|
||||||
|
case Format.R16Uscaled:
|
||||||
|
case Format.R16Sscaled:
|
||||||
|
case Format.R16G16Uscaled:
|
||||||
|
case Format.R16G16Sscaled:
|
||||||
|
case Format.R16G16B16Uscaled:
|
||||||
|
case Format.R16G16B16Sscaled:
|
||||||
|
case Format.R16G16B16A16Uscaled:
|
||||||
|
case Format.R16G16B16A16Sscaled:
|
||||||
|
case Format.B5G6R5Unorm:
|
||||||
|
case Format.B5G5R5A1Unorm:
|
||||||
|
case Format.A1B5G5R5Unorm:
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
case Format.R32Float:
|
||||||
|
case Format.R32Uint:
|
||||||
|
case Format.R32Sint:
|
||||||
|
case Format.R32G32Float:
|
||||||
|
case Format.R32G32Uint:
|
||||||
|
case Format.R32G32Sint:
|
||||||
|
case Format.R32G32B32Float:
|
||||||
|
case Format.R32G32B32Uint:
|
||||||
|
case Format.R32G32B32Sint:
|
||||||
|
case Format.R32G32B32A32Float:
|
||||||
|
case Format.R32G32B32A32Uint:
|
||||||
|
case Format.R32G32B32A32Sint:
|
||||||
|
case Format.R10G10B10A2Unorm:
|
||||||
|
case Format.R10G10B10A2Uint:
|
||||||
|
case Format.R11G11B10Float:
|
||||||
|
case Format.R9G9B9E5Float:
|
||||||
|
case Format.R32Uscaled:
|
||||||
|
case Format.R32Sscaled:
|
||||||
|
case Format.R32G32Uscaled:
|
||||||
|
case Format.R32G32Sscaled:
|
||||||
|
case Format.R32G32B32Uscaled:
|
||||||
|
case Format.R32G32B32Sscaled:
|
||||||
|
case Format.R32G32B32A32Uscaled:
|
||||||
|
case Format.R32G32B32A32Sscaled:
|
||||||
|
case Format.R10G10B10A2Snorm:
|
||||||
|
case Format.R10G10B10A2Sint:
|
||||||
|
case Format.R10G10B10A2Uscaled:
|
||||||
|
case Format.R10G10B10A2Sscaled:
|
||||||
|
return 4;
|
||||||
|
|
||||||
|
case Format.S8Uint:
|
||||||
|
return 1;
|
||||||
|
case Format.D16Unorm:
|
||||||
|
return 2;
|
||||||
|
case Format.S8UintD24Unorm:
|
||||||
|
case Format.D32Float:
|
||||||
|
case Format.D24UnormS8Uint:
|
||||||
|
return 4;
|
||||||
|
case Format.D32FloatS8Uint:
|
||||||
|
return 8;
|
||||||
|
|
||||||
|
case Format.Bc1RgbaUnorm:
|
||||||
|
case Format.Bc1RgbaSrgb:
|
||||||
|
return 8;
|
||||||
|
|
||||||
|
case Format.Bc2Unorm:
|
||||||
|
case Format.Bc3Unorm:
|
||||||
|
case Format.Bc2Srgb:
|
||||||
|
case Format.Bc3Srgb:
|
||||||
|
case Format.Bc4Unorm:
|
||||||
|
case Format.Bc4Snorm:
|
||||||
|
case Format.Bc5Unorm:
|
||||||
|
case Format.Bc5Snorm:
|
||||||
|
case Format.Bc7Unorm:
|
||||||
|
case Format.Bc7Srgb:
|
||||||
|
case Format.Bc6HSfloat:
|
||||||
|
case Format.Bc6HUfloat:
|
||||||
|
return 16;
|
||||||
|
|
||||||
|
case Format.Etc2RgbUnorm:
|
||||||
|
case Format.Etc2RgbPtaUnorm:
|
||||||
|
case Format.Etc2RgbSrgb:
|
||||||
|
case Format.Etc2RgbPtaSrgb:
|
||||||
|
return 8;
|
||||||
|
|
||||||
|
case Format.Etc2RgbaUnorm:
|
||||||
|
case Format.Etc2RgbaSrgb:
|
||||||
|
return 16;
|
||||||
|
|
||||||
|
case Format.Astc4x4Unorm:
|
||||||
|
case Format.Astc5x4Unorm:
|
||||||
|
case Format.Astc5x5Unorm:
|
||||||
|
case Format.Astc6x5Unorm:
|
||||||
|
case Format.Astc6x6Unorm:
|
||||||
|
case Format.Astc8x5Unorm:
|
||||||
|
case Format.Astc8x6Unorm:
|
||||||
|
case Format.Astc8x8Unorm:
|
||||||
|
case Format.Astc10x5Unorm:
|
||||||
|
case Format.Astc10x6Unorm:
|
||||||
|
case Format.Astc10x8Unorm:
|
||||||
|
case Format.Astc10x10Unorm:
|
||||||
|
case Format.Astc12x10Unorm:
|
||||||
|
case Format.Astc12x12Unorm:
|
||||||
|
case Format.Astc4x4Srgb:
|
||||||
|
case Format.Astc5x4Srgb:
|
||||||
|
case Format.Astc5x5Srgb:
|
||||||
|
case Format.Astc6x5Srgb:
|
||||||
|
case Format.Astc6x6Srgb:
|
||||||
|
case Format.Astc8x5Srgb:
|
||||||
|
case Format.Astc8x6Srgb:
|
||||||
|
case Format.Astc8x8Srgb:
|
||||||
|
case Format.Astc10x5Srgb:
|
||||||
|
case Format.Astc10x6Srgb:
|
||||||
|
case Format.Astc10x8Srgb:
|
||||||
|
case Format.Astc10x10Srgb:
|
||||||
|
case Format.Astc12x10Srgb:
|
||||||
|
case Format.Astc12x12Srgb:
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if the texture format is valid to use as image format.
|
/// Checks if the texture format is valid to use as image format.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -27,7 +27,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
private readonly Auto<MemoryAllocation> _allocationAuto;
|
private readonly Auto<MemoryAllocation> _allocationAuto;
|
||||||
private readonly ulong _bufferHandle;
|
private readonly ulong _bufferHandle;
|
||||||
|
|
||||||
private CacheByRange<BufferHolder> _cachedConvertedIndexBuffers;
|
private CacheByRange<BufferHolder> _cachedConvertedBuffers;
|
||||||
|
|
||||||
public int Size { get; }
|
public int Size { get; }
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
if (isWrite)
|
if (isWrite)
|
||||||
{
|
{
|
||||||
_cachedConvertedIndexBuffers.Clear();
|
_cachedConvertedBuffers.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
return _buffer;
|
return _buffer;
|
||||||
|
@ -364,13 +364,35 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
public Auto<DisposableBuffer> GetBufferI8ToI16(CommandBufferScoped cbs, int offset, int size)
|
public Auto<DisposableBuffer> GetBufferI8ToI16(CommandBufferScoped cbs, int offset, int size)
|
||||||
{
|
{
|
||||||
if (!_cachedConvertedIndexBuffers.TryGetValue(offset, size, out var holder))
|
var key = new I8ToI16CacheKey();
|
||||||
|
|
||||||
|
if (!_cachedConvertedBuffers.TryGetValue(offset, size, key, out var holder))
|
||||||
{
|
{
|
||||||
holder = _gd.BufferManager.Create(_gd, (size * 2 + 3) & ~3);
|
holder = _gd.BufferManager.Create(_gd, (size * 2 + 3) & ~3);
|
||||||
|
|
||||||
_gd.HelperShader.ConvertI8ToI16(_gd, cbs, this, holder, offset, size);
|
_gd.HelperShader.ConvertI8ToI16(_gd, cbs, this, holder, offset, size);
|
||||||
|
|
||||||
_cachedConvertedIndexBuffers.Add(offset, size, holder);
|
_cachedConvertedBuffers.Add(offset, size, key, holder);
|
||||||
|
}
|
||||||
|
|
||||||
|
return holder.GetBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Auto<DisposableBuffer> GetAlignedVertexBuffer(CommandBufferScoped cbs, int offset, int size, int stride, int alignment)
|
||||||
|
{
|
||||||
|
var key = new AlignedVertexBufferCacheKey(_gd, stride, alignment);
|
||||||
|
|
||||||
|
if (!_cachedConvertedBuffers.TryGetValue(offset, size, key, out var holder))
|
||||||
|
{
|
||||||
|
int alignedStride = (stride + (alignment - 1)) & -alignment;
|
||||||
|
|
||||||
|
holder = _gd.BufferManager.Create(_gd, (size / stride) * alignedStride);
|
||||||
|
|
||||||
|
_gd.HelperShader.ChangeStride(_gd, cbs, this, holder, offset, size, stride, alignedStride);
|
||||||
|
|
||||||
|
key.SetBuffer(holder.GetBuffer());
|
||||||
|
|
||||||
|
_cachedConvertedBuffers.Add(offset, size, key, holder);
|
||||||
}
|
}
|
||||||
|
|
||||||
return holder.GetBuffer();
|
return holder.GetBuffer();
|
||||||
|
@ -382,7 +404,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
_buffer.Dispose();
|
_buffer.Dispose();
|
||||||
_allocationAuto.Dispose();
|
_allocationAuto.Dispose();
|
||||||
_cachedConvertedIndexBuffers.Dispose();
|
_cachedConvertedBuffers.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,6 +130,16 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Auto<DisposableBuffer> GetAlignedVertexBuffer(CommandBufferScoped cbs, BufferHandle handle, int offset, int size, int stride, int alignment)
|
||||||
|
{
|
||||||
|
if (TryGetBuffer(handle, out var holder))
|
||||||
|
{
|
||||||
|
return holder.GetAlignedVertexBuffer(cbs, offset, size, stride, alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public Auto<DisposableBuffer> GetBuffer(CommandBuffer commandBuffer, BufferHandle handle, bool isWrite, out int size)
|
public Auto<DisposableBuffer> GetBuffer(CommandBuffer commandBuffer, BufferHandle handle, bool isWrite, out int size)
|
||||||
{
|
{
|
||||||
if (TryGetBuffer(handle, out var holder))
|
if (TryGetBuffer(handle, out var holder))
|
||||||
|
|
|
@ -7,28 +7,28 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
public static BufferState Null => new BufferState(null, 0, 0);
|
public static BufferState Null => new BufferState(null, 0, 0);
|
||||||
|
|
||||||
private readonly Auto<DisposableBuffer> _buffer;
|
|
||||||
private readonly int _offset;
|
private readonly int _offset;
|
||||||
private readonly int _size;
|
private readonly int _size;
|
||||||
private readonly ulong _stride;
|
|
||||||
private readonly IndexType _type;
|
private readonly IndexType _type;
|
||||||
|
|
||||||
|
private readonly Auto<DisposableBuffer> _buffer;
|
||||||
|
|
||||||
public BufferState(Auto<DisposableBuffer> buffer, int offset, int size, IndexType type)
|
public BufferState(Auto<DisposableBuffer> buffer, int offset, int size, IndexType type)
|
||||||
{
|
{
|
||||||
_buffer = buffer;
|
_buffer = buffer;
|
||||||
|
|
||||||
_offset = offset;
|
_offset = offset;
|
||||||
_size = size;
|
_size = size;
|
||||||
_stride = 0;
|
|
||||||
_type = type;
|
_type = type;
|
||||||
buffer?.IncrementReferenceCount();
|
buffer?.IncrementReferenceCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
public BufferState(Auto<DisposableBuffer> buffer, int offset, int size, ulong stride = 0UL)
|
public BufferState(Auto<DisposableBuffer> buffer, int offset, int size)
|
||||||
{
|
{
|
||||||
_buffer = buffer;
|
_buffer = buffer;
|
||||||
|
|
||||||
_offset = offset;
|
_offset = offset;
|
||||||
_size = size;
|
_size = size;
|
||||||
_stride = stride;
|
|
||||||
_type = IndexType.Uint16;
|
_type = IndexType.Uint16;
|
||||||
buffer?.IncrementReferenceCount();
|
buffer?.IncrementReferenceCount();
|
||||||
}
|
}
|
||||||
|
@ -51,30 +51,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BindVertexBuffer(VulkanRenderer gd, CommandBufferScoped cbs, uint binding)
|
|
||||||
{
|
|
||||||
if (_buffer != null)
|
|
||||||
{
|
|
||||||
var buffer = _buffer.Get(cbs, _offset, _size).Value;
|
|
||||||
|
|
||||||
if (gd.Capabilities.SupportsExtendedDynamicState)
|
|
||||||
{
|
|
||||||
gd.ExtendedDynamicStateApi.CmdBindVertexBuffers2(
|
|
||||||
cbs.CommandBuffer,
|
|
||||||
binding,
|
|
||||||
1,
|
|
||||||
buffer,
|
|
||||||
(ulong)_offset,
|
|
||||||
(ulong)_size,
|
|
||||||
_stride);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gd.Api.CmdBindVertexBuffers(cbs.CommandBuffer, binding, 1, buffer, (ulong)_offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_buffer?.DecrementReferenceCount();
|
_buffer?.DecrementReferenceCount();
|
||||||
|
|
|
@ -3,29 +3,110 @@ using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Vulkan
|
namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
struct CacheByRange<T> where T : IDisposable
|
interface ICacheKey : IDisposable
|
||||||
{
|
{
|
||||||
private Dictionary<ulong, T> _ranges;
|
bool KeyEqual(ICacheKey other);
|
||||||
|
}
|
||||||
|
|
||||||
public void Add(int offset, int size, T value)
|
struct I8ToI16CacheKey : ICacheKey
|
||||||
|
{
|
||||||
|
public I8ToI16CacheKey() { }
|
||||||
|
|
||||||
|
public bool KeyEqual(ICacheKey other)
|
||||||
{
|
{
|
||||||
EnsureInitialized();
|
return other is I8ToI16CacheKey;
|
||||||
_ranges.Add(PackRange(offset, size), value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetValue(int offset, int size, out T value)
|
public void Dispose() { }
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AlignedVertexBufferCacheKey : ICacheKey
|
||||||
|
{
|
||||||
|
private readonly int _stride;
|
||||||
|
private readonly int _alignment;
|
||||||
|
|
||||||
|
// Used to notify the pipeline that bindings have invalidated on dispose.
|
||||||
|
private readonly VulkanRenderer _gd;
|
||||||
|
private Auto<DisposableBuffer> _buffer;
|
||||||
|
|
||||||
|
public AlignedVertexBufferCacheKey(VulkanRenderer gd, int stride, int alignment)
|
||||||
{
|
{
|
||||||
EnsureInitialized();
|
_gd = gd;
|
||||||
return _ranges.TryGetValue(PackRange(offset, size), out value);
|
_stride = stride;
|
||||||
|
_alignment = alignment;
|
||||||
|
_buffer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool KeyEqual(ICacheKey other)
|
||||||
|
{
|
||||||
|
return other is AlignedVertexBufferCacheKey entry &&
|
||||||
|
entry._stride == _stride &&
|
||||||
|
entry._alignment == _alignment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetBuffer(Auto<DisposableBuffer> buffer)
|
||||||
|
{
|
||||||
|
_buffer = buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_gd.PipelineInternal.DirtyVertexBuffer(_buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CacheByRange<T> where T : IDisposable
|
||||||
|
{
|
||||||
|
private struct Entry
|
||||||
|
{
|
||||||
|
public ICacheKey Key;
|
||||||
|
public T Value;
|
||||||
|
|
||||||
|
public Entry(ICacheKey key, T value)
|
||||||
|
{
|
||||||
|
Key = key;
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<ulong, List<Entry>> _ranges;
|
||||||
|
|
||||||
|
public void Add(int offset, int size, ICacheKey key, T value)
|
||||||
|
{
|
||||||
|
List<Entry> entries = GetEntries(offset, size);
|
||||||
|
|
||||||
|
entries.Add(new Entry(key, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetValue(int offset, int size, ICacheKey key, out T value)
|
||||||
|
{
|
||||||
|
List<Entry> entries = GetEntries(offset, size);
|
||||||
|
|
||||||
|
foreach (Entry entry in entries)
|
||||||
|
{
|
||||||
|
if (entry.Key.KeyEqual(key))
|
||||||
|
{
|
||||||
|
value = entry.Value;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
value = default;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
if (_ranges != null)
|
if (_ranges != null)
|
||||||
{
|
{
|
||||||
foreach (T value in _ranges.Values)
|
foreach (List<Entry> entries in _ranges.Values)
|
||||||
{
|
{
|
||||||
value.Dispose();
|
foreach (Entry entry in entries)
|
||||||
|
{
|
||||||
|
entry.Key.Dispose();
|
||||||
|
entry.Value.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ranges.Clear();
|
_ranges.Clear();
|
||||||
|
@ -33,12 +114,23 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EnsureInitialized()
|
private List<Entry> GetEntries(int offset, int size)
|
||||||
{
|
{
|
||||||
if (_ranges == null)
|
if (_ranges == null)
|
||||||
{
|
{
|
||||||
_ranges = new Dictionary<ulong, T>();
|
_ranges = new Dictionary<ulong, List<Entry>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ulong key = PackRange(offset, size);
|
||||||
|
|
||||||
|
List<Entry> value;
|
||||||
|
if (!_ranges.TryGetValue(key, out value))
|
||||||
|
{
|
||||||
|
value = new List<Entry>();
|
||||||
|
_ranges.Add(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ulong PackRange(int offset, int size)
|
private static ulong PackRange(int offset, int size)
|
||||||
|
|
|
@ -185,6 +185,34 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
SignalDirty(DirtyFlags.Storage);
|
SignalDirty(DirtyFlags.Storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetStorageBuffers(CommandBuffer commandBuffer, int first, ReadOnlySpan<Auto<DisposableBuffer>> buffers)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < buffers.Length; i++)
|
||||||
|
{
|
||||||
|
var vkBuffer = buffers[i];
|
||||||
|
int index = first + i;
|
||||||
|
|
||||||
|
ref Auto<DisposableBuffer> currentVkBuffer = ref _storageBufferRefs[index];
|
||||||
|
|
||||||
|
DescriptorBufferInfo info = new DescriptorBufferInfo()
|
||||||
|
{
|
||||||
|
Offset = 0,
|
||||||
|
Range = Vk.WholeSize
|
||||||
|
};
|
||||||
|
ref DescriptorBufferInfo currentInfo = ref _storageBuffers[index];
|
||||||
|
|
||||||
|
if (vkBuffer != currentVkBuffer || currentInfo.Offset != info.Offset || currentInfo.Range != info.Range)
|
||||||
|
{
|
||||||
|
_storageSet[index] = false;
|
||||||
|
|
||||||
|
currentInfo = info;
|
||||||
|
currentVkBuffer = vkBuffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SignalDirty(DirtyFlags.Storage);
|
||||||
|
}
|
||||||
|
|
||||||
public void SetTextureAndSampler(CommandBufferScoped cbs, ShaderStage stage, int binding, ITexture texture, ISampler sampler)
|
public void SetTextureAndSampler(CommandBufferScoped cbs, ShaderStage stage, int binding, ITexture texture, ISampler sampler)
|
||||||
{
|
{
|
||||||
if (texture == null)
|
if (texture == null)
|
||||||
|
@ -388,7 +416,14 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadOnlySpan<DescriptorBufferInfo> storageBuffers = _storageBuffers;
|
ReadOnlySpan<DescriptorBufferInfo> storageBuffers = _storageBuffers;
|
||||||
dsc.UpdateStorageBuffers(0, binding, storageBuffers.Slice(binding, count));
|
if (program.HasMinimalLayout)
|
||||||
|
{
|
||||||
|
dsc.UpdateBuffers(0, binding, storageBuffers.Slice(binding, count), DescriptorType.StorageBuffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dsc.UpdateStorageBuffers(0, binding, storageBuffers.Slice(binding, count));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (setIndex == PipelineBase.TextureSetIndex)
|
else if (setIndex == PipelineBase.TextureSetIndex)
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,6 +10,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
public readonly bool SupportsFragmentShaderInterlock;
|
public readonly bool SupportsFragmentShaderInterlock;
|
||||||
public readonly bool SupportsGeometryShaderPassthrough;
|
public readonly bool SupportsGeometryShaderPassthrough;
|
||||||
public readonly bool SupportsSubgroupSizeControl;
|
public readonly bool SupportsSubgroupSizeControl;
|
||||||
|
public readonly bool SupportsShaderInt8;
|
||||||
public readonly bool SupportsConditionalRendering;
|
public readonly bool SupportsConditionalRendering;
|
||||||
public readonly bool SupportsExtendedDynamicState;
|
public readonly bool SupportsExtendedDynamicState;
|
||||||
public readonly bool SupportsMultiView;
|
public readonly bool SupportsMultiView;
|
||||||
|
@ -29,6 +30,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
bool supportsFragmentShaderInterlock,
|
bool supportsFragmentShaderInterlock,
|
||||||
bool supportsGeometryShaderPassthrough,
|
bool supportsGeometryShaderPassthrough,
|
||||||
bool supportsSubgroupSizeControl,
|
bool supportsSubgroupSizeControl,
|
||||||
|
bool supportsShaderInt8,
|
||||||
bool supportsConditionalRendering,
|
bool supportsConditionalRendering,
|
||||||
bool supportsExtendedDynamicState,
|
bool supportsExtendedDynamicState,
|
||||||
bool supportsMultiView,
|
bool supportsMultiView,
|
||||||
|
@ -47,6 +49,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
SupportsFragmentShaderInterlock = supportsFragmentShaderInterlock;
|
SupportsFragmentShaderInterlock = supportsFragmentShaderInterlock;
|
||||||
SupportsGeometryShaderPassthrough = supportsGeometryShaderPassthrough;
|
SupportsGeometryShaderPassthrough = supportsGeometryShaderPassthrough;
|
||||||
SupportsSubgroupSizeControl = supportsSubgroupSizeControl;
|
SupportsSubgroupSizeControl = supportsSubgroupSizeControl;
|
||||||
|
SupportsShaderInt8 = supportsShaderInt8;
|
||||||
SupportsConditionalRendering = supportsConditionalRendering;
|
SupportsConditionalRendering = supportsConditionalRendering;
|
||||||
SupportsExtendedDynamicState = supportsExtendedDynamicState;
|
SupportsExtendedDynamicState = supportsExtendedDynamicState;
|
||||||
SupportsMultiView = supportsMultiView;
|
SupportsMultiView = supportsMultiView;
|
||||||
|
|
|
@ -16,6 +16,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
private readonly IProgram _programColorBlit;
|
private readonly IProgram _programColorBlit;
|
||||||
private readonly IProgram _programColorBlitClearAlpha;
|
private readonly IProgram _programColorBlitClearAlpha;
|
||||||
private readonly IProgram _programColorClear;
|
private readonly IProgram _programColorClear;
|
||||||
|
private readonly IProgram _programStrideChange;
|
||||||
|
|
||||||
public HelperShader(VulkanRenderer gd, Device device)
|
public HelperShader(VulkanRenderer gd, Device device)
|
||||||
{
|
{
|
||||||
|
@ -39,14 +40,14 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
_programColorBlit = gd.CreateProgramWithMinimalLayout(new[]
|
_programColorBlit = gd.CreateProgramWithMinimalLayout(new[]
|
||||||
{
|
{
|
||||||
new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Glsl),
|
new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||||
new ShaderSource(ShaderBinaries.ColorBlitFragmentShaderSource, fragmentBindings, ShaderStage.Fragment, TargetLanguage.Glsl),
|
new ShaderSource(ShaderBinaries.ColorBlitFragmentShaderSource, fragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||||
});
|
});
|
||||||
|
|
||||||
_programColorBlitClearAlpha = gd.CreateProgramWithMinimalLayout(new[]
|
_programColorBlitClearAlpha = gd.CreateProgramWithMinimalLayout(new[]
|
||||||
{
|
{
|
||||||
new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Glsl),
|
new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||||
new ShaderSource(ShaderBinaries.ColorBlitClearAlphaFragmentShaderSource, fragmentBindings, ShaderStage.Fragment, TargetLanguage.Glsl),
|
new ShaderSource(ShaderBinaries.ColorBlitClearAlphaFragmentShaderSource, fragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||||
});
|
});
|
||||||
|
|
||||||
var fragmentBindings2 = new ShaderBindings(
|
var fragmentBindings2 = new ShaderBindings(
|
||||||
|
@ -57,8 +58,19 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
_programColorClear = gd.CreateProgramWithMinimalLayout(new[]
|
_programColorClear = gd.CreateProgramWithMinimalLayout(new[]
|
||||||
{
|
{
|
||||||
new ShaderSource(ShaderBinaries.ColorClearVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Glsl),
|
new ShaderSource(ShaderBinaries.ColorClearVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv),
|
||||||
new ShaderSource(ShaderBinaries.ColorClearFragmentShaderSource, fragmentBindings2, ShaderStage.Fragment, TargetLanguage.Glsl),
|
new ShaderSource(ShaderBinaries.ColorClearFragmentShaderSource, fragmentBindings2, ShaderStage.Fragment, TargetLanguage.Spirv),
|
||||||
|
});
|
||||||
|
|
||||||
|
var strideChangeBindings = new ShaderBindings(
|
||||||
|
new[] { 0 },
|
||||||
|
new[] { 1, 2 },
|
||||||
|
Array.Empty<int>(),
|
||||||
|
Array.Empty<int>());
|
||||||
|
|
||||||
|
_programStrideChange = gd.CreateProgramWithMinimalLayout(new[]
|
||||||
|
{
|
||||||
|
new ShaderSource(ShaderBinaries.ChangeBufferStrideShaderSource, strideChangeBindings, ShaderStage.Compute, TargetLanguage.Spirv),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,7 +175,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_pipeline.SetViewports(viewports, false);
|
_pipeline.SetViewports(viewports, false);
|
||||||
_pipeline.SetPrimitiveTopology(GAL.PrimitiveTopology.TriangleStrip);
|
_pipeline.SetPrimitiveTopology(GAL.PrimitiveTopology.TriangleStrip);
|
||||||
_pipeline.Draw(4, 1, 0, 0);
|
_pipeline.Draw(4, 1, 0, 0);
|
||||||
_pipeline.Finish();
|
_pipeline.Finish(gd, cbs);
|
||||||
|
|
||||||
gd.BufferManager.Delete(bufferHandle);
|
gd.BufferManager.Delete(bufferHandle);
|
||||||
}
|
}
|
||||||
|
@ -291,45 +303,100 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
public unsafe void ConvertI8ToI16(VulkanRenderer gd, CommandBufferScoped cbs, BufferHolder src, BufferHolder dst, int srcOffset, int size)
|
public unsafe void ConvertI8ToI16(VulkanRenderer gd, CommandBufferScoped cbs, BufferHolder src, BufferHolder dst, int srcOffset, int size)
|
||||||
{
|
{
|
||||||
// TODO: Do this with a compute shader?
|
ChangeStride(gd, cbs, src, dst, srcOffset, size, 1, 2);
|
||||||
var srcBuffer = src.GetBuffer().Get(cbs, srcOffset, size).Value;
|
}
|
||||||
var dstBuffer = dst.GetBuffer().Get(cbs, 0, size * 2).Value;
|
|
||||||
|
|
||||||
gd.Api.CmdFillBuffer(cbs.CommandBuffer, dstBuffer, 0, Vk.WholeSize, 0);
|
public unsafe void ChangeStride(VulkanRenderer gd, CommandBufferScoped cbs, BufferHolder src, BufferHolder dst, int srcOffset, int size, int stride, int newStride)
|
||||||
|
{
|
||||||
|
bool supportsUint8 = gd.Capabilities.SupportsShaderInt8;
|
||||||
|
|
||||||
var bufferCopy = new BufferCopy[size];
|
int elems = size / stride;
|
||||||
|
int newSize = elems * newStride;
|
||||||
|
|
||||||
for (ulong i = 0; i < (ulong)size; i++)
|
var srcBufferAuto = src.GetBuffer();
|
||||||
{
|
var dstBufferAuto = dst.GetBuffer();
|
||||||
bufferCopy[i] = new BufferCopy((ulong)srcOffset + i, i * 2, 1);
|
|
||||||
}
|
var srcBuffer = srcBufferAuto.Get(cbs, srcOffset, size).Value;
|
||||||
|
var dstBuffer = dstBufferAuto.Get(cbs, 0, newSize).Value;
|
||||||
|
|
||||||
|
var access = supportsUint8 ? AccessFlags.AccessShaderWriteBit : AccessFlags.AccessTransferWriteBit;
|
||||||
|
var stage = supportsUint8 ? PipelineStageFlags.PipelineStageComputeShaderBit : PipelineStageFlags.PipelineStageTransferBit;
|
||||||
|
|
||||||
BufferHolder.InsertBufferBarrier(
|
BufferHolder.InsertBufferBarrier(
|
||||||
gd,
|
gd,
|
||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
dstBuffer,
|
dstBuffer,
|
||||||
BufferHolder.DefaultAccessFlags,
|
BufferHolder.DefaultAccessFlags,
|
||||||
AccessFlags.AccessTransferWriteBit,
|
access,
|
||||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
PipelineStageFlags.PipelineStageAllCommandsBit,
|
||||||
PipelineStageFlags.PipelineStageTransferBit,
|
stage,
|
||||||
0,
|
0,
|
||||||
size * 2);
|
newSize);
|
||||||
|
|
||||||
fixed (BufferCopy* pBufferCopy = bufferCopy)
|
if (supportsUint8)
|
||||||
{
|
{
|
||||||
gd.Api.CmdCopyBuffer(cbs.CommandBuffer, srcBuffer, dstBuffer, (uint)size, pBufferCopy);
|
const int ParamsBufferSize = 16;
|
||||||
|
|
||||||
|
Span<int> shaderParams = stackalloc int[ParamsBufferSize / sizeof(int)];
|
||||||
|
|
||||||
|
shaderParams[0] = stride;
|
||||||
|
shaderParams[1] = newStride;
|
||||||
|
shaderParams[2] = size;
|
||||||
|
shaderParams[3] = srcOffset;
|
||||||
|
|
||||||
|
var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize, false);
|
||||||
|
|
||||||
|
gd.BufferManager.SetData<int>(bufferHandle, 0, shaderParams);
|
||||||
|
|
||||||
|
_pipeline.SetCommandBuffer(cbs);
|
||||||
|
|
||||||
|
Span<BufferRange> cbRanges = stackalloc BufferRange[1];
|
||||||
|
|
||||||
|
cbRanges[0] = new BufferRange(bufferHandle, 0, ParamsBufferSize);
|
||||||
|
|
||||||
|
_pipeline.SetUniformBuffers(0, cbRanges);
|
||||||
|
|
||||||
|
Span<Auto<DisposableBuffer>> sbRanges = new Auto<DisposableBuffer>[2];
|
||||||
|
|
||||||
|
sbRanges[0] = srcBufferAuto;
|
||||||
|
sbRanges[1] = dstBufferAuto;
|
||||||
|
|
||||||
|
_pipeline.SetStorageBuffers(1, sbRanges);
|
||||||
|
|
||||||
|
_pipeline.SetProgram(_programStrideChange);
|
||||||
|
_pipeline.DispatchCompute(1, 1, 1);
|
||||||
|
|
||||||
|
gd.BufferManager.Delete(bufferHandle);
|
||||||
|
|
||||||
|
_pipeline.Finish(gd, cbs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gd.Api.CmdFillBuffer(cbs.CommandBuffer, dstBuffer, 0, Vk.WholeSize, 0);
|
||||||
|
|
||||||
|
var bufferCopy = new BufferCopy[elems];
|
||||||
|
|
||||||
|
for (ulong i = 0; i < (ulong)elems; i++)
|
||||||
|
{
|
||||||
|
bufferCopy[i] = new BufferCopy((ulong)srcOffset + i * (ulong)stride, i * (ulong)newStride, (ulong)stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
fixed (BufferCopy* pBufferCopy = bufferCopy)
|
||||||
|
{
|
||||||
|
gd.Api.CmdCopyBuffer(cbs.CommandBuffer, srcBuffer, dstBuffer, (uint)elems, pBufferCopy);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferHolder.InsertBufferBarrier(
|
BufferHolder.InsertBufferBarrier(
|
||||||
gd,
|
gd,
|
||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
dstBuffer,
|
dstBuffer,
|
||||||
AccessFlags.AccessTransferWriteBit,
|
access,
|
||||||
BufferHolder.DefaultAccessFlags,
|
BufferHolder.DefaultAccessFlags,
|
||||||
PipelineStageFlags.PipelineStageTransferBit,
|
stage,
|
||||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
PipelineStageFlags.PipelineStageAllCommandsBit,
|
||||||
0,
|
0,
|
||||||
size * 2);
|
newSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
protected virtual void Dispose(bool disposing)
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
using Ryujinx.Graphics.Shader;
|
using Ryujinx.Graphics.Shader;
|
||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Vulkan
|
namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
|
@ -50,14 +51,14 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
private BufferState _indexBuffer;
|
private BufferState _indexBuffer;
|
||||||
private readonly BufferState[] _transformFeedbackBuffers;
|
private readonly BufferState[] _transformFeedbackBuffers;
|
||||||
private readonly BufferState[] _vertexBuffers;
|
private readonly VertexBufferState[] _vertexBuffers;
|
||||||
|
private ulong _vertexBuffersDirty;
|
||||||
protected Rectangle<int> ClearScissor;
|
protected Rectangle<int> ClearScissor;
|
||||||
|
|
||||||
public SupportBufferUpdater SupportBufferUpdater;
|
public SupportBufferUpdater SupportBufferUpdater;
|
||||||
|
|
||||||
private bool _needsIndexBufferRebind;
|
private bool _needsIndexBufferRebind;
|
||||||
private bool _needsTransformFeedbackBuffersRebind;
|
private bool _needsTransformFeedbackBuffersRebind;
|
||||||
private bool _needsVertexBuffersRebind;
|
|
||||||
|
|
||||||
private bool _tfEnabled;
|
private bool _tfEnabled;
|
||||||
private bool _tfActive;
|
private bool _tfActive;
|
||||||
|
@ -79,14 +80,14 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_descriptorSetUpdater = new DescriptorSetUpdater(gd, this);
|
_descriptorSetUpdater = new DescriptorSetUpdater(gd, this);
|
||||||
|
|
||||||
_transformFeedbackBuffers = new BufferState[Constants.MaxTransformFeedbackBuffers];
|
_transformFeedbackBuffers = new BufferState[Constants.MaxTransformFeedbackBuffers];
|
||||||
_vertexBuffers = new BufferState[Constants.MaxVertexBuffers + 1];
|
_vertexBuffers = new VertexBufferState[Constants.MaxVertexBuffers + 1];
|
||||||
|
|
||||||
const int EmptyVbSize = 16;
|
const int EmptyVbSize = 16;
|
||||||
|
|
||||||
using var emptyVb = gd.BufferManager.Create(gd, EmptyVbSize);
|
using var emptyVb = gd.BufferManager.Create(gd, EmptyVbSize);
|
||||||
emptyVb.SetData(0, new byte[EmptyVbSize]);
|
emptyVb.SetData(0, new byte[EmptyVbSize]);
|
||||||
_vertexBuffers[0] = new BufferState(emptyVb.GetBuffer(), 0, EmptyVbSize, 0UL);
|
_vertexBuffers[0] = new VertexBufferState(emptyVb.GetBuffer(), 0, EmptyVbSize, 0);
|
||||||
_needsVertexBuffersRebind = true;
|
_vertexBuffersDirty = ulong.MaxValue >> (64 - _vertexBuffers.Length);
|
||||||
|
|
||||||
ClearScissor = new Rectangle<int>(0, 0, 0xffff, 0xffff);
|
ClearScissor = new Rectangle<int>(0, 0, 0xffff, 0xffff);
|
||||||
|
|
||||||
|
@ -229,6 +230,17 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
BufferHolder.Copy(Gd, Cbs, src, dst, srcOffset, dstOffset, size);
|
BufferHolder.Copy(Gd, Cbs, src, dst, srcOffset, dstOffset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DirtyVertexBuffer(Auto<DisposableBuffer> buffer)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _vertexBuffers.Length; i++)
|
||||||
|
{
|
||||||
|
if (_vertexBuffers[i].BoundEquals(buffer))
|
||||||
|
{
|
||||||
|
_vertexBuffersDirty |= 1UL << i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void DispatchCompute(int groupsX, int groupsY, int groupsZ)
|
public void DispatchCompute(int groupsX, int groupsY, int groupsZ)
|
||||||
{
|
{
|
||||||
if (!_program.IsLinked)
|
if (!_program.IsLinked)
|
||||||
|
@ -345,6 +357,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_tfEnabled = false;
|
_tfEnabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsCommandBufferActive(CommandBuffer cb)
|
||||||
|
{
|
||||||
|
return CommandBuffer.Handle == cb.Handle;
|
||||||
|
}
|
||||||
|
|
||||||
public void MultiDrawIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
|
public void MultiDrawIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
|
||||||
{
|
{
|
||||||
if (!Gd.Capabilities.SupportsIndirectParameters)
|
if (!Gd.Capabilities.SupportsIndirectParameters)
|
||||||
|
@ -689,6 +706,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_descriptorSetUpdater.SetStorageBuffers(CommandBuffer, first, buffers);
|
_descriptorSetUpdater.SetStorageBuffers(CommandBuffer, first, buffers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetStorageBuffers(int first, ReadOnlySpan<Auto<DisposableBuffer>> buffers)
|
||||||
|
{
|
||||||
|
_descriptorSetUpdater.SetStorageBuffers(CommandBuffer, first, buffers);
|
||||||
|
}
|
||||||
|
|
||||||
public void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler)
|
public void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler)
|
||||||
{
|
{
|
||||||
_descriptorSetUpdater.SetTextureAndSampler(Cbs, stage, binding, texture, sampler);
|
_descriptorSetUpdater.SetTextureAndSampler(Cbs, stage, binding, texture, sampler);
|
||||||
|
@ -732,12 +754,22 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
var formatCapabilities = Gd.FormatCapabilities;
|
var formatCapabilities = Gd.FormatCapabilities;
|
||||||
|
|
||||||
|
Span<int> newVbScalarSizes = stackalloc int[Constants.MaxVertexBuffers];
|
||||||
|
|
||||||
int count = Math.Min(Constants.MaxVertexAttributes, vertexAttribs.Length);
|
int count = Math.Min(Constants.MaxVertexAttributes, vertexAttribs.Length);
|
||||||
|
uint dirtyVbSizes = 0;
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
var attribute = vertexAttribs[i];
|
var attribute = vertexAttribs[i];
|
||||||
var bufferIndex = attribute.IsZero ? 0 : attribute.BufferIndex + 1;
|
var rawIndex = attribute.BufferIndex;
|
||||||
|
var bufferIndex = attribute.IsZero ? 0 : rawIndex + 1;
|
||||||
|
|
||||||
|
if (!attribute.IsZero)
|
||||||
|
{
|
||||||
|
newVbScalarSizes[rawIndex] = Math.Max(newVbScalarSizes[rawIndex], attribute.Format.GetScalarSize());
|
||||||
|
dirtyVbSizes |= 1u << rawIndex;
|
||||||
|
}
|
||||||
|
|
||||||
_newState.Internal.VertexAttributeDescriptions[i] = new VertexInputAttributeDescription(
|
_newState.Internal.VertexAttributeDescriptions[i] = new VertexInputAttributeDescription(
|
||||||
(uint)i,
|
(uint)i,
|
||||||
|
@ -746,6 +778,21 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
(uint)attribute.Offset);
|
(uint)attribute.Offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (dirtyVbSizes != 0)
|
||||||
|
{
|
||||||
|
int dirtyBit = BitOperations.TrailingZeroCount(dirtyVbSizes);
|
||||||
|
|
||||||
|
ref var buffer = ref _vertexBuffers[dirtyBit + 1];
|
||||||
|
|
||||||
|
if (buffer.AttributeScalarAlignment != newVbScalarSizes[dirtyBit])
|
||||||
|
{
|
||||||
|
_vertexBuffersDirty |= 1UL << (dirtyBit + 1);
|
||||||
|
buffer.AttributeScalarAlignment = newVbScalarSizes[dirtyBit];
|
||||||
|
}
|
||||||
|
|
||||||
|
dirtyVbSizes &= ~(1u << dirtyBit);
|
||||||
|
}
|
||||||
|
|
||||||
_newState.VertexAttributeDescriptionsCount = (uint)count;
|
_newState.VertexAttributeDescriptionsCount = (uint)count;
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
}
|
}
|
||||||
|
@ -792,14 +839,37 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_vertexBuffers[binding].Dispose();
|
ref var buffer = ref _vertexBuffers[binding];
|
||||||
_vertexBuffers[binding] = new BufferState(
|
int oldScalarAlign = buffer.AttributeScalarAlignment;
|
||||||
vb,
|
|
||||||
vertexBuffer.Buffer.Offset,
|
|
||||||
vbSize,
|
|
||||||
(ulong)vertexBuffer.Stride);
|
|
||||||
|
|
||||||
_vertexBuffers[binding].BindVertexBuffer(Gd, Cbs, (uint)binding);
|
buffer.Dispose();
|
||||||
|
|
||||||
|
if ((vertexBuffer.Stride % FormatExtensions.MaxBufferFormatScalarSize) == 0)
|
||||||
|
{
|
||||||
|
buffer = new VertexBufferState(
|
||||||
|
vb,
|
||||||
|
descriptorIndex,
|
||||||
|
vertexBuffer.Buffer.Offset,
|
||||||
|
vbSize,
|
||||||
|
vertexBuffer.Stride);
|
||||||
|
|
||||||
|
buffer.BindVertexBuffer(Gd, Cbs, (uint)binding, ref _newState);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// May need to be rewritten. Bind this buffer before draw.
|
||||||
|
|
||||||
|
buffer = new VertexBufferState(
|
||||||
|
vertexBuffer.Buffer.Handle,
|
||||||
|
descriptorIndex,
|
||||||
|
vertexBuffer.Buffer.Offset,
|
||||||
|
vbSize,
|
||||||
|
vertexBuffer.Stride);
|
||||||
|
|
||||||
|
_vertexBuffersDirty |= 1UL << binding;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.AttributeScalarAlignment = oldScalarAlign;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -907,7 +977,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
_needsIndexBufferRebind = true;
|
_needsIndexBufferRebind = true;
|
||||||
_needsTransformFeedbackBuffersRebind = true;
|
_needsTransformFeedbackBuffersRebind = true;
|
||||||
_needsVertexBuffersRebind = true;
|
_vertexBuffersDirty = ulong.MaxValue >> (64 - _vertexBuffers.Length);
|
||||||
|
|
||||||
_descriptorSetUpdater.SignalCommandBufferChange();
|
_descriptorSetUpdater.SignalCommandBufferChange();
|
||||||
_dynamicState.ForceAllDirty();
|
_dynamicState.ForceAllDirty();
|
||||||
|
@ -1053,13 +1123,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
// Commit changes to the support buffer before drawing.
|
// Commit changes to the support buffer before drawing.
|
||||||
SupportBufferUpdater.Commit();
|
SupportBufferUpdater.Commit();
|
||||||
|
|
||||||
if (_stateDirty || Pbp != pbp)
|
|
||||||
{
|
|
||||||
CreatePipeline(pbp);
|
|
||||||
_stateDirty = false;
|
|
||||||
Pbp = pbp;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_needsIndexBufferRebind)
|
if (_needsIndexBufferRebind)
|
||||||
{
|
{
|
||||||
_indexBuffer.BindIndexBuffer(Gd.Api, Cbs);
|
_indexBuffer.BindIndexBuffer(Gd.Api, Cbs);
|
||||||
|
@ -1078,14 +1141,23 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_needsTransformFeedbackBuffersRebind = false;
|
_needsTransformFeedbackBuffersRebind = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_needsVertexBuffersRebind)
|
if (_vertexBuffersDirty != 0)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < Constants.MaxVertexBuffers + 1; i++)
|
while (_vertexBuffersDirty != 0)
|
||||||
{
|
{
|
||||||
_vertexBuffers[i].BindVertexBuffer(Gd, Cbs, (uint)i);
|
int i = BitOperations.TrailingZeroCount(_vertexBuffersDirty);
|
||||||
}
|
|
||||||
|
|
||||||
_needsVertexBuffersRebind = false;
|
_vertexBuffers[i].BindVertexBuffer(Gd, Cbs, (uint)i, ref _newState);
|
||||||
|
|
||||||
|
_vertexBuffersDirty &= ~(1u << i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_stateDirty || Pbp != pbp)
|
||||||
|
{
|
||||||
|
CreatePipeline(pbp);
|
||||||
|
_stateDirty = false;
|
||||||
|
Pbp = pbp;
|
||||||
}
|
}
|
||||||
|
|
||||||
_descriptorSetUpdater.UpdateAndBindDescriptorSets(Cbs, pbp);
|
_descriptorSetUpdater.UpdateAndBindDescriptorSets(Cbs, pbp);
|
||||||
|
|
|
@ -202,6 +202,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
pipeline.Topology = state.Topology.Convert();
|
pipeline.Topology = state.Topology.Convert();
|
||||||
|
|
||||||
int vaCount = Math.Min(Constants.MaxVertexAttributes, state.VertexAttribCount);
|
int vaCount = Math.Min(Constants.MaxVertexAttributes, state.VertexAttribCount);
|
||||||
|
int vbCount = Math.Min(Constants.MaxVertexBuffers, state.VertexBufferCount);
|
||||||
|
|
||||||
|
Span<int> vbScalarSizes = stackalloc int[vbCount];
|
||||||
|
|
||||||
for (int i = 0; i < vaCount; i++)
|
for (int i = 0; i < vaCount; i++)
|
||||||
{
|
{
|
||||||
|
@ -213,13 +216,16 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
(uint)bufferIndex,
|
(uint)bufferIndex,
|
||||||
gd.FormatCapabilities.ConvertToVertexVkFormat(attribute.Format),
|
gd.FormatCapabilities.ConvertToVertexVkFormat(attribute.Format),
|
||||||
(uint)attribute.Offset);
|
(uint)attribute.Offset);
|
||||||
|
|
||||||
|
if (!attribute.IsZero && bufferIndex < vbCount)
|
||||||
|
{
|
||||||
|
vbScalarSizes[bufferIndex - 1] = Math.Max(attribute.Format.GetScalarSize(), vbScalarSizes[bufferIndex - 1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int descriptorIndex = 1;
|
int descriptorIndex = 1;
|
||||||
pipeline.Internal.VertexBindingDescriptions[0] = new VertexInputBindingDescription(0, 0, VertexInputRate.Vertex);
|
pipeline.Internal.VertexBindingDescriptions[0] = new VertexInputBindingDescription(0, 0, VertexInputRate.Vertex);
|
||||||
|
|
||||||
int vbCount = Math.Min(Constants.MaxVertexBuffers, state.VertexBufferCount);
|
|
||||||
|
|
||||||
for (int i = 0; i < vbCount; i++)
|
for (int i = 0; i < vbCount; i++)
|
||||||
{
|
{
|
||||||
var vertexBuffer = state.VertexBuffers[i];
|
var vertexBuffer = state.VertexBuffers[i];
|
||||||
|
@ -228,10 +234,17 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
var inputRate = vertexBuffer.Divisor != 0 ? VertexInputRate.Instance : VertexInputRate.Vertex;
|
var inputRate = vertexBuffer.Divisor != 0 ? VertexInputRate.Instance : VertexInputRate.Vertex;
|
||||||
|
|
||||||
|
int alignedStride = vertexBuffer.Stride;
|
||||||
|
|
||||||
|
if (gd.NeedsVertexBufferAlignment(vbScalarSizes[i], out int alignment))
|
||||||
|
{
|
||||||
|
alignedStride = (vertexBuffer.Stride + (alignment - 1)) & -alignment;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Support divisor > 1
|
// TODO: Support divisor > 1
|
||||||
pipeline.Internal.VertexBindingDescriptions[descriptorIndex++] = new VertexInputBindingDescription(
|
pipeline.Internal.VertexBindingDescriptions[descriptorIndex++] = new VertexInputBindingDescription(
|
||||||
(uint)i + 1,
|
(uint)i + 1,
|
||||||
(uint)vertexBuffer.Stride,
|
(uint)alignedStride,
|
||||||
inputRate);
|
inputRate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,6 +199,16 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Restore()
|
||||||
|
{
|
||||||
|
if (Pipeline != null)
|
||||||
|
{
|
||||||
|
Gd.Api.CmdBindPipeline(CommandBuffer, Pbp, Pipeline.Get(Cbs).Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
SignalCommandBufferChange();
|
||||||
|
}
|
||||||
|
|
||||||
public void FlushCommandsImpl()
|
public void FlushCommandsImpl()
|
||||||
{
|
{
|
||||||
EndRenderPass();
|
EndRenderPass();
|
||||||
|
@ -220,18 +230,13 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
// Restore per-command buffer state.
|
// Restore per-command buffer state.
|
||||||
|
|
||||||
if (Pipeline != null)
|
|
||||||
{
|
|
||||||
Gd.Api.CmdBindPipeline(CommandBuffer, Pbp, Pipeline.Get(Cbs).Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var queryPool in _activeQueries)
|
foreach (var queryPool in _activeQueries)
|
||||||
{
|
{
|
||||||
Gd.Api.CmdResetQueryPool(CommandBuffer, queryPool, 0, 1);
|
Gd.Api.CmdResetQueryPool(CommandBuffer, queryPool, 0, 1);
|
||||||
Gd.Api.CmdBeginQuery(CommandBuffer, queryPool, 0, 0);
|
Gd.Api.CmdBeginQuery(CommandBuffer, queryPool, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
SignalCommandBufferChange();
|
Restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BeginQuery(BufferedQuery query, QueryPool pool, bool needsReset)
|
public void BeginQuery(BufferedQuery query, QueryPool pool, bool needsReset)
|
||||||
|
|
|
@ -40,5 +40,15 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
EndRenderPass();
|
EndRenderPass();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Finish(VulkanRenderer gd, CommandBufferScoped cbs)
|
||||||
|
{
|
||||||
|
Finish();
|
||||||
|
|
||||||
|
if (gd.PipelineInternal.IsCommandBufferActive(cbs.CommandBuffer))
|
||||||
|
{
|
||||||
|
gd.PipelineInternal.Restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,18 +142,20 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
int stagesCount = shaders.Length;
|
int stagesCount = shaders.Length;
|
||||||
|
|
||||||
int uCount = 0;
|
int uCount = 0;
|
||||||
|
int sCount = 0;
|
||||||
int tCount = 0;
|
int tCount = 0;
|
||||||
int iCount = 0;
|
int iCount = 0;
|
||||||
|
|
||||||
foreach (var shader in shaders)
|
foreach (var shader in shaders)
|
||||||
{
|
{
|
||||||
uCount += shader.Bindings.UniformBufferBindings.Count;
|
uCount += shader.Bindings.UniformBufferBindings.Count;
|
||||||
|
sCount += shader.Bindings.StorageBufferBindings.Count;
|
||||||
tCount += shader.Bindings.TextureBindings.Count;
|
tCount += shader.Bindings.TextureBindings.Count;
|
||||||
iCount += shader.Bindings.ImageBindings.Count;
|
iCount += shader.Bindings.ImageBindings.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
DescriptorSetLayoutBinding* uLayoutBindings = stackalloc DescriptorSetLayoutBinding[uCount];
|
DescriptorSetLayoutBinding* uLayoutBindings = stackalloc DescriptorSetLayoutBinding[uCount];
|
||||||
DescriptorSetLayoutBinding* sLayoutBindings = stackalloc DescriptorSetLayoutBinding[stagesCount];
|
DescriptorSetLayoutBinding* sLayoutBindings = stackalloc DescriptorSetLayoutBinding[sCount];
|
||||||
DescriptorSetLayoutBinding* tLayoutBindings = stackalloc DescriptorSetLayoutBinding[tCount];
|
DescriptorSetLayoutBinding* tLayoutBindings = stackalloc DescriptorSetLayoutBinding[tCount];
|
||||||
DescriptorSetLayoutBinding* iLayoutBindings = stackalloc DescriptorSetLayoutBinding[iCount];
|
DescriptorSetLayoutBinding* iLayoutBindings = stackalloc DescriptorSetLayoutBinding[iCount];
|
||||||
|
|
||||||
|
@ -180,22 +182,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetStorage(DescriptorSetLayoutBinding* bindings, ref int start, int count)
|
|
||||||
{
|
|
||||||
bindings[start++] = new DescriptorSetLayoutBinding
|
|
||||||
{
|
|
||||||
Binding = (uint)start,
|
|
||||||
DescriptorType = DescriptorType.StorageBuffer,
|
|
||||||
DescriptorCount = (uint)count,
|
|
||||||
StageFlags = stageFlags
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Support buffer textures and images here.
|
// TODO: Support buffer textures and images here.
|
||||||
// This is only used for the helper shaders on the backend, and we don't use buffer textures on them
|
// This is only used for the helper shaders on the backend, and we don't use buffer textures on them
|
||||||
// so far, so it's not really necessary right now.
|
// so far, so it's not really necessary right now.
|
||||||
Set(uLayoutBindings, DescriptorType.UniformBuffer, ref uIndex, shader.Bindings.UniformBufferBindings);
|
Set(uLayoutBindings, DescriptorType.UniformBuffer, ref uIndex, shader.Bindings.UniformBufferBindings);
|
||||||
SetStorage(sLayoutBindings, ref sIndex, shader.Bindings.StorageBufferBindings.Count);
|
Set(sLayoutBindings, DescriptorType.StorageBuffer, ref sIndex, shader.Bindings.StorageBufferBindings);
|
||||||
Set(tLayoutBindings, DescriptorType.CombinedImageSampler, ref tIndex, shader.Bindings.TextureBindings);
|
Set(tLayoutBindings, DescriptorType.CombinedImageSampler, ref tIndex, shader.Bindings.TextureBindings);
|
||||||
Set(iLayoutBindings, DescriptorType.StorageImage, ref iIndex, shader.Bindings.ImageBindings);
|
Set(iLayoutBindings, DescriptorType.StorageImage, ref iIndex, shader.Bindings.ImageBindings);
|
||||||
}
|
}
|
||||||
|
@ -213,7 +204,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
SType = StructureType.DescriptorSetLayoutCreateInfo,
|
SType = StructureType.DescriptorSetLayoutCreateInfo,
|
||||||
PBindings = sLayoutBindings,
|
PBindings = sLayoutBindings,
|
||||||
BindingCount = (uint)stagesCount
|
BindingCount = (uint)sCount
|
||||||
};
|
};
|
||||||
|
|
||||||
var tDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo()
|
var tDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo()
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
#version 450 core
|
||||||
|
|
||||||
|
#extension GL_EXT_shader_8bit_storage : require
|
||||||
|
|
||||||
|
layout (local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
|
||||||
|
|
||||||
|
layout (std140, set = 0, binding = 0) uniform stride_arguments
|
||||||
|
{
|
||||||
|
ivec4 stride_arguments_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout (std430, set = 1, binding = 1) buffer in_s
|
||||||
|
{
|
||||||
|
uint8_t[] in_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout (std430, set = 1, binding = 2) buffer out_s
|
||||||
|
{
|
||||||
|
uint8_t[] out_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// Determine what slice of the stride copies this invocation will perform.
|
||||||
|
|
||||||
|
int sourceStride = stride_arguments_data.x;
|
||||||
|
int targetStride = stride_arguments_data.y;
|
||||||
|
int bufferSize = stride_arguments_data.z;
|
||||||
|
int sourceOffset = stride_arguments_data.w;
|
||||||
|
|
||||||
|
int strideRemainder = targetStride - sourceStride;
|
||||||
|
int invocations = int(gl_WorkGroupSize.x);
|
||||||
|
|
||||||
|
int copiesRequired = bufferSize / sourceStride;
|
||||||
|
|
||||||
|
// Find the copies that this invocation should perform.
|
||||||
|
|
||||||
|
// - Copies that all invocations perform.
|
||||||
|
int allInvocationCopies = copiesRequired / invocations;
|
||||||
|
|
||||||
|
// - Extra remainder copy that this invocation performs.
|
||||||
|
int index = int(gl_LocalInvocationID.x);
|
||||||
|
int extra = (index < (copiesRequired % invocations)) ? 1 : 0;
|
||||||
|
|
||||||
|
int copyCount = allInvocationCopies + extra;
|
||||||
|
|
||||||
|
// Finally, get the starting offset. Make sure to count extra copies.
|
||||||
|
|
||||||
|
int startCopy = allInvocationCopies * index + min(copiesRequired % invocations, index);
|
||||||
|
|
||||||
|
int srcOffset = sourceOffset + startCopy * sourceStride;
|
||||||
|
int dstOffset = startCopy * targetStride;
|
||||||
|
|
||||||
|
// Perform the copies for this region
|
||||||
|
for (int i=0; i<copyCount; i++) {
|
||||||
|
for (int j=0; j<sourceStride; j++) {
|
||||||
|
out_data[dstOffset++] = in_data[srcOffset++];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j=0; j<strideRemainder; j++) {
|
||||||
|
out_data[dstOffset++] = uint8_t(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,249 @@ namespace Ryujinx.Graphics.Vulkan.Shaders
|
||||||
{
|
{
|
||||||
static class ShaderBinaries
|
static class ShaderBinaries
|
||||||
{
|
{
|
||||||
|
public static readonly byte[] ChangeBufferStrideShaderSource = new byte[]
|
||||||
|
{
|
||||||
|
0x03, 0x02, 0x23, 0x07, 0x00, 0x05, 0x01, 0x00, 0x0A, 0x00, 0x0D, 0x00, 0x8E, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
|
||||||
|
0x60, 0x11, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C,
|
||||||
|
0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x03, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x09, 0x00, 0x05, 0x00, 0x00, 0x00,
|
||||||
|
0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
|
||||||
|
0x30, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x10, 0x00, 0x06, 0x00,
|
||||||
|
0x04, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||||
|
0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xC2, 0x01, 0x00, 0x00,
|
||||||
|
0x04, 0x00, 0x08, 0x00, 0x47, 0x4C, 0x5F, 0x45, 0x58, 0x54, 0x5F, 0x73, 0x68, 0x61, 0x64, 0x65,
|
||||||
|
0x72, 0x5F, 0x38, 0x62, 0x69, 0x74, 0x5F, 0x73, 0x74, 0x6F, 0x72, 0x61, 0x67, 0x65, 0x00, 0x00,
|
||||||
|
0x04, 0x00, 0x0A, 0x00, 0x47, 0x4C, 0x5F, 0x47, 0x4F, 0x4F, 0x47, 0x4C, 0x45, 0x5F, 0x63, 0x70,
|
||||||
|
0x70, 0x5F, 0x73, 0x74, 0x79, 0x6C, 0x65, 0x5F, 0x6C, 0x69, 0x6E, 0x65, 0x5F, 0x64, 0x69, 0x72,
|
||||||
|
0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x47, 0x4C, 0x5F, 0x47,
|
||||||
|
0x4F, 0x4F, 0x47, 0x4C, 0x45, 0x5F, 0x69, 0x6E, 0x63, 0x6C, 0x75, 0x64, 0x65, 0x5F, 0x64, 0x69,
|
||||||
|
0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||||
|
0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||||
|
0x73, 0x6F, 0x75, 0x72, 0x63, 0x65, 0x53, 0x74, 0x72, 0x69, 0x64, 0x65, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x05, 0x00, 0x07, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x73, 0x74, 0x72, 0x69, 0x64, 0x65, 0x5F, 0x61,
|
||||||
|
0x72, 0x67, 0x75, 0x6D, 0x65, 0x6E, 0x74, 0x73, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x09, 0x00,
|
||||||
|
0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x74, 0x72, 0x69, 0x64, 0x65, 0x5F, 0x61,
|
||||||
|
0x72, 0x67, 0x75, 0x6D, 0x65, 0x6E, 0x74, 0x73, 0x5F, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00,
|
||||||
|
0x05, 0x00, 0x03, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00,
|
||||||
|
0x13, 0x00, 0x00, 0x00, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x74, 0x72, 0x69, 0x64, 0x65,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x17, 0x00, 0x00, 0x00, 0x62, 0x75, 0x66, 0x66,
|
||||||
|
0x65, 0x72, 0x53, 0x69, 0x7A, 0x65, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x1B, 0x00, 0x00, 0x00,
|
||||||
|
0x73, 0x6F, 0x75, 0x72, 0x63, 0x65, 0x4F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x05, 0x00, 0x06, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x73, 0x74, 0x72, 0x69, 0x64, 0x65, 0x52, 0x65,
|
||||||
|
0x6D, 0x61, 0x69, 0x6E, 0x64, 0x65, 0x72, 0x00, 0x05, 0x00, 0x05, 0x00, 0x23, 0x00, 0x00, 0x00,
|
||||||
|
0x69, 0x6E, 0x76, 0x6F, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x00, 0x05, 0x00, 0x06, 0x00,
|
||||||
|
0x25, 0x00, 0x00, 0x00, 0x63, 0x6F, 0x70, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72,
|
||||||
|
0x65, 0x64, 0x00, 0x00, 0x05, 0x00, 0x07, 0x00, 0x29, 0x00, 0x00, 0x00, 0x61, 0x6C, 0x6C, 0x49,
|
||||||
|
0x6E, 0x76, 0x6F, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x43, 0x6F, 0x70, 0x69, 0x65, 0x73, 0x00,
|
||||||
|
0x05, 0x00, 0x04, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x00, 0x00, 0x00,
|
||||||
|
0x05, 0x00, 0x08, 0x00, 0x30, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x4C, 0x6F, 0x63, 0x61, 0x6C,
|
||||||
|
0x49, 0x6E, 0x76, 0x6F, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x49, 0x44, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x05, 0x00, 0x04, 0x00, 0x35, 0x00, 0x00, 0x00, 0x65, 0x78, 0x74, 0x72, 0x61, 0x00, 0x00, 0x00,
|
||||||
|
0x05, 0x00, 0x05, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x63, 0x6F, 0x70, 0x79, 0x43, 0x6F, 0x75, 0x6E,
|
||||||
|
0x74, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x42, 0x00, 0x00, 0x00, 0x73, 0x74, 0x61, 0x72,
|
||||||
|
0x74, 0x43, 0x6F, 0x70, 0x79, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x4C, 0x00, 0x00, 0x00,
|
||||||
|
0x73, 0x72, 0x63, 0x4F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,
|
||||||
|
0x52, 0x00, 0x00, 0x00, 0x64, 0x73, 0x74, 0x4F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x00, 0x00, 0x00,
|
||||||
|
0x05, 0x00, 0x03, 0x00, 0x56, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00,
|
||||||
|
0x5F, 0x00, 0x00, 0x00, 0x6A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x6A, 0x00, 0x00, 0x00,
|
||||||
|
0x6F, 0x75, 0x74, 0x5F, 0x73, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x6A, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x6F, 0x75, 0x74, 0x5F, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x05, 0x00, 0x03, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00,
|
||||||
|
0x70, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x5F, 0x73, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00,
|
||||||
|
0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x5F, 0x64, 0x61, 0x74, 0x61, 0x00,
|
||||||
|
0x05, 0x00, 0x03, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00,
|
||||||
|
0x7B, 0x00, 0x00, 0x00, 0x6A, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00,
|
||||||
|
0x0A, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00,
|
||||||
|
0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00,
|
||||||
|
0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x30, 0x00, 0x00, 0x00,
|
||||||
|
0x0B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00,
|
||||||
|
0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x6A, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00,
|
||||||
|
0x6A, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x6C, 0x00, 0x00, 0x00,
|
||||||
|
0x22, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x6C, 0x00, 0x00, 0x00,
|
||||||
|
0x21, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x6F, 0x00, 0x00, 0x00,
|
||||||
|
0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x70, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00,
|
||||||
|
0x70, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x72, 0x00, 0x00, 0x00,
|
||||||
|
0x22, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x72, 0x00, 0x00, 0x00,
|
||||||
|
0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x8D, 0x00, 0x00, 0x00,
|
||||||
|
0x0B, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||||
|
0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00,
|
||||||
|
0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
|
||||||
|
0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00,
|
||||||
|
0x09, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x03, 0x00,
|
||||||
|
0x0A, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00,
|
||||||
|
0x02, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00,
|
||||||
|
0x0C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
|
||||||
|
0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00,
|
||||||
|
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00,
|
||||||
|
0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00,
|
||||||
|
0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00,
|
||||||
|
0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00,
|
||||||
|
0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00,
|
||||||
|
0x1C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
|
||||||
|
0x24, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x2E, 0x00, 0x00, 0x00,
|
||||||
|
0x0E, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x2F, 0x00, 0x00, 0x00,
|
||||||
|
0x01, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x2F, 0x00, 0x00, 0x00,
|
||||||
|
0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x31, 0x00, 0x00, 0x00,
|
||||||
|
0x01, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0x3A, 0x00, 0x00, 0x00,
|
||||||
|
0x2B, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||||
|
0x15, 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x1D, 0x00, 0x03, 0x00, 0x69, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x03, 0x00,
|
||||||
|
0x6A, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x6B, 0x00, 0x00, 0x00,
|
||||||
|
0x0C, 0x00, 0x00, 0x00, 0x6A, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x6B, 0x00, 0x00, 0x00,
|
||||||
|
0x6C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x03, 0x00, 0x6F, 0x00, 0x00, 0x00,
|
||||||
|
0x68, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x03, 0x00, 0x70, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00,
|
||||||
|
0x20, 0x00, 0x04, 0x00, 0x71, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00,
|
||||||
|
0x3B, 0x00, 0x04, 0x00, 0x71, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
|
||||||
|
0x20, 0x00, 0x04, 0x00, 0x75, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00,
|
||||||
|
0x2B, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x8C, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
|
||||||
|
0x2C, 0x00, 0x06, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x8D, 0x00, 0x00, 0x00, 0x8C, 0x00, 0x00, 0x00,
|
||||||
|
0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||||
|
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00,
|
||||||
|
0x05, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||||
|
0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
|
||||||
|
0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
|
||||||
|
0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,
|
||||||
|
0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,
|
||||||
|
0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
|
||||||
|
0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
|
||||||
|
0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00,
|
||||||
|
0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00,
|
||||||
|
0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00,
|
||||||
|
0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00,
|
||||||
|
0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00,
|
||||||
|
0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x00, 0x00,
|
||||||
|
0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00,
|
||||||
|
0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00,
|
||||||
|
0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00,
|
||||||
|
0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x7B, 0x00, 0x00, 0x00,
|
||||||
|
0x07, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
|
||||||
|
0x0C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
|
||||||
|
0x06, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
|
||||||
|
0x08, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x10, 0x00, 0x00, 0x00,
|
||||||
|
0x15, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
|
||||||
|
0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
|
||||||
|
0x3E, 0x00, 0x03, 0x00, 0x13, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00,
|
||||||
|
0x10, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
|
||||||
|
0x18, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00,
|
||||||
|
0x19, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00,
|
||||||
|
0x41, 0x00, 0x06, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
|
||||||
|
0x0D, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
|
||||||
|
0x1E, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x1B, 0x00, 0x00, 0x00,
|
||||||
|
0x1E, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||||
|
0x13, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
|
||||||
|
0x08, 0x00, 0x00, 0x00, 0x82, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
|
||||||
|
0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x1F, 0x00, 0x00, 0x00,
|
||||||
|
0x22, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x23, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
|
||||||
|
0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
|
||||||
|
0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||||
|
0x87, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,
|
||||||
|
0x27, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x25, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
|
||||||
|
0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
|
||||||
|
0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
|
||||||
|
0x87, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00,
|
||||||
|
0x2B, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,
|
||||||
|
0x41, 0x00, 0x05, 0x00, 0x31, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
|
||||||
|
0x0F, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,
|
||||||
|
0x32, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
|
||||||
|
0x33, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
|
||||||
|
0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00,
|
||||||
|
0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
|
||||||
|
0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
|
||||||
|
0x8B, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00,
|
||||||
|
0x38, 0x00, 0x00, 0x00, 0xB1, 0x00, 0x05, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00,
|
||||||
|
0x36, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0xA9, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00,
|
||||||
|
0x3D, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
|
||||||
|
0x3E, 0x00, 0x03, 0x00, 0x35, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
|
||||||
|
0x06, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
|
||||||
|
0x06, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00,
|
||||||
|
0x06, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
|
||||||
|
0x3E, 0x00, 0x03, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
|
||||||
|
0x06, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
|
||||||
|
0x06, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x84, 0x00, 0x05, 0x00,
|
||||||
|
0x06, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00,
|
||||||
|
0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
|
||||||
|
0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
|
||||||
|
0x8B, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00,
|
||||||
|
0x47, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00,
|
||||||
|
0x2D, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00,
|
||||||
|
0x01, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00,
|
||||||
|
0x80, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x4B, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00,
|
||||||
|
0x4A, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x42, 0x00, 0x00, 0x00, 0x4B, 0x00, 0x00, 0x00,
|
||||||
|
0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,
|
||||||
|
0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x4E, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00,
|
||||||
|
0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x4F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||||
|
0x84, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x4E, 0x00, 0x00, 0x00,
|
||||||
|
0x4F, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00,
|
||||||
|
0x4D, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x4C, 0x00, 0x00, 0x00,
|
||||||
|
0x51, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00,
|
||||||
|
0x42, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
|
||||||
|
0x13, 0x00, 0x00, 0x00, 0x84, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00,
|
||||||
|
0x53, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x52, 0x00, 0x00, 0x00,
|
||||||
|
0x55, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x56, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
|
||||||
|
0xF9, 0x00, 0x02, 0x00, 0x57, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x57, 0x00, 0x00, 0x00,
|
||||||
|
0xF6, 0x00, 0x04, 0x00, 0x59, 0x00, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0xF9, 0x00, 0x02, 0x00, 0x5B, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x5B, 0x00, 0x00, 0x00,
|
||||||
|
0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00,
|
||||||
|
0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00,
|
||||||
|
0xB1, 0x00, 0x05, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x5E, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x00,
|
||||||
|
0x5D, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, 0x5E, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00,
|
||||||
|
0x59, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x58, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
|
||||||
|
0x5F, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0x60, 0x00, 0x00, 0x00,
|
||||||
|
0xF8, 0x00, 0x02, 0x00, 0x60, 0x00, 0x00, 0x00, 0xF6, 0x00, 0x04, 0x00, 0x62, 0x00, 0x00, 0x00,
|
||||||
|
0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0x64, 0x00, 0x00, 0x00,
|
||||||
|
0xF8, 0x00, 0x02, 0x00, 0x64, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
|
||||||
|
0x65, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
|
||||||
|
0x66, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xB1, 0x00, 0x05, 0x00, 0x3A, 0x00, 0x00, 0x00,
|
||||||
|
0x67, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00,
|
||||||
|
0x67, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00,
|
||||||
|
0x61, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x6D, 0x00, 0x00, 0x00,
|
||||||
|
0x52, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00,
|
||||||
|
0x6D, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x52, 0x00, 0x00, 0x00,
|
||||||
|
0x6E, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00,
|
||||||
|
0x4C, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00,
|
||||||
|
0x73, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x4C, 0x00, 0x00, 0x00,
|
||||||
|
0x74, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x75, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00,
|
||||||
|
0x72, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
|
||||||
|
0x68, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00,
|
||||||
|
0x75, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
|
||||||
|
0x6D, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x78, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00,
|
||||||
|
0xF9, 0x00, 0x02, 0x00, 0x63, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x63, 0x00, 0x00, 0x00,
|
||||||
|
0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00,
|
||||||
|
0x80, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x7A, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00,
|
||||||
|
0x3C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x5F, 0x00, 0x00, 0x00, 0x7A, 0x00, 0x00, 0x00,
|
||||||
|
0xF9, 0x00, 0x02, 0x00, 0x60, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x62, 0x00, 0x00, 0x00,
|
||||||
|
0x3E, 0x00, 0x03, 0x00, 0x7B, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00,
|
||||||
|
0x7C, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x7C, 0x00, 0x00, 0x00, 0xF6, 0x00, 0x04, 0x00,
|
||||||
|
0x7E, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00,
|
||||||
|
0x80, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x80, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
|
||||||
|
0x06, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x7B, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
|
||||||
|
0x06, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0xB1, 0x00, 0x05, 0x00,
|
||||||
|
0x3A, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00,
|
||||||
|
0xFA, 0x00, 0x04, 0x00, 0x83, 0x00, 0x00, 0x00, 0x7D, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00,
|
||||||
|
0xF8, 0x00, 0x02, 0x00, 0x7D, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
|
||||||
|
0x84, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00,
|
||||||
|
0x85, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
|
||||||
|
0x52, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x71, 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00,
|
||||||
|
0x86, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x75, 0x00, 0x00, 0x00,
|
||||||
|
0x87, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00,
|
||||||
|
0x3E, 0x00, 0x03, 0x00, 0x87, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00,
|
||||||
|
0x7F, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
|
||||||
|
0x06, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x7B, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00,
|
||||||
|
0x06, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00,
|
||||||
|
0x3E, 0x00, 0x03, 0x00, 0x7B, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00,
|
||||||
|
0x7C, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x7E, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00,
|
||||||
|
0x5A, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x5A, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
|
||||||
|
0x06, 0x00, 0x00, 0x00, 0x8A, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00,
|
||||||
|
0x06, 0x00, 0x00, 0x00, 0x8B, 0x00, 0x00, 0x00, 0x8A, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00,
|
||||||
|
0x3E, 0x00, 0x03, 0x00, 0x56, 0x00, 0x00, 0x00, 0x8B, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00,
|
||||||
|
0x57, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x59, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00,
|
||||||
|
0x38, 0x00, 0x01, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
public static readonly byte[] ColorBlitClearAlphaFragmentShaderSource = new byte[]
|
public static readonly byte[] ColorBlitClearAlphaFragmentShaderSource = new byte[]
|
||||||
{
|
{
|
||||||
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x08, 0x00, 0x1B, 0x00, 0x00, 0x00,
|
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x08, 0x00, 0x1B, 0x00, 0x00, 0x00,
|
||||||
|
|
131
Ryujinx.Graphics.Vulkan/VertexBufferState.cs
Normal file
131
Ryujinx.Graphics.Vulkan/VertexBufferState.cs
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
using BufferHandle = Ryujinx.Graphics.GAL.BufferHandle;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Vulkan
|
||||||
|
{
|
||||||
|
internal struct VertexBufferState
|
||||||
|
{
|
||||||
|
public static VertexBufferState Null => new VertexBufferState(null, 0, 0, 0);
|
||||||
|
|
||||||
|
private readonly int _offset;
|
||||||
|
private readonly int _size;
|
||||||
|
private readonly int _stride;
|
||||||
|
|
||||||
|
private readonly BufferHandle _handle;
|
||||||
|
private Auto<DisposableBuffer> _buffer;
|
||||||
|
|
||||||
|
internal readonly int DescriptorIndex;
|
||||||
|
internal int AttributeScalarAlignment;
|
||||||
|
|
||||||
|
public VertexBufferState(Auto<DisposableBuffer> buffer, int descriptorIndex, int offset, int size, int stride = 0)
|
||||||
|
{
|
||||||
|
_buffer = buffer;
|
||||||
|
_handle = BufferHandle.Null;
|
||||||
|
|
||||||
|
_offset = offset;
|
||||||
|
_size = size;
|
||||||
|
_stride = stride;
|
||||||
|
|
||||||
|
DescriptorIndex = descriptorIndex;
|
||||||
|
AttributeScalarAlignment = 1;
|
||||||
|
|
||||||
|
buffer?.IncrementReferenceCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
public VertexBufferState(BufferHandle handle, int descriptorIndex, int offset, int size, int stride = 0)
|
||||||
|
{
|
||||||
|
// This buffer state may be rewritten at bind time, so it must be retrieved on bind.
|
||||||
|
|
||||||
|
_buffer = null;
|
||||||
|
_handle = handle;
|
||||||
|
|
||||||
|
_offset = offset;
|
||||||
|
_size = size;
|
||||||
|
_stride = stride;
|
||||||
|
|
||||||
|
DescriptorIndex = descriptorIndex;
|
||||||
|
AttributeScalarAlignment = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void BindVertexBuffer(VulkanRenderer gd, CommandBufferScoped cbs, uint binding, ref PipelineState state)
|
||||||
|
{
|
||||||
|
var autoBuffer = _buffer;
|
||||||
|
|
||||||
|
if (_handle != BufferHandle.Null)
|
||||||
|
{
|
||||||
|
// May need to restride the vertex buffer.
|
||||||
|
|
||||||
|
if (gd.NeedsVertexBufferAlignment(AttributeScalarAlignment, out int alignment) && (_stride % alignment) != 0)
|
||||||
|
{
|
||||||
|
autoBuffer = gd.BufferManager.GetAlignedVertexBuffer(cbs, _handle, _offset, _size, _stride, alignment);
|
||||||
|
int stride = (_stride + (alignment - 1)) & -alignment;
|
||||||
|
|
||||||
|
var buffer = autoBuffer.Get(cbs, _offset, _size).Value;
|
||||||
|
|
||||||
|
if (gd.Capabilities.SupportsExtendedDynamicState)
|
||||||
|
{
|
||||||
|
gd.ExtendedDynamicStateApi.CmdBindVertexBuffers2(
|
||||||
|
cbs.CommandBuffer,
|
||||||
|
binding,
|
||||||
|
1,
|
||||||
|
buffer,
|
||||||
|
0,
|
||||||
|
(ulong)(_size / _stride) * (ulong)stride,
|
||||||
|
(ulong)stride);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gd.Api.CmdBindVertexBuffers(cbs.CommandBuffer, binding, 1, buffer, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
_buffer = autoBuffer;
|
||||||
|
state.Internal.VertexBindingDescriptions[DescriptorIndex].Stride = (uint)stride;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
autoBuffer = gd.BufferManager.GetBuffer(cbs.CommandBuffer, _handle, false, out int _);
|
||||||
|
|
||||||
|
// The original stride must be reapplied in case it was rewritten.
|
||||||
|
state.Internal.VertexBindingDescriptions[DescriptorIndex].Stride = (uint)_stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (autoBuffer != null)
|
||||||
|
{
|
||||||
|
var buffer = autoBuffer.Get(cbs, _offset, _size).Value;
|
||||||
|
|
||||||
|
if (gd.Capabilities.SupportsExtendedDynamicState)
|
||||||
|
{
|
||||||
|
gd.ExtendedDynamicStateApi.CmdBindVertexBuffers2(
|
||||||
|
cbs.CommandBuffer,
|
||||||
|
binding,
|
||||||
|
1,
|
||||||
|
buffer,
|
||||||
|
(ulong)_offset,
|
||||||
|
(ulong)_size,
|
||||||
|
(ulong)_stride);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gd.Api.CmdBindVertexBuffers(cbs.CommandBuffer, binding, 1, buffer, (ulong)_offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool BoundEquals(Auto<DisposableBuffer> buffer)
|
||||||
|
{
|
||||||
|
return _buffer == buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
// Only dispose if this buffer is not refetched on each bind.
|
||||||
|
|
||||||
|
if (_handle == BufferHandle.Null)
|
||||||
|
{
|
||||||
|
_buffer?.DecrementReferenceCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,6 +28,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
"VK_EXT_fragment_shader_interlock",
|
"VK_EXT_fragment_shader_interlock",
|
||||||
"VK_EXT_index_type_uint8",
|
"VK_EXT_index_type_uint8",
|
||||||
"VK_EXT_robustness2",
|
"VK_EXT_robustness2",
|
||||||
|
"VK_KHR_shader_float16_int8",
|
||||||
"VK_EXT_shader_subgroup_ballot",
|
"VK_EXT_shader_subgroup_ballot",
|
||||||
"VK_EXT_subgroup_size_control",
|
"VK_EXT_subgroup_size_control",
|
||||||
"VK_NV_geometry_shader_passthrough"
|
"VK_NV_geometry_shader_passthrough"
|
||||||
|
|
|
@ -188,11 +188,22 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
SType = StructureType.PhysicalDeviceRobustness2FeaturesExt
|
SType = StructureType.PhysicalDeviceRobustness2FeaturesExt
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PhysicalDeviceShaderFloat16Int8FeaturesKHR featuresShaderInt8 = new PhysicalDeviceShaderFloat16Int8FeaturesKHR()
|
||||||
|
{
|
||||||
|
SType = StructureType.PhysicalDeviceShaderFloat16Int8Features
|
||||||
|
};
|
||||||
|
|
||||||
if (supportedExtensions.Contains("VK_EXT_robustness2"))
|
if (supportedExtensions.Contains("VK_EXT_robustness2"))
|
||||||
{
|
{
|
||||||
features2.PNext = &featuresRobustness2;
|
features2.PNext = &featuresRobustness2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (supportedExtensions.Contains("VK_KHR_shader_float16_int8"))
|
||||||
|
{
|
||||||
|
featuresShaderInt8.PNext = features2.PNext;
|
||||||
|
features2.PNext = &featuresShaderInt8;
|
||||||
|
}
|
||||||
|
|
||||||
Api.GetPhysicalDeviceFeatures2(_physicalDevice, &features2);
|
Api.GetPhysicalDeviceFeatures2(_physicalDevice, &features2);
|
||||||
|
|
||||||
Capabilities = new HardwareCapabilities(
|
Capabilities = new HardwareCapabilities(
|
||||||
|
@ -202,6 +213,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
supportedExtensions.Contains("VK_EXT_fragment_shader_interlock"),
|
supportedExtensions.Contains("VK_EXT_fragment_shader_interlock"),
|
||||||
supportedExtensions.Contains("VK_NV_geometry_shader_passthrough"),
|
supportedExtensions.Contains("VK_NV_geometry_shader_passthrough"),
|
||||||
supportedExtensions.Contains("VK_EXT_subgroup_size_control"),
|
supportedExtensions.Contains("VK_EXT_subgroup_size_control"),
|
||||||
|
featuresShaderInt8.ShaderInt8,
|
||||||
supportedExtensions.Contains(ExtConditionalRendering.ExtensionName),
|
supportedExtensions.Contains(ExtConditionalRendering.ExtensionName),
|
||||||
supportedExtensions.Contains(ExtExtendedDynamicState.ExtensionName),
|
supportedExtensions.Contains(ExtExtendedDynamicState.ExtensionName),
|
||||||
features2.Features.MultiViewport,
|
features2.Features.MultiViewport,
|
||||||
|
@ -506,6 +518,24 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
PrintGpuInformation();
|
PrintGpuInformation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool NeedsVertexBufferAlignment(int attrScalarAlignment, out int alignment)
|
||||||
|
{
|
||||||
|
if (Vendor != Vendor.Nvidia)
|
||||||
|
{
|
||||||
|
// Vulkan requires that vertex attributes are globally aligned by their component size,
|
||||||
|
// so buffer strides that don't divide by the largest scalar element are invalid.
|
||||||
|
// Guest applications do this, NVIDIA GPUs are OK with it, others are not.
|
||||||
|
|
||||||
|
alignment = attrScalarAlignment;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
alignment = 1;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public void PreFrame()
|
public void PreFrame()
|
||||||
{
|
{
|
||||||
_syncManager.Cleanup();
|
_syncManager.Cleanup();
|
||||||
|
|
Loading…
Reference in a new issue