Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
022d495335 | ||
|
c1372ed775 | ||
|
a16682cfd3 | ||
|
7c53b69c30 | ||
|
33a4d7d1ba | ||
|
391e08dd27 | ||
|
b5cf8b8af9 |
12
.github/workflows/build.yml
vendored
12
.github/workflows/build.yml
vendored
@@ -52,26 +52,22 @@ jobs:
|
|||||||
- uses: actions/setup-dotnet@v3
|
- uses: actions/setup-dotnet@v3
|
||||||
with:
|
with:
|
||||||
dotnet-version: 7.0.x
|
dotnet-version: 7.0.x
|
||||||
- name: Ensure NuGet Source
|
|
||||||
uses: fabriciomurta/ensure-nuget-source@v1
|
|
||||||
- name: Get git short hash
|
- name: Get git short hash
|
||||||
id: git_short_hash
|
id: git_short_hash
|
||||||
run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
|
run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
|
||||||
shell: bash
|
shell: bash
|
||||||
- name: Clear
|
|
||||||
run: dotnet clean && dotnet nuget locals all --clear
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: dotnet build -c "${{ matrix.configuration }}" /p:Version="${{ env.RYUJINX_BASE_VERSION }}" /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER
|
run: dotnet build -c "${{ matrix.configuration }}" -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER
|
||||||
- name: Test
|
- name: Test
|
||||||
run: dotnet test --no-build -c "${{ matrix.configuration }}"
|
run: dotnet test --no-build -c "${{ matrix.configuration }}"
|
||||||
- name: Publish Ryujinx
|
- name: Publish Ryujinx
|
||||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish /p:Version="${{ env.RYUJINX_BASE_VERSION }}" /p:DebugType=embedded /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx --self-contained
|
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx --self-contained true
|
||||||
if: github.event_name == 'pull_request'
|
if: github.event_name == 'pull_request'
|
||||||
- name: Publish Ryujinx.Headless.SDL2
|
- name: Publish Ryujinx.Headless.SDL2
|
||||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless /p:Version="${{ env.RYUJINX_BASE_VERSION }}" /p:DebugType=embedded /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx.Headless.SDL2 --self-contained
|
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx.Headless.SDL2 --self-contained true
|
||||||
if: github.event_name == 'pull_request'
|
if: github.event_name == 'pull_request'
|
||||||
- name: Publish Ryujinx.Ava
|
- name: Publish Ryujinx.Ava
|
||||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava /p:Version="1.0.0" /p:DebugType=embedded /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx.Ava
|
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx.Ava --self-contained true
|
||||||
if: github.event_name == 'pull_request'
|
if: github.event_name == 'pull_request'
|
||||||
- name: Upload Ryujinx artifact
|
- name: Upload Ryujinx artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
|
16
.github/workflows/release.yml
vendored
16
.github/workflows/release.yml
vendored
@@ -29,10 +29,6 @@ jobs:
|
|||||||
- uses: actions/setup-dotnet@v3
|
- uses: actions/setup-dotnet@v3
|
||||||
with:
|
with:
|
||||||
dotnet-version: 7.0.x
|
dotnet-version: 7.0.x
|
||||||
- name: Ensure NuGet Source
|
|
||||||
uses: fabriciomurta/ensure-nuget-source@v1
|
|
||||||
- name: Clear
|
|
||||||
run: dotnet clean && dotnet nuget locals all --clear
|
|
||||||
- name: Get version info
|
- name: Get version info
|
||||||
id: version_info
|
id: version_info
|
||||||
run: |
|
run: |
|
||||||
@@ -51,9 +47,9 @@ jobs:
|
|||||||
run: "mkdir release_output"
|
run: "mkdir release_output"
|
||||||
- name: Publish Windows
|
- name: Publish Windows
|
||||||
run: |
|
run: |
|
||||||
dotnet publish -c Release -r win10-x64 -o ./publish_windows/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx --self-contained
|
dotnet publish -c Release -r win10-x64 -o ./publish_windows/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx --self-contained true
|
||||||
dotnet publish -c Release -r win10-x64 -o ./publish_windows_sdl2_headless/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Headless.SDL2 --self-contained
|
dotnet publish -c Release -r win10-x64 -o ./publish_windows_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx.Headless.SDL2 --self-contained true
|
||||||
dotnet publish -c Release -r win10-x64 -o ./publish_windows_ava/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Ava --self-contained
|
dotnet publish -c Release -r win10-x64 -o ./publish_windows_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx.Ava --self-contained true
|
||||||
- name: Packing Windows builds
|
- name: Packing Windows builds
|
||||||
run: |
|
run: |
|
||||||
pushd publish_windows
|
pushd publish_windows
|
||||||
@@ -71,9 +67,9 @@ jobs:
|
|||||||
|
|
||||||
- name: Publish Linux
|
- name: Publish Linux
|
||||||
run: |
|
run: |
|
||||||
dotnet publish -c Release -r linux-x64 -o ./publish_linux/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx --self-contained
|
dotnet publish -c Release -r linux-x64 -o ./publish_linux/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx --self-contained true
|
||||||
dotnet publish -c Release -r linux-x64 -o ./publish_linux_sdl2_headless/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Headless.SDL2 --self-contained
|
dotnet publish -c Release -r linux-x64 -o ./publish_linux_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx.Headless.SDL2 --self-contained true
|
||||||
dotnet publish -c Release -r linux-x64 -o ./publish_linux_ava/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Ava --self-contained
|
dotnet publish -c Release -r linux-x64 -o ./publish_linux_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx.Ava --self-contained true
|
||||||
|
|
||||||
- name: Packing Linux builds
|
- name: Packing Linux builds
|
||||||
run: |
|
run: |
|
||||||
|
@@ -1,15 +1,11 @@
|
|||||||
|
using System;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
|
||||||
namespace ARMeilleure.Common
|
namespace ARMeilleure.Common
|
||||||
{
|
{
|
||||||
static class BitUtils
|
static class BitUtils
|
||||||
{
|
{
|
||||||
private static readonly sbyte[] HbsNibbleLut;
|
private static ReadOnlySpan<sbyte> HbsNibbleLut => new sbyte[] { -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 };
|
||||||
|
|
||||||
static BitUtils()
|
|
||||||
{
|
|
||||||
HbsNibbleLut = new sbyte[] { -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 };
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long FillWithOnes(int bits)
|
public static long FillWithOnes(int bits)
|
||||||
{
|
{
|
||||||
|
@@ -27,7 +27,7 @@ namespace Ryujinx.Cpu
|
|||||||
long TpidrroEl0 { get; set; }
|
long TpidrroEl0 { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Processor State register.
|
/// Processor State Register.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
uint Pstate { get; set; }
|
uint Pstate { get; set; }
|
||||||
|
|
||||||
|
@@ -95,5 +95,10 @@ namespace Ryujinx.Graphics.Gpu
|
|||||||
/// Byte alignment for block linear textures
|
/// Byte alignment for block linear textures
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const int GobAlignment = 64;
|
public const int GobAlignment = 64;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Expected byte alignment for storage buffers
|
||||||
|
/// </summary>
|
||||||
|
public const int StorageAlignment = 16;
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -138,7 +138,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
|
|||||||
qmd.CtaThreadDimension1,
|
qmd.CtaThreadDimension1,
|
||||||
qmd.CtaThreadDimension2,
|
qmd.CtaThreadDimension2,
|
||||||
localMemorySize,
|
localMemorySize,
|
||||||
sharedMemorySize);
|
sharedMemorySize,
|
||||||
|
_channel.BufferManager.HasUnalignedStorageBuffers);
|
||||||
|
|
||||||
CachedShaderProgram cs = memoryManager.Physical.ShaderCache.GetComputeShader(_channel, poolState, computeState, shaderGpuVa);
|
CachedShaderProgram cs = memoryManager.Physical.ShaderCache.GetComputeShader(_channel, poolState, computeState, shaderGpuVa);
|
||||||
|
|
||||||
@@ -150,6 +151,33 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
|
|||||||
|
|
||||||
ShaderProgramInfo info = cs.Shaders[0].Info;
|
ShaderProgramInfo info = cs.Shaders[0].Info;
|
||||||
|
|
||||||
|
bool hasUnaligned = _channel.BufferManager.HasUnalignedStorageBuffers;
|
||||||
|
|
||||||
|
for (int index = 0; index < info.SBuffers.Count; index++)
|
||||||
|
{
|
||||||
|
BufferDescriptor sb = info.SBuffers[index];
|
||||||
|
|
||||||
|
ulong sbDescAddress = _channel.BufferManager.GetComputeUniformBufferAddress(0);
|
||||||
|
|
||||||
|
int sbDescOffset = 0x310 + sb.Slot * 0x10;
|
||||||
|
|
||||||
|
sbDescAddress += (ulong)sbDescOffset;
|
||||||
|
|
||||||
|
SbDescriptor sbDescriptor = _channel.MemoryManager.Physical.Read<SbDescriptor>(sbDescAddress);
|
||||||
|
|
||||||
|
_channel.BufferManager.SetComputeStorageBuffer(sb.Slot, sbDescriptor.PackAddress(), (uint)sbDescriptor.Size, sb.Flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((_channel.BufferManager.HasUnalignedStorageBuffers) != hasUnaligned)
|
||||||
|
{
|
||||||
|
// Refetch the shader, as assumptions about storage buffer alignment have changed.
|
||||||
|
cs = memoryManager.Physical.ShaderCache.GetComputeShader(_channel, poolState, computeState, shaderGpuVa);
|
||||||
|
|
||||||
|
_context.Renderer.Pipeline.SetProgram(cs.HostProgram);
|
||||||
|
|
||||||
|
info = cs.Shaders[0].Info;
|
||||||
|
}
|
||||||
|
|
||||||
for (int index = 0; index < info.CBuffers.Count; index++)
|
for (int index = 0; index < info.CBuffers.Count; index++)
|
||||||
{
|
{
|
||||||
BufferDescriptor cb = info.CBuffers[index];
|
BufferDescriptor cb = info.CBuffers[index];
|
||||||
@@ -174,21 +202,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
|
|||||||
_channel.BufferManager.SetComputeUniformBuffer(cb.Slot, cbDescriptor.PackAddress(), (uint)cbDescriptor.Size);
|
_channel.BufferManager.SetComputeUniformBuffer(cb.Slot, cbDescriptor.PackAddress(), (uint)cbDescriptor.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int index = 0; index < info.SBuffers.Count; index++)
|
|
||||||
{
|
|
||||||
BufferDescriptor sb = info.SBuffers[index];
|
|
||||||
|
|
||||||
ulong sbDescAddress = _channel.BufferManager.GetComputeUniformBufferAddress(0);
|
|
||||||
|
|
||||||
int sbDescOffset = 0x310 + sb.Slot * 0x10;
|
|
||||||
|
|
||||||
sbDescAddress += (ulong)sbDescOffset;
|
|
||||||
|
|
||||||
SbDescriptor sbDescriptor = _channel.MemoryManager.Physical.Read<SbDescriptor>(sbDescAddress);
|
|
||||||
|
|
||||||
_channel.BufferManager.SetComputeStorageBuffer(sb.Slot, sbDescriptor.PackAddress(), (uint)sbDescriptor.Size, sb.Flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
_channel.BufferManager.SetComputeStorageBufferBindings(info.SBuffers);
|
_channel.BufferManager.SetComputeStorageBufferBindings(info.SBuffers);
|
||||||
_channel.BufferManager.SetComputeUniformBufferBindings(info.CBuffers);
|
_channel.BufferManager.SetComputeUniformBufferBindings(info.CBuffers);
|
||||||
|
|
||||||
|
@@ -293,9 +293,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void CommitBindings()
|
private void CommitBindings()
|
||||||
{
|
{
|
||||||
|
var buffers = _channel.BufferManager;
|
||||||
|
var hasUnaligned = buffers.HasUnalignedStorageBuffers;
|
||||||
|
|
||||||
UpdateStorageBuffers();
|
UpdateStorageBuffers();
|
||||||
|
|
||||||
if (!_channel.TextureManager.CommitGraphicsBindings(_shaderSpecState))
|
if (!_channel.TextureManager.CommitGraphicsBindings(_shaderSpecState) || (buffers.HasUnalignedStorageBuffers != hasUnaligned))
|
||||||
{
|
{
|
||||||
// Shader must be reloaded.
|
// Shader must be reloaded.
|
||||||
UpdateShaderState();
|
UpdateShaderState();
|
||||||
@@ -1361,7 +1364,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
_state.State.AlphaTestFunc,
|
_state.State.AlphaTestFunc,
|
||||||
_state.State.AlphaTestRef,
|
_state.State.AlphaTestRef,
|
||||||
ref attributeTypes,
|
ref attributeTypes,
|
||||||
_drawState.HasConstantBufferDrawParameters);
|
_drawState.HasConstantBufferDrawParameters,
|
||||||
|
_channel.BufferManager.HasUnalignedStorageBuffers);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -17,6 +17,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
private readonly GpuContext _context;
|
private readonly GpuContext _context;
|
||||||
private readonly GpuChannel _channel;
|
private readonly GpuChannel _channel;
|
||||||
|
|
||||||
|
private int _unalignedStorageBuffers;
|
||||||
|
public bool HasUnalignedStorageBuffers => _unalignedStorageBuffers > 0;
|
||||||
|
|
||||||
private IndexBuffer _indexBuffer;
|
private IndexBuffer _indexBuffer;
|
||||||
private readonly VertexBuffer[] _vertexBuffers;
|
private readonly VertexBuffer[] _vertexBuffers;
|
||||||
private readonly BufferBounds[] _transformFeedbackBuffers;
|
private readonly BufferBounds[] _transformFeedbackBuffers;
|
||||||
@@ -38,6 +41,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public BufferBounds[] Buffers { get; }
|
public BufferBounds[] Buffers { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Flag indicating if this binding is unaligned.
|
||||||
|
/// </summary>
|
||||||
|
public bool[] Unaligned { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Total amount of buffers used on the shader.
|
/// Total amount of buffers used on the shader.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -51,6 +59,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
{
|
{
|
||||||
Bindings = new BufferDescriptor[count];
|
Bindings = new BufferDescriptor[count];
|
||||||
Buffers = new BufferBounds[count];
|
Buffers = new BufferBounds[count];
|
||||||
|
Unaligned = new bool[count];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -202,6 +211,31 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
_transformFeedbackBuffersDirty = true;
|
_transformFeedbackBuffersDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Records the alignment of a storage buffer.
|
||||||
|
/// Unaligned storage buffers disable some optimizations on the shader.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buffers">The binding list to modify</param>
|
||||||
|
/// <param name="index">Index of the storage buffer</param>
|
||||||
|
/// <param name="gpuVa">Start GPU virtual address of the buffer</param>
|
||||||
|
private void RecordStorageAlignment(BuffersPerStage buffers, int index, ulong gpuVa)
|
||||||
|
{
|
||||||
|
bool unaligned = (gpuVa & (Constants.StorageAlignment - 1)) != 0;
|
||||||
|
|
||||||
|
if (unaligned || HasUnalignedStorageBuffers)
|
||||||
|
{
|
||||||
|
// Check if the alignment changed for this binding.
|
||||||
|
|
||||||
|
ref bool currentUnaligned = ref buffers.Unaligned[index];
|
||||||
|
|
||||||
|
if (currentUnaligned != unaligned)
|
||||||
|
{
|
||||||
|
currentUnaligned = unaligned;
|
||||||
|
_unalignedStorageBuffers += unaligned ? 1 : -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets a storage buffer on the compute pipeline.
|
/// Sets a storage buffer on the compute pipeline.
|
||||||
/// Storage buffers can be read and written to on shaders.
|
/// Storage buffers can be read and written to on shaders.
|
||||||
@@ -214,6 +248,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
{
|
{
|
||||||
size += gpuVa & ((ulong)_context.Capabilities.StorageBufferOffsetAlignment - 1);
|
size += gpuVa & ((ulong)_context.Capabilities.StorageBufferOffsetAlignment - 1);
|
||||||
|
|
||||||
|
RecordStorageAlignment(_cpStorageBuffers, index, gpuVa);
|
||||||
|
|
||||||
gpuVa = BitUtils.AlignDown(gpuVa, _context.Capabilities.StorageBufferOffsetAlignment);
|
gpuVa = BitUtils.AlignDown(gpuVa, _context.Capabilities.StorageBufferOffsetAlignment);
|
||||||
|
|
||||||
ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
|
ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
|
||||||
@@ -234,17 +270,21 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
{
|
{
|
||||||
size += gpuVa & ((ulong)_context.Capabilities.StorageBufferOffsetAlignment - 1);
|
size += gpuVa & ((ulong)_context.Capabilities.StorageBufferOffsetAlignment - 1);
|
||||||
|
|
||||||
|
BuffersPerStage buffers = _gpStorageBuffers[stage];
|
||||||
|
|
||||||
|
RecordStorageAlignment(buffers, index, gpuVa);
|
||||||
|
|
||||||
gpuVa = BitUtils.AlignDown(gpuVa, _context.Capabilities.StorageBufferOffsetAlignment);
|
gpuVa = BitUtils.AlignDown(gpuVa, _context.Capabilities.StorageBufferOffsetAlignment);
|
||||||
|
|
||||||
ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
|
ulong address = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateBuffer(_channel.MemoryManager, gpuVa, size);
|
||||||
|
|
||||||
if (_gpStorageBuffers[stage].Buffers[index].Address != address ||
|
if (buffers.Buffers[index].Address != address ||
|
||||||
_gpStorageBuffers[stage].Buffers[index].Size != size)
|
buffers.Buffers[index].Size != size)
|
||||||
{
|
{
|
||||||
_gpStorageBuffersDirty = true;
|
_gpStorageBuffersDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_gpStorageBuffers[stage].SetBounds(index, address, size, flags);
|
buffers.SetBounds(index, address, size, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -36,6 +36,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="channel">GPU channel</param>
|
/// <param name="channel">GPU channel</param>
|
||||||
/// <param name="poolState">Texture pool state</param>
|
/// <param name="poolState">Texture pool state</param>
|
||||||
|
/// <param name="computeState">Compute state</param>
|
||||||
/// <param name="gpuVa">GPU virtual address of the compute shader</param>
|
/// <param name="gpuVa">GPU virtual address of the compute shader</param>
|
||||||
/// <param name="program">Cached host program for the given state, if found</param>
|
/// <param name="program">Cached host program for the given state, if found</param>
|
||||||
/// <param name="cachedGuestCode">Cached guest code, if any found</param>
|
/// <param name="cachedGuestCode">Cached guest code, if any found</param>
|
||||||
@@ -43,6 +44,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
public bool TryFind(
|
public bool TryFind(
|
||||||
GpuChannel channel,
|
GpuChannel channel,
|
||||||
GpuChannelPoolState poolState,
|
GpuChannelPoolState poolState,
|
||||||
|
GpuChannelComputeState computeState,
|
||||||
ulong gpuVa,
|
ulong gpuVa,
|
||||||
out CachedShaderProgram program,
|
out CachedShaderProgram program,
|
||||||
out byte[] cachedGuestCode)
|
out byte[] cachedGuestCode)
|
||||||
@@ -50,7 +52,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
program = null;
|
program = null;
|
||||||
ShaderCodeAccessor codeAccessor = new ShaderCodeAccessor(channel.MemoryManager, gpuVa);
|
ShaderCodeAccessor codeAccessor = new ShaderCodeAccessor(channel.MemoryManager, gpuVa);
|
||||||
bool hasSpecList = _cache.TryFindItem(codeAccessor, out var specList, out cachedGuestCode);
|
bool hasSpecList = _cache.TryFindItem(codeAccessor, out var specList, out cachedGuestCode);
|
||||||
return hasSpecList && specList.TryFindForCompute(channel, poolState, out program);
|
return hasSpecList && specList.TryFindForCompute(channel, poolState, computeState, out program);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -225,6 +225,12 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
return _oldSpecState.GraphicsState.EarlyZForce;
|
return _oldSpecState.GraphicsState.EarlyZForce;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool QueryHasUnalignedStorageBuffer()
|
||||||
|
{
|
||||||
|
return _oldSpecState.GraphicsState.HasUnalignedStorageBuffer || _oldSpecState.ComputeState.HasUnalignedStorageBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool QueryViewportTransformDisable()
|
public bool QueryViewportTransformDisable()
|
||||||
{
|
{
|
||||||
|
@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
private const ushort FileFormatVersionMajor = 1;
|
private const ushort FileFormatVersionMajor = 1;
|
||||||
private const ushort FileFormatVersionMinor = 2;
|
private const ushort FileFormatVersionMinor = 2;
|
||||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||||
private const uint CodeGenVersion = 3747;
|
private const uint CodeGenVersion = 3863;
|
||||||
|
|
||||||
private const string SharedTocFileName = "shared.toc";
|
private const string SharedTocFileName = "shared.toc";
|
||||||
private const string SharedDataFileName = "shared.data";
|
private const string SharedDataFileName = "shared.data";
|
||||||
|
@@ -145,6 +145,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
return _state.GraphicsState.HasConstantBufferDrawParameters;
|
return _state.GraphicsState.HasConstantBufferDrawParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool QueryHasUnalignedStorageBuffer()
|
||||||
|
{
|
||||||
|
return _state.GraphicsState.HasUnalignedStorageBuffer || _state.ComputeState.HasUnalignedStorageBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public InputTopology QueryPrimitiveTopology()
|
public InputTopology QueryPrimitiveTopology()
|
||||||
{
|
{
|
||||||
|
@@ -32,6 +32,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly int SharedMemorySize;
|
public readonly int SharedMemorySize;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates that any storage buffer use is unaligned.
|
||||||
|
/// </summary>
|
||||||
|
public readonly bool HasUnalignedStorageBuffer;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new GPU compute state.
|
/// Creates a new GPU compute state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -40,18 +45,21 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
/// <param name="localSizeZ">Local group size Z of the compute shader</param>
|
/// <param name="localSizeZ">Local group size Z of the compute shader</param>
|
||||||
/// <param name="localMemorySize">Local memory size of the compute shader</param>
|
/// <param name="localMemorySize">Local memory size of the compute shader</param>
|
||||||
/// <param name="sharedMemorySize">Shared memory size of the compute shader</param>
|
/// <param name="sharedMemorySize">Shared memory size of the compute shader</param>
|
||||||
|
/// <param name="hasUnalignedStorageBuffer">Indicates that any storage buffer use is unaligned</param>
|
||||||
public GpuChannelComputeState(
|
public GpuChannelComputeState(
|
||||||
int localSizeX,
|
int localSizeX,
|
||||||
int localSizeY,
|
int localSizeY,
|
||||||
int localSizeZ,
|
int localSizeZ,
|
||||||
int localMemorySize,
|
int localMemorySize,
|
||||||
int sharedMemorySize)
|
int sharedMemorySize,
|
||||||
|
bool hasUnalignedStorageBuffer)
|
||||||
{
|
{
|
||||||
LocalSizeX = localSizeX;
|
LocalSizeX = localSizeX;
|
||||||
LocalSizeY = localSizeY;
|
LocalSizeY = localSizeY;
|
||||||
LocalSizeZ = localSizeZ;
|
LocalSizeZ = localSizeZ;
|
||||||
LocalMemorySize = localMemorySize;
|
LocalMemorySize = localMemorySize;
|
||||||
SharedMemorySize = sharedMemorySize;
|
SharedMemorySize = sharedMemorySize;
|
||||||
|
HasUnalignedStorageBuffer = hasUnalignedStorageBuffer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -82,6 +82,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly bool HasConstantBufferDrawParameters;
|
public readonly bool HasConstantBufferDrawParameters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates that any storage buffer use is unaligned.
|
||||||
|
/// </summary>
|
||||||
|
public readonly bool HasUnalignedStorageBuffer;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new GPU graphics state.
|
/// Creates a new GPU graphics state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -99,6 +104,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
/// <param name="alphaTestReference">When alpha test is enabled, indicates the value to compare with the fragment output alpha</param>
|
/// <param name="alphaTestReference">When alpha test is enabled, indicates the value to compare with the fragment output alpha</param>
|
||||||
/// <param name="attributeTypes">Type of the vertex attributes consumed by the shader</param>
|
/// <param name="attributeTypes">Type of the vertex attributes consumed by the shader</param>
|
||||||
/// <param name="hasConstantBufferDrawParameters">Indicates that the draw is writing the base vertex, base instance and draw index to Constant Buffer 0</param>
|
/// <param name="hasConstantBufferDrawParameters">Indicates that the draw is writing the base vertex, base instance and draw index to Constant Buffer 0</param>
|
||||||
|
/// <param name="hasUnalignedStorageBuffer">Indicates that any storage buffer use is unaligned</param>
|
||||||
public GpuChannelGraphicsState(
|
public GpuChannelGraphicsState(
|
||||||
bool earlyZForce,
|
bool earlyZForce,
|
||||||
PrimitiveTopology topology,
|
PrimitiveTopology topology,
|
||||||
@@ -113,7 +119,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
CompareOp alphaTestCompare,
|
CompareOp alphaTestCompare,
|
||||||
float alphaTestReference,
|
float alphaTestReference,
|
||||||
ref Array32<AttributeType> attributeTypes,
|
ref Array32<AttributeType> attributeTypes,
|
||||||
bool hasConstantBufferDrawParameters)
|
bool hasConstantBufferDrawParameters,
|
||||||
|
bool hasUnalignedStorageBuffer)
|
||||||
{
|
{
|
||||||
EarlyZForce = earlyZForce;
|
EarlyZForce = earlyZForce;
|
||||||
Topology = topology;
|
Topology = topology;
|
||||||
@@ -129,6 +136,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
AlphaTestReference = alphaTestReference;
|
AlphaTestReference = alphaTestReference;
|
||||||
AttributeTypes = attributeTypes;
|
AttributeTypes = attributeTypes;
|
||||||
HasConstantBufferDrawParameters = hasConstantBufferDrawParameters;
|
HasConstantBufferDrawParameters = hasConstantBufferDrawParameters;
|
||||||
|
HasUnalignedStorageBuffer = hasUnalignedStorageBuffer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -203,12 +203,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
GpuChannelComputeState computeState,
|
GpuChannelComputeState computeState,
|
||||||
ulong gpuVa)
|
ulong gpuVa)
|
||||||
{
|
{
|
||||||
if (_cpPrograms.TryGetValue(gpuVa, out var cpShader) && IsShaderEqual(channel, poolState, cpShader, gpuVa))
|
if (_cpPrograms.TryGetValue(gpuVa, out var cpShader) && IsShaderEqual(channel, poolState, computeState, cpShader, gpuVa))
|
||||||
{
|
{
|
||||||
return cpShader;
|
return cpShader;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_computeShaderCache.TryFind(channel, poolState, gpuVa, out cpShader, out byte[] cachedGuestCode))
|
if (_computeShaderCache.TryFind(channel, poolState, computeState, gpuVa, out cpShader, out byte[] cachedGuestCode))
|
||||||
{
|
{
|
||||||
_cpPrograms[gpuVa] = cpShader;
|
_cpPrograms[gpuVa] = cpShader;
|
||||||
return cpShader;
|
return cpShader;
|
||||||
@@ -473,18 +473,20 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="channel">GPU channel using the shader</param>
|
/// <param name="channel">GPU channel using the shader</param>
|
||||||
/// <param name="poolState">GPU channel state to verify shader compatibility</param>
|
/// <param name="poolState">GPU channel state to verify shader compatibility</param>
|
||||||
|
/// <param name="computeState">GPU channel compute state to verify shader compatibility</param>
|
||||||
/// <param name="cpShader">Cached compute shader</param>
|
/// <param name="cpShader">Cached compute shader</param>
|
||||||
/// <param name="gpuVa">GPU virtual address of the shader code in memory</param>
|
/// <param name="gpuVa">GPU virtual address of the shader code in memory</param>
|
||||||
/// <returns>True if the code is different, false otherwise</returns>
|
/// <returns>True if the code is different, false otherwise</returns>
|
||||||
private static bool IsShaderEqual(
|
private static bool IsShaderEqual(
|
||||||
GpuChannel channel,
|
GpuChannel channel,
|
||||||
GpuChannelPoolState poolState,
|
GpuChannelPoolState poolState,
|
||||||
|
GpuChannelComputeState computeState,
|
||||||
CachedShaderProgram cpShader,
|
CachedShaderProgram cpShader,
|
||||||
ulong gpuVa)
|
ulong gpuVa)
|
||||||
{
|
{
|
||||||
if (IsShaderEqual(channel.MemoryManager, cpShader.Shaders[0], gpuVa))
|
if (IsShaderEqual(channel.MemoryManager, cpShader.Shaders[0], gpuVa))
|
||||||
{
|
{
|
||||||
return cpShader.SpecializationState.MatchesCompute(channel, poolState, true);
|
return cpShader.SpecializationState.MatchesCompute(channel, poolState, computeState, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@@ -53,13 +53,14 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="channel">GPU channel</param>
|
/// <param name="channel">GPU channel</param>
|
||||||
/// <param name="poolState">Texture pool state</param>
|
/// <param name="poolState">Texture pool state</param>
|
||||||
|
/// <param name="computeState">Compute state</param>
|
||||||
/// <param name="program">Cached program, if found</param>
|
/// <param name="program">Cached program, if found</param>
|
||||||
/// <returns>True if a compatible program is found, false otherwise</returns>
|
/// <returns>True if a compatible program is found, false otherwise</returns>
|
||||||
public bool TryFindForCompute(GpuChannel channel, GpuChannelPoolState poolState, out CachedShaderProgram program)
|
public bool TryFindForCompute(GpuChannel channel, GpuChannelPoolState poolState, GpuChannelComputeState computeState, out CachedShaderProgram program)
|
||||||
{
|
{
|
||||||
foreach (var entry in _entries)
|
foreach (var entry in _entries)
|
||||||
{
|
{
|
||||||
if (entry.SpecializationState.MatchesCompute(channel, poolState, true))
|
if (entry.SpecializationState.MatchesCompute(channel, poolState, computeState, true))
|
||||||
{
|
{
|
||||||
program = entry;
|
program = entry;
|
||||||
return true;
|
return true;
|
||||||
|
@@ -531,6 +531,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (graphicsState.HasUnalignedStorageBuffer != GraphicsState.HasUnalignedStorageBuffer)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return Matches(channel, poolState, checkTextures, isCompute: false);
|
return Matches(channel, poolState, checkTextures, isCompute: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -539,10 +544,16 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="channel">GPU channel</param>
|
/// <param name="channel">GPU channel</param>
|
||||||
/// <param name="poolState">Texture pool state</param>
|
/// <param name="poolState">Texture pool state</param>
|
||||||
|
/// <param name="computeState">Compute state</param>
|
||||||
/// <param name="checkTextures">Indicates whether texture descriptors should be checked</param>
|
/// <param name="checkTextures">Indicates whether texture descriptors should be checked</param>
|
||||||
/// <returns>True if the state matches, false otherwise</returns>
|
/// <returns>True if the state matches, false otherwise</returns>
|
||||||
public bool MatchesCompute(GpuChannel channel, GpuChannelPoolState poolState, bool checkTextures)
|
public bool MatchesCompute(GpuChannel channel, GpuChannelPoolState poolState, GpuChannelComputeState computeState, bool checkTextures)
|
||||||
{
|
{
|
||||||
|
if (computeState.HasUnalignedStorageBuffer != ComputeState.HasUnalignedStorageBuffer)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return Matches(channel, poolState, checkTextures, isCompute: true);
|
return Matches(channel, poolState, checkTextures, isCompute: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -63,7 +63,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
short dqv = dq[0];
|
short dqv = dq[0];
|
||||||
ReadOnlySpan<byte> cat6Prob = (xd.Bd == 12)
|
ReadOnlySpan<byte> cat6Prob = (xd.Bd == 12)
|
||||||
? Luts.Vp9Cat6ProbHigh12
|
? Luts.Vp9Cat6ProbHigh12
|
||||||
: (xd.Bd == 10) ? new ReadOnlySpan<byte>(Luts.Vp9Cat6ProbHigh12).Slice(2) : Luts.Vp9Cat6Prob;
|
: (xd.Bd == 10) ? Luts.Vp9Cat6ProbHigh12.Slice(2) : Luts.Vp9Cat6Prob;
|
||||||
int cat6Bits = (xd.Bd == 12) ? 18 : (xd.Bd == 10) ? 16 : 14;
|
int cat6Bits = (xd.Bd == 12) ? 18 : (xd.Bd == 10) ? 16 : 14;
|
||||||
// Keep value, range, and count as locals. The compiler produces better
|
// Keep value, range, and count as locals. The compiler produces better
|
||||||
// results with the locals than using r directly.
|
// results with the locals than using r directly.
|
||||||
|
@@ -1,14 +1,12 @@
|
|||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.Graphics.Nvdec.Vp9.Types;
|
using Ryujinx.Graphics.Nvdec.Vp9.Types;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Nvdec.Vp9
|
namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||||
{
|
{
|
||||||
internal static class Luts
|
internal static class Luts
|
||||||
{
|
{
|
||||||
public static readonly byte[] SizeGroupLookup = new byte[]
|
public static ReadOnlySpan<byte> SizeGroupLookup => new byte[] { 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3 };
|
||||||
{
|
|
||||||
0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3
|
|
||||||
};
|
|
||||||
|
|
||||||
public static readonly BlockSize[][] SubsizeLookup = new BlockSize[][]
|
public static readonly BlockSize[][] SubsizeLookup = new BlockSize[][]
|
||||||
{
|
{
|
||||||
@@ -1070,18 +1068,18 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
-(sbyte)MvClassType.MvClass10,
|
-(sbyte)MvClassType.MvClass10,
|
||||||
};
|
};
|
||||||
|
|
||||||
public static readonly sbyte[] Vp9MvFPTree = new sbyte[] { -0, 2, -1, 4, -2, -3 };
|
public static ReadOnlySpan<sbyte> Vp9MvFPTree => new sbyte[] { -0, 2, -1, 4, -2, -3 };
|
||||||
|
|
||||||
// Entropy
|
// Entropy
|
||||||
|
|
||||||
public static readonly byte[] Vp9Cat1Prob = new byte[] { 159 };
|
public static ReadOnlySpan<byte> Vp9Cat1Prob => new byte[] { 159 };
|
||||||
public static readonly byte[] Vp9Cat2Prob = new byte[] { 165, 145 };
|
public static ReadOnlySpan<byte> Vp9Cat2Prob => new byte[] { 165, 145 };
|
||||||
public static readonly byte[] Vp9Cat3Prob = new byte[] { 173, 148, 140 };
|
public static ReadOnlySpan<byte> Vp9Cat3Prob => new byte[] { 173, 148, 140 };
|
||||||
public static readonly byte[] Vp9Cat4Prob = new byte[] { 176, 155, 140, 135 };
|
public static ReadOnlySpan<byte> Vp9Cat4Prob => new byte[] { 176, 155, 140, 135 };
|
||||||
public static readonly byte[] Vp9Cat5Prob = new byte[] { 180, 157, 141, 134, 130 };
|
public static ReadOnlySpan<byte> Vp9Cat5Prob => new byte[] { 180, 157, 141, 134, 130 };
|
||||||
public static readonly byte[] Vp9Cat6Prob = new byte[] { 254, 254, 254, 252, 249, 243, 230, 196, 177, 153, 140, 133, 130, 129 };
|
public static ReadOnlySpan<byte> Vp9Cat6Prob => new byte[] { 254, 254, 254, 252, 249, 243, 230, 196, 177, 153, 140, 133, 130, 129 };
|
||||||
|
|
||||||
public static readonly byte[] Vp9Cat6ProbHigh12 = new byte[]
|
public static ReadOnlySpan<byte> Vp9Cat6ProbHigh12 => new byte[]
|
||||||
{
|
{
|
||||||
255, 255, 255, 255, 254, 254, 54, 252, 249, 243, 230, 196, 177, 153, 140, 133, 130, 129
|
255, 255, 255, 255, 254, 254, 54, 252, 249, 243, 230, 196, 177, 153, 140, 133, 130, 129
|
||||||
};
|
};
|
||||||
@@ -1131,12 +1129,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly byte[] Vp9CoefbandTrans4X4 = new byte[]
|
private static ReadOnlySpan<byte> Vp9CoefbandTrans4X4 => new byte[]
|
||||||
{
|
{
|
||||||
0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5,
|
0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
public static byte[] get_band_translate(TxSize txSize)
|
public static ReadOnlySpan<byte> get_band_translate(TxSize txSize)
|
||||||
{
|
{
|
||||||
return txSize == TxSize.Tx4x4 ? Vp9CoefbandTrans4X4 : Vp9CoefbandTrans8X8Plus;
|
return txSize == TxSize.Tx4x4 ? Vp9CoefbandTrans4X4 : Vp9CoefbandTrans8X8Plus;
|
||||||
}
|
}
|
||||||
|
@@ -1829,7 +1829,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
|||||||
|
|
||||||
if (texOp.Index < 2 || (type & SamplerType.Mask) == SamplerType.Texture3D)
|
if (texOp.Index < 2 || (type & SamplerType.Mask) == SamplerType.Texture3D)
|
||||||
{
|
{
|
||||||
result = ScalingHelpers.ApplyUnscaling(context, texOp, result, isBindless, isIndexed);
|
result = ScalingHelpers.ApplyUnscaling(context, texOp.WithType(type), result, isBindless, isIndexed);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new OperationResult(AggregateType.S32, result);
|
return new OperationResult(AggregateType.S32, result);
|
||||||
|
@@ -10,5 +10,7 @@ namespace Ryujinx.Graphics.Shader
|
|||||||
public const int NvnBaseVertexByteOffset = 0x640;
|
public const int NvnBaseVertexByteOffset = 0x640;
|
||||||
public const int NvnBaseInstanceByteOffset = 0x644;
|
public const int NvnBaseInstanceByteOffset = 0x644;
|
||||||
public const int NvnDrawIndexByteOffset = 0x648;
|
public const int NvnDrawIndexByteOffset = 0x648;
|
||||||
|
|
||||||
|
public const int StorageAlignment = 16;
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -177,6 +177,15 @@ namespace Ryujinx.Graphics.Shader
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queries whenever the current draw uses unaligned storage buffer addresses.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if any storage buffer address is not aligned to 16 bytes, false otherwise</returns>
|
||||||
|
bool QueryHasUnalignedStorageBuffer()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Queries host about the presence of the FrontFacing built-in variable bug.
|
/// Queries host about the presence of the FrontFacing built-in variable bug.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@@ -27,5 +27,10 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
|||||||
CbufSlot = cbufSlot;
|
CbufSlot = cbufSlot;
|
||||||
Handle = handle;
|
Handle = handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AstTextureOperation WithType(SamplerType type)
|
||||||
|
{
|
||||||
|
return new AstTextureOperation(Inst, type, Format, Flags, CbufSlot, Handle, Index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -34,7 +34,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
|||||||
// we can guess which storage buffer it is accessing.
|
// we can guess which storage buffer it is accessing.
|
||||||
// We can then replace the global memory access with a storage
|
// We can then replace the global memory access with a storage
|
||||||
// buffer access.
|
// buffer access.
|
||||||
node = ReplaceGlobalWithStorage(node, config, storageIndex);
|
node = ReplaceGlobalWithStorage(block, node, config, storageIndex);
|
||||||
}
|
}
|
||||||
else if (config.Stage == ShaderStage.Compute && operation.Inst == Instruction.LoadGlobal)
|
else if (config.Stage == ShaderStage.Compute && operation.Inst == Instruction.LoadGlobal)
|
||||||
{
|
{
|
||||||
@@ -54,7 +54,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static LinkedListNode<INode> ReplaceGlobalWithStorage(LinkedListNode<INode> node, ShaderConfig config, int storageIndex)
|
private static LinkedListNode<INode> ReplaceGlobalWithStorage(BasicBlock block, LinkedListNode<INode> node, ShaderConfig config, int storageIndex)
|
||||||
{
|
{
|
||||||
Operation operation = (Operation)node.Value;
|
Operation operation = (Operation)node.Value;
|
||||||
|
|
||||||
@@ -64,42 +64,10 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
|||||||
|
|
||||||
config.SetUsedStorageBuffer(storageIndex, isWrite);
|
config.SetUsedStorageBuffer(storageIndex, isWrite);
|
||||||
|
|
||||||
Operand GetStorageOffset()
|
|
||||||
{
|
|
||||||
Operand addrLow = operation.GetSource(0);
|
|
||||||
|
|
||||||
Operand baseAddrLow = Cbuf(0, GetStorageCbOffset(config.Stage, storageIndex));
|
|
||||||
|
|
||||||
Operand baseAddrTrunc = Local();
|
|
||||||
|
|
||||||
Operand alignMask = Const(-config.GpuAccessor.QueryHostStorageBufferOffsetAlignment());
|
|
||||||
|
|
||||||
Operation andOp = new Operation(Instruction.BitwiseAnd, baseAddrTrunc, baseAddrLow, alignMask);
|
|
||||||
|
|
||||||
node.List.AddBefore(node, andOp);
|
|
||||||
|
|
||||||
Operand byteOffset = Local();
|
|
||||||
Operation subOp = new Operation(Instruction.Subtract, byteOffset, addrLow, baseAddrTrunc);
|
|
||||||
|
|
||||||
node.List.AddBefore(node, subOp);
|
|
||||||
|
|
||||||
if (isStg16Or8)
|
|
||||||
{
|
|
||||||
return byteOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
Operand wordOffset = Local();
|
|
||||||
Operation shrOp = new Operation(Instruction.ShiftRightU32, wordOffset, byteOffset, Const(2));
|
|
||||||
|
|
||||||
node.List.AddBefore(node, shrOp);
|
|
||||||
|
|
||||||
return wordOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
Operand[] sources = new Operand[operation.SourcesCount];
|
Operand[] sources = new Operand[operation.SourcesCount];
|
||||||
|
|
||||||
sources[0] = Const(storageIndex);
|
sources[0] = Const(storageIndex);
|
||||||
sources[1] = GetStorageOffset();
|
sources[1] = GetStorageOffset(block, node, config, storageIndex, operation.GetSource(0), isStg16Or8);
|
||||||
|
|
||||||
for (int index = 2; index < operation.SourcesCount; index++)
|
for (int index = 2; index < operation.SourcesCount; index++)
|
||||||
{
|
{
|
||||||
@@ -144,6 +112,170 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Operand GetStorageOffset(
|
||||||
|
BasicBlock block,
|
||||||
|
LinkedListNode<INode> node,
|
||||||
|
ShaderConfig config,
|
||||||
|
int storageIndex,
|
||||||
|
Operand addrLow,
|
||||||
|
bool isStg16Or8)
|
||||||
|
{
|
||||||
|
int baseAddressCbOffset = GetStorageCbOffset(config.Stage, storageIndex);
|
||||||
|
|
||||||
|
bool storageAligned = !(config.GpuAccessor.QueryHasUnalignedStorageBuffer() || config.GpuAccessor.QueryHostStorageBufferOffsetAlignment() > Constants.StorageAlignment);
|
||||||
|
|
||||||
|
(Operand byteOffset, int constantOffset) = storageAligned ?
|
||||||
|
GetStorageOffset(block, Utils.FindLastOperation(addrLow, block), baseAddressCbOffset) :
|
||||||
|
(null, 0);
|
||||||
|
|
||||||
|
if (byteOffset == null)
|
||||||
|
{
|
||||||
|
Operand baseAddrLow = Cbuf(0, baseAddressCbOffset);
|
||||||
|
Operand baseAddrTrunc = Local();
|
||||||
|
|
||||||
|
Operand alignMask = Const(-config.GpuAccessor.QueryHostStorageBufferOffsetAlignment());
|
||||||
|
|
||||||
|
Operation andOp = new Operation(Instruction.BitwiseAnd, baseAddrTrunc, baseAddrLow, alignMask);
|
||||||
|
|
||||||
|
node.List.AddBefore(node, andOp);
|
||||||
|
|
||||||
|
Operand offset = Local();
|
||||||
|
Operation subOp = new Operation(Instruction.Subtract, offset, addrLow, baseAddrTrunc);
|
||||||
|
|
||||||
|
node.List.AddBefore(node, subOp);
|
||||||
|
|
||||||
|
byteOffset = offset;
|
||||||
|
}
|
||||||
|
else if (constantOffset != 0)
|
||||||
|
{
|
||||||
|
Operand offset = Local();
|
||||||
|
Operation addOp = new Operation(Instruction.Add, offset, byteOffset, Const(constantOffset));
|
||||||
|
|
||||||
|
node.List.AddBefore(node, addOp);
|
||||||
|
|
||||||
|
byteOffset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (byteOffset != null)
|
||||||
|
{
|
||||||
|
ReplaceAddressAlignment(node.List, addrLow, byteOffset, constantOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isStg16Or8)
|
||||||
|
{
|
||||||
|
return byteOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand wordOffset = Local();
|
||||||
|
Operation shrOp = new Operation(Instruction.ShiftRightU32, wordOffset, byteOffset, Const(2));
|
||||||
|
|
||||||
|
node.List.AddBefore(node, shrOp);
|
||||||
|
|
||||||
|
return wordOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsCb0Offset(Operand operand, int offset)
|
||||||
|
{
|
||||||
|
return operand.Type == OperandType.ConstantBuffer && operand.GetCbufSlot() == 0 && operand.GetCbufOffset() == offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ReplaceAddressAlignment(LinkedList<INode> list, Operand address, Operand byteOffset, int constantOffset)
|
||||||
|
{
|
||||||
|
// When we emit 16/8-bit LDG, we add extra code to determine the address alignment.
|
||||||
|
// Eliminate the storage buffer base address from this too, leaving only the byte offset.
|
||||||
|
|
||||||
|
foreach (INode useNode in address.UseOps)
|
||||||
|
{
|
||||||
|
if (useNode is Operation op && op.Inst == Instruction.BitwiseAnd)
|
||||||
|
{
|
||||||
|
Operand src1 = op.GetSource(0);
|
||||||
|
Operand src2 = op.GetSource(1);
|
||||||
|
|
||||||
|
int addressIndex = -1;
|
||||||
|
|
||||||
|
if (src1 == address && src2.Type == OperandType.Constant && src2.Value == 3)
|
||||||
|
{
|
||||||
|
addressIndex = 0;
|
||||||
|
}
|
||||||
|
else if (src2 == address && src1.Type == OperandType.Constant && src1.Value == 3)
|
||||||
|
{
|
||||||
|
addressIndex = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addressIndex != -1)
|
||||||
|
{
|
||||||
|
LinkedListNode<INode> node = list.Find(op);
|
||||||
|
|
||||||
|
// Add offset calculation before the use. Needs to be on the same block.
|
||||||
|
if (node != null)
|
||||||
|
{
|
||||||
|
Operand offset = Local();
|
||||||
|
Operation addOp = new Operation(Instruction.Add, offset, byteOffset, Const(constantOffset));
|
||||||
|
list.AddBefore(node, addOp);
|
||||||
|
|
||||||
|
op.SetSource(addressIndex, offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static (Operand, int) GetStorageOffset(BasicBlock block, Operand address, int baseAddressCbOffset)
|
||||||
|
{
|
||||||
|
if (IsCb0Offset(address, baseAddressCbOffset))
|
||||||
|
{
|
||||||
|
// Direct offset: zero.
|
||||||
|
return (Const(0), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
(address, int constantOffset) = GetStorageConstantOffset(block, address);
|
||||||
|
|
||||||
|
address = Utils.FindLastOperation(address, block);
|
||||||
|
|
||||||
|
if (IsCb0Offset(address, baseAddressCbOffset))
|
||||||
|
{
|
||||||
|
// Only constant offset
|
||||||
|
return (Const(0), constantOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(address.AsgOp is Operation offsetAdd) || offsetAdd.Inst != Instruction.Add)
|
||||||
|
{
|
||||||
|
return (null, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand src1 = offsetAdd.GetSource(0);
|
||||||
|
Operand src2 = Utils.FindLastOperation(offsetAdd.GetSource(1), block);
|
||||||
|
|
||||||
|
if (IsCb0Offset(src2, baseAddressCbOffset))
|
||||||
|
{
|
||||||
|
return (src1, constantOffset);
|
||||||
|
}
|
||||||
|
else if (IsCb0Offset(src1, baseAddressCbOffset))
|
||||||
|
{
|
||||||
|
return (src2, constantOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (null, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static (Operand, int) GetStorageConstantOffset(BasicBlock block, Operand address)
|
||||||
|
{
|
||||||
|
if (!(address.AsgOp is Operation offsetAdd) || offsetAdd.Inst != Instruction.Add)
|
||||||
|
{
|
||||||
|
return (address, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand src1 = offsetAdd.GetSource(0);
|
||||||
|
Operand src2 = offsetAdd.GetSource(1);
|
||||||
|
|
||||||
|
if (src2.Type != OperandType.Constant)
|
||||||
|
{
|
||||||
|
return (address, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (src1, src2.Value);
|
||||||
|
}
|
||||||
|
|
||||||
private static LinkedListNode<INode> ReplaceLdgWithLdc(LinkedListNode<INode> node, ShaderConfig config, int storageIndex)
|
private static LinkedListNode<INode> ReplaceLdgWithLdc(LinkedListNode<INode> node, ShaderConfig config, int storageIndex)
|
||||||
{
|
{
|
||||||
Operation operation = (Operation)node.Value;
|
Operation operation = (Operation)node.Value;
|
||||||
|
@@ -26,8 +26,8 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
|
|||||||
{
|
{
|
||||||
class IApplicationFunctions : IpcService
|
class IApplicationFunctions : IpcService
|
||||||
{
|
{
|
||||||
private ulong _defaultSaveDataSize = 200000000;
|
private long _defaultSaveDataSize = 200000000;
|
||||||
private ulong _defaultJournalSaveDataSize = 200000000;
|
private long _defaultJournalSaveDataSize = 200000000;
|
||||||
|
|
||||||
private KEvent _gpuErrorDetectedSystemEvent;
|
private KEvent _gpuErrorDetectedSystemEvent;
|
||||||
private KEvent _friendInvitationStorageChannelEvent;
|
private KEvent _friendInvitationStorageChannelEvent;
|
||||||
@@ -203,13 +203,13 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
|
|||||||
}
|
}
|
||||||
|
|
||||||
[CommandHipc(25)] // 3.0.0+
|
[CommandHipc(25)] // 3.0.0+
|
||||||
// ExtendSaveData(u8 save_data_type, nn::account::Uid, u64 save_size, u64 journal_size) -> u64 result_code
|
// ExtendSaveData(u8 save_data_type, nn::account::Uid, s64 save_size, s64 journal_size) -> u64 result_code
|
||||||
public ResultCode ExtendSaveData(ServiceCtx context)
|
public ResultCode ExtendSaveData(ServiceCtx context)
|
||||||
{
|
{
|
||||||
SaveDataType saveDataType = (SaveDataType)context.RequestData.ReadUInt64();
|
SaveDataType saveDataType = (SaveDataType)context.RequestData.ReadUInt64();
|
||||||
Uid userId = context.RequestData.ReadStruct<Uid>();
|
Uid userId = context.RequestData.ReadStruct<Uid>();
|
||||||
ulong saveDataSize = context.RequestData.ReadUInt64();
|
long saveDataSize = context.RequestData.ReadInt64();
|
||||||
ulong journalSize = context.RequestData.ReadUInt64();
|
long journalSize = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
// NOTE: Service calls nn::fs::ExtendApplicationSaveData.
|
// NOTE: Service calls nn::fs::ExtendApplicationSaveData.
|
||||||
// Since LibHac currently doesn't support this method, we can stub it for now.
|
// Since LibHac currently doesn't support this method, we can stub it for now.
|
||||||
@@ -225,7 +225,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
|
|||||||
}
|
}
|
||||||
|
|
||||||
[CommandHipc(26)] // 3.0.0+
|
[CommandHipc(26)] // 3.0.0+
|
||||||
// GetSaveDataSize(u8 save_data_type, nn::account::Uid) -> (u64 save_size, u64 journal_size)
|
// GetSaveDataSize(u8 save_data_type, nn::account::Uid) -> (s64 save_size, s64 journal_size)
|
||||||
public ResultCode GetSaveDataSize(ServiceCtx context)
|
public ResultCode GetSaveDataSize(ServiceCtx context)
|
||||||
{
|
{
|
||||||
SaveDataType saveDataType = (SaveDataType)context.RequestData.ReadUInt64();
|
SaveDataType saveDataType = (SaveDataType)context.RequestData.ReadUInt64();
|
||||||
@@ -268,6 +268,23 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
|
|||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[CommandHipc(28)] // 11.0.0+
|
||||||
|
// GetSaveDataSizeMax() -> (s64 save_size_max, s64 journal_size_max)
|
||||||
|
public ResultCode GetSaveDataSizeMax(ServiceCtx context)
|
||||||
|
{
|
||||||
|
// NOTE: We are currently using a stub for GetSaveDataSize() which returns the default values.
|
||||||
|
// For this method we shouldn't return anything lower than that, but since we aren't interacting
|
||||||
|
// with fs to get the actual sizes, we return the default values here as well.
|
||||||
|
// This also helps in case ExtendSaveData() has been executed and the default values were modified.
|
||||||
|
|
||||||
|
context.ResponseData.Write(_defaultSaveDataSize);
|
||||||
|
context.ResponseData.Write(_defaultJournalSaveDataSize);
|
||||||
|
|
||||||
|
Logger.Stub?.PrintStub(LogClass.ServiceAm);
|
||||||
|
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
[CommandHipc(30)]
|
[CommandHipc(30)]
|
||||||
// BeginBlockingHomeButtonShortAndLongPressed()
|
// BeginBlockingHomeButtonShortAndLongPressed()
|
||||||
public ResultCode BeginBlockingHomeButtonShortAndLongPressed(ServiceCtx context)
|
public ResultCode BeginBlockingHomeButtonShortAndLongPressed(ServiceCtx context)
|
||||||
|
@@ -25,6 +25,7 @@ namespace Ryujinx.Memory.Tracking
|
|||||||
|
|
||||||
private int _sequenceNumber;
|
private int _sequenceNumber;
|
||||||
private BitMap _sequenceNumberBitmap;
|
private BitMap _sequenceNumberBitmap;
|
||||||
|
private BitMap _dirtyCheckedBitmap;
|
||||||
private int _uncheckedHandles;
|
private int _uncheckedHandles;
|
||||||
|
|
||||||
public bool Dirty { get; private set; } = true;
|
public bool Dirty { get; private set; } = true;
|
||||||
@@ -36,6 +37,7 @@ namespace Ryujinx.Memory.Tracking
|
|||||||
|
|
||||||
_dirtyBitmap = new ConcurrentBitmap(_handles.Length, true);
|
_dirtyBitmap = new ConcurrentBitmap(_handles.Length, true);
|
||||||
_sequenceNumberBitmap = new BitMap(_handles.Length);
|
_sequenceNumberBitmap = new BitMap(_handles.Length);
|
||||||
|
_dirtyCheckedBitmap = new BitMap(_handles.Length);
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
@@ -246,16 +248,18 @@ namespace Ryujinx.Memory.Tracking
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private void ParseDirtyBits(long dirtyBits, long mask, int index, long[] seqMasks, ref int baseBit, ref int prevHandle, ref ulong rgStart, ref ulong rgSize, Action<ulong, ulong> modifiedAction)
|
private void ParseDirtyBits(long dirtyBits, long mask, int index, long[] seqMasks, long[] checkMasks, ref int baseBit, ref int prevHandle, ref ulong rgStart, ref ulong rgSize, Action<ulong, ulong> modifiedAction)
|
||||||
{
|
{
|
||||||
long seqMask = mask & ~seqMasks[index];
|
long seqMask = mask & ~seqMasks[index];
|
||||||
|
long checkMask = (~dirtyBits) & seqMask;
|
||||||
dirtyBits &= seqMask;
|
dirtyBits &= seqMask;
|
||||||
|
|
||||||
while (dirtyBits != 0)
|
while (dirtyBits != 0)
|
||||||
{
|
{
|
||||||
int bit = BitOperations.TrailingZeroCount(dirtyBits);
|
int bit = BitOperations.TrailingZeroCount(dirtyBits);
|
||||||
|
long bitValue = 1L << bit;
|
||||||
|
|
||||||
dirtyBits &= ~(1L << bit);
|
dirtyBits &= ~bitValue;
|
||||||
|
|
||||||
int handleIndex = baseBit + bit;
|
int handleIndex = baseBit + bit;
|
||||||
|
|
||||||
@@ -273,11 +277,14 @@ namespace Ryujinx.Memory.Tracking
|
|||||||
}
|
}
|
||||||
|
|
||||||
rgSize += handle.Size;
|
rgSize += handle.Size;
|
||||||
handle.Reprotect();
|
handle.Reprotect(false, (checkMasks[index] & bitValue) == 0);
|
||||||
|
|
||||||
|
checkMasks[index] &= ~bitValue;
|
||||||
|
|
||||||
prevHandle = handleIndex;
|
prevHandle = handleIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkMasks[index] |= checkMask;
|
||||||
seqMasks[index] |= mask;
|
seqMasks[index] |= mask;
|
||||||
_uncheckedHandles -= BitOperations.PopCount((ulong)seqMask);
|
_uncheckedHandles -= BitOperations.PopCount((ulong)seqMask);
|
||||||
|
|
||||||
@@ -328,6 +335,7 @@ namespace Ryujinx.Memory.Tracking
|
|||||||
ulong rgSize = 0;
|
ulong rgSize = 0;
|
||||||
|
|
||||||
long[] seqMasks = _sequenceNumberBitmap.Masks;
|
long[] seqMasks = _sequenceNumberBitmap.Masks;
|
||||||
|
long[] checkedMasks = _dirtyCheckedBitmap.Masks;
|
||||||
long[] masks = _dirtyBitmap.Masks;
|
long[] masks = _dirtyBitmap.Masks;
|
||||||
|
|
||||||
int startIndex = startHandle >> ConcurrentBitmap.IntShift;
|
int startIndex = startHandle >> ConcurrentBitmap.IntShift;
|
||||||
@@ -345,20 +353,20 @@ namespace Ryujinx.Memory.Tracking
|
|||||||
|
|
||||||
if (startIndex == endIndex)
|
if (startIndex == endIndex)
|
||||||
{
|
{
|
||||||
ParseDirtyBits(startValue, startMask & endMask, startIndex, seqMasks, ref baseBit, ref prevHandle, ref rgStart, ref rgSize, modifiedAction);
|
ParseDirtyBits(startValue, startMask & endMask, startIndex, seqMasks, checkedMasks, ref baseBit, ref prevHandle, ref rgStart, ref rgSize, modifiedAction);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ParseDirtyBits(startValue, startMask, startIndex, seqMasks, ref baseBit, ref prevHandle, ref rgStart, ref rgSize, modifiedAction);
|
ParseDirtyBits(startValue, startMask, startIndex, seqMasks, checkedMasks, ref baseBit, ref prevHandle, ref rgStart, ref rgSize, modifiedAction);
|
||||||
|
|
||||||
for (int i = startIndex + 1; i < endIndex; i++)
|
for (int i = startIndex + 1; i < endIndex; i++)
|
||||||
{
|
{
|
||||||
ParseDirtyBits(Volatile.Read(ref masks[i]), -1L, i, seqMasks, ref baseBit, ref prevHandle, ref rgStart, ref rgSize, modifiedAction);
|
ParseDirtyBits(Volatile.Read(ref masks[i]), -1L, i, seqMasks, checkedMasks, ref baseBit, ref prevHandle, ref rgStart, ref rgSize, modifiedAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
long endValue = Volatile.Read(ref masks[endIndex]);
|
long endValue = Volatile.Read(ref masks[endIndex]);
|
||||||
|
|
||||||
ParseDirtyBits(endValue, endMask, endIndex, seqMasks, ref baseBit, ref prevHandle, ref rgStart, ref rgSize, modifiedAction);
|
ParseDirtyBits(endValue, endMask, endIndex, seqMasks, checkedMasks, ref baseBit, ref prevHandle, ref rgStart, ref rgSize, modifiedAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rgSize != 0)
|
if (rgSize != 0)
|
||||||
|
@@ -263,15 +263,15 @@ namespace Ryujinx.Memory.Tracking
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void ForceDirty()
|
public void ForceDirty()
|
||||||
{
|
{
|
||||||
_checkCount++;
|
|
||||||
|
|
||||||
Dirty = true;
|
Dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Consume the dirty flag for this handle, and reprotect so it can be set on the next write.
|
/// Consume the dirty flag for this handle, and reprotect so it can be set on the next write.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Reprotect(bool asDirty = false)
|
/// <param name="asDirty">True if the handle should be reprotected as dirty, rather than have it cleared</param>
|
||||||
|
/// <param name="consecutiveCheck">True if this reprotect is the result of consecutive dirty checks</param>
|
||||||
|
public void Reprotect(bool asDirty, bool consecutiveCheck = false)
|
||||||
{
|
{
|
||||||
if (_volatile) return;
|
if (_volatile) return;
|
||||||
|
|
||||||
@@ -296,7 +296,7 @@ namespace Ryujinx.Memory.Tracking
|
|||||||
}
|
}
|
||||||
else if (!asDirty)
|
else if (!asDirty)
|
||||||
{
|
{
|
||||||
if (_checkCount > 0 && _checkCount < CheckCountForInfrequent)
|
if (consecutiveCheck || (_checkCount > 0 && _checkCount < CheckCountForInfrequent))
|
||||||
{
|
{
|
||||||
if (++_volatileCount >= VolatileThreshold && _preAction == null)
|
if (++_volatileCount >= VolatileThreshold && _preAction == null)
|
||||||
{
|
{
|
||||||
@@ -313,6 +313,15 @@ namespace Ryujinx.Memory.Tracking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Consume the dirty flag for this handle, and reprotect so it can be set on the next write.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="asDirty">True if the handle should be reprotected as dirty, rather than have it cleared</param>
|
||||||
|
public void Reprotect(bool asDirty = false)
|
||||||
|
{
|
||||||
|
Reprotect(asDirty, false);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Register an action to perform when the tracked region is read or written.
|
/// Register an action to perform when the tracked region is read or written.
|
||||||
/// The action is automatically removed after it runs.
|
/// The action is automatically removed after it runs.
|
||||||
|
Reference in New Issue
Block a user