Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
46cc7b55f0 | ||
|
dd8f97ab9e | ||
|
633c5ec330 | ||
|
a3e7bb8eb4 | ||
|
2073ba2919 | ||
|
d03124a992 | ||
|
59490d54b5 |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -39,7 +39,7 @@ jobs:
|
|||||||
|
|
||||||
- os: windows-latest
|
- os: windows-latest
|
||||||
OS_NAME: Windows x64
|
OS_NAME: Windows x64
|
||||||
DOTNET_RUNTIME_IDENTIFIER: win-x64
|
DOTNET_RUNTIME_IDENTIFIER: win10-x64
|
||||||
RELEASE_ZIP_OS_NAME: win_x64
|
RELEASE_ZIP_OS_NAME: win_x64
|
||||||
|
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
|
7
.github/workflows/nightly_pr_comment.yml
vendored
7
.github/workflows/nightly_pr_comment.yml
vendored
@@ -36,19 +36,24 @@ jobs:
|
|||||||
return core.error(`No artifacts found`);
|
return core.error(`No artifacts found`);
|
||||||
}
|
}
|
||||||
let body = `Download the artifacts for this pull request:\n`;
|
let body = `Download the artifacts for this pull request:\n`;
|
||||||
|
let hidden_avalonia_artifacts = `\n\n <details><summary>Experimental GUI (Avalonia)</summary>\n`;
|
||||||
let hidden_headless_artifacts = `\n\n <details><summary>GUI-less (SDL2)</summary>\n`;
|
let hidden_headless_artifacts = `\n\n <details><summary>GUI-less (SDL2)</summary>\n`;
|
||||||
let hidden_debug_artifacts = `\n\n <details><summary>Only for Developers</summary>\n`;
|
let hidden_debug_artifacts = `\n\n <details><summary>Only for Developers</summary>\n`;
|
||||||
for (const art of artifacts) {
|
for (const art of artifacts) {
|
||||||
if(art.name.includes('Debug')) {
|
if(art.name.includes('Debug')) {
|
||||||
hidden_debug_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
|
hidden_debug_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
|
||||||
} else if(art.name.includes('headless-sdl2')) {
|
} else if(art.name.includes('ava-ryujinx')) {
|
||||||
|
hidden_avalonia_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
|
||||||
|
} else if(art.name.includes('sdl2-ryujinx-headless')) {
|
||||||
hidden_headless_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
|
hidden_headless_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
|
||||||
} else {
|
} else {
|
||||||
body += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
|
body += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
hidden_avalonia_artifacts += `\n</details>`;
|
||||||
hidden_headless_artifacts += `\n</details>`;
|
hidden_headless_artifacts += `\n</details>`;
|
||||||
hidden_debug_artifacts += `\n</details>`;
|
hidden_debug_artifacts += `\n</details>`;
|
||||||
|
body += hidden_avalonia_artifacts;
|
||||||
body += hidden_headless_artifacts;
|
body += hidden_headless_artifacts;
|
||||||
body += hidden_debug_artifacts;
|
body += hidden_debug_artifacts;
|
||||||
|
|
||||||
|
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
@@ -51,9 +51,9 @@ jobs:
|
|||||||
run: "mkdir release_output"
|
run: "mkdir release_output"
|
||||||
- name: Publish Windows
|
- name: Publish Windows
|
||||||
run: |
|
run: |
|
||||||
dotnet publish -c Release -r win-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
|
||||||
dotnet publish -c Release -r win-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
|
||||||
dotnet publish -c Release -r win-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
|
||||||
- name: Packing Windows builds
|
- name: Packing Windows builds
|
||||||
run: |
|
run: |
|
||||||
pushd publish_windows
|
pushd publish_windows
|
||||||
|
@@ -14,10 +14,11 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
public byte Kind;
|
public byte Kind;
|
||||||
public byte Type;
|
public byte Type;
|
||||||
public byte SymbolType;
|
public byte SymbolType;
|
||||||
|
public byte Padding; // Unused space.
|
||||||
public ushort AssignmentsCount;
|
public ushort AssignmentsCount;
|
||||||
public ushort AssignmentsCapacity;
|
public ushort AssignmentsCapacity;
|
||||||
public ushort UsesCount;
|
public uint UsesCount;
|
||||||
public ushort UsesCapacity;
|
public uint UsesCapacity;
|
||||||
public Operation* Assignments;
|
public Operation* Assignments;
|
||||||
public Operation* Uses;
|
public Operation* Uses;
|
||||||
public ulong Value;
|
public ulong Value;
|
||||||
@@ -84,11 +85,11 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
{
|
{
|
||||||
Debug.Assert(Kind != OperandKind.Memory);
|
Debug.Assert(Kind != OperandKind.Memory);
|
||||||
|
|
||||||
return new ReadOnlySpan<Operation>(_data->Uses, _data->UsesCount);
|
return new ReadOnlySpan<Operation>(_data->Uses, (int)_data->UsesCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int UsesCount => _data->UsesCount;
|
public int UsesCount => (int)_data->UsesCount;
|
||||||
public int AssignmentsCount => _data->AssignmentsCount;
|
public int AssignmentsCount => _data->AssignmentsCount;
|
||||||
|
|
||||||
public bool Relocatable => Symbol.Type != SymbolType.None;
|
public bool Relocatable => Symbol.Type != SymbolType.None;
|
||||||
@@ -178,7 +179,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
{
|
{
|
||||||
Add(operation, ref addr._data->Assignments, ref addr._data->AssignmentsCount, ref addr._data->AssignmentsCapacity);
|
Add(operation, ref addr._data->Assignments, ref addr._data->AssignmentsCount, ref addr._data->AssignmentsCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index != default)
|
if (index != default)
|
||||||
{
|
{
|
||||||
Add(operation, ref index._data->Assignments, ref index._data->AssignmentsCount, ref index._data->AssignmentsCapacity);
|
Add(operation, ref index._data->Assignments, ref index._data->AssignmentsCount, ref index._data->AssignmentsCapacity);
|
||||||
@@ -265,6 +266,13 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
data = Allocators.References.Allocate<T>(initialCapacity);
|
data = Allocators.References.Allocate<T>(initialCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void New<T>(ref T* data, ref uint count, ref uint capacity, uint initialCapacity) where T : unmanaged
|
||||||
|
{
|
||||||
|
count = 0;
|
||||||
|
capacity = initialCapacity;
|
||||||
|
data = Allocators.References.Allocate<T>(initialCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
private static void Add<T>(T item, ref T* data, ref ushort count, ref ushort capacity) where T : unmanaged
|
private static void Add<T>(T item, ref T* data, ref ushort count, ref ushort capacity) where T : unmanaged
|
||||||
{
|
{
|
||||||
if (count < capacity)
|
if (count < capacity)
|
||||||
@@ -294,6 +302,40 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void Add<T>(T item, ref T* data, ref uint count, ref uint capacity) where T : unmanaged
|
||||||
|
{
|
||||||
|
if (count < capacity)
|
||||||
|
{
|
||||||
|
data[count++] = item;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Could not add item in the fast path, fallback onto the slow path.
|
||||||
|
ExpandAdd(item, ref data, ref count, ref capacity);
|
||||||
|
|
||||||
|
static void ExpandAdd(T item, ref T* data, ref uint count, ref uint capacity)
|
||||||
|
{
|
||||||
|
uint newCount = checked(count + 1);
|
||||||
|
uint newCapacity = (uint)Math.Min(capacity * 2, int.MaxValue);
|
||||||
|
|
||||||
|
if (newCapacity <= capacity)
|
||||||
|
{
|
||||||
|
throw new OverflowException();
|
||||||
|
}
|
||||||
|
|
||||||
|
var oldSpan = new Span<T>(data, (int)count);
|
||||||
|
|
||||||
|
capacity = newCapacity;
|
||||||
|
data = Allocators.References.Allocate<T>(capacity);
|
||||||
|
|
||||||
|
oldSpan.CopyTo(new Span<T>(data, (int)count));
|
||||||
|
|
||||||
|
data[count] = item;
|
||||||
|
count = newCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void Remove<T>(in T item, ref T* data, ref ushort count) where T : unmanaged
|
private static void Remove<T>(in T item, ref T* data, ref ushort count) where T : unmanaged
|
||||||
{
|
{
|
||||||
var span = new Span<T>(data, count);
|
var span = new Span<T>(data, count);
|
||||||
@@ -314,6 +356,26 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void Remove<T>(in T item, ref T* data, ref uint count) where T : unmanaged
|
||||||
|
{
|
||||||
|
var span = new Span<T>(data, (int)count);
|
||||||
|
|
||||||
|
for (int i = 0; i < span.Length; i++)
|
||||||
|
{
|
||||||
|
if (EqualityComparer<T>.Default.Equals(span[i], item))
|
||||||
|
{
|
||||||
|
if (i + 1 < count)
|
||||||
|
{
|
||||||
|
span.Slice(i + 1).CopyTo(span.Slice(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
count--;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
if (Kind == OperandKind.LocalVariable)
|
if (Kind == OperandKind.LocalVariable)
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win10-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -15,11 +15,11 @@
|
|||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
<TargetPath>libsoundio.dll</TargetPath>
|
<TargetPath>libsoundio.dll</TargetPath>
|
||||||
</ContentWithTargetPath>
|
</ContentWithTargetPath>
|
||||||
<ContentWithTargetPath Include="Native\libsoundio\libs\libsoundio.dylib" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'win-x64'">
|
<ContentWithTargetPath Include="Native\libsoundio\libs\libsoundio.dylib" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'win10-x64'">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
<TargetPath>libsoundio.dylib</TargetPath>
|
<TargetPath>libsoundio.dylib</TargetPath>
|
||||||
</ContentWithTargetPath>
|
</ContentWithTargetPath>
|
||||||
<ContentWithTargetPath Include="Native\libsoundio\libs\libsoundio.so" Condition="'$(RuntimeIdentifier)' != 'win-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'">
|
<ContentWithTargetPath Include="Native\libsoundio\libs\libsoundio.so" Condition="'$(RuntimeIdentifier)' != 'win10-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
<TargetPath>libsoundio.so</TargetPath>
|
<TargetPath>libsoundio.so</TargetPath>
|
||||||
</ContentWithTargetPath>
|
</ContentWithTargetPath>
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<RuntimeIdentifiers>win-x64;osx-x64;linux-x64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win10-x64;osx-x64;linux-x64</RuntimeIdentifiers>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<Version>1.0.0-dirty</Version>
|
<Version>1.0.0-dirty</Version>
|
||||||
|
@@ -13,4 +13,12 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
CubemapArray,
|
CubemapArray,
|
||||||
TextureBuffer
|
TextureBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class TargetExtensions
|
||||||
|
{
|
||||||
|
public static bool IsMultisample(this Target target)
|
||||||
|
{
|
||||||
|
return target == Target.Texture2DMultisample || target == Target.Texture2DMultisampleArray;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@@ -18,6 +18,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
|
|
||||||
private bool _instancedDrawPending;
|
private bool _instancedDrawPending;
|
||||||
private bool _instancedIndexed;
|
private bool _instancedIndexed;
|
||||||
|
private bool _instancedIndexedInline;
|
||||||
|
|
||||||
private int _instancedFirstIndex;
|
private int _instancedFirstIndex;
|
||||||
private int _instancedFirstVertex;
|
private int _instancedFirstVertex;
|
||||||
@@ -135,6 +136,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
_instancedDrawPending = true;
|
_instancedDrawPending = true;
|
||||||
|
|
||||||
_instancedIndexed = _drawState.DrawIndexed;
|
_instancedIndexed = _drawState.DrawIndexed;
|
||||||
|
_instancedIndexedInline = _drawState.IbStreamer.HasInlineIndexData;
|
||||||
|
|
||||||
_instancedFirstIndex = firstIndex;
|
_instancedFirstIndex = firstIndex;
|
||||||
_instancedFirstVertex = (int)_state.State.FirstVertex;
|
_instancedFirstVertex = (int)_state.State.FirstVertex;
|
||||||
@@ -451,7 +453,21 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
{
|
{
|
||||||
_instancedDrawPending = false;
|
_instancedDrawPending = false;
|
||||||
|
|
||||||
if (_instancedIndexed)
|
if (_instancedIndexedInline)
|
||||||
|
{
|
||||||
|
int inlineIndexCount = _drawState.IbStreamer.GetAndResetInlineIndexCount();
|
||||||
|
BufferRange br = new BufferRange(_drawState.IbStreamer.GetInlineIndexBuffer(), 0, inlineIndexCount * 4);
|
||||||
|
|
||||||
|
_channel.BufferManager.SetIndexBuffer(br, IndexType.UInt);
|
||||||
|
|
||||||
|
_context.Renderer.Pipeline.DrawIndexed(
|
||||||
|
inlineIndexCount,
|
||||||
|
_instanceIndex + 1,
|
||||||
|
_instancedFirstIndex,
|
||||||
|
_instancedFirstVertex,
|
||||||
|
_instancedFirstInstance);
|
||||||
|
}
|
||||||
|
else if (_instancedIndexed)
|
||||||
{
|
{
|
||||||
_context.Renderer.Pipeline.DrawIndexed(
|
_context.Renderer.Pipeline.DrawIndexed(
|
||||||
_instancedIndexCount,
|
_instancedIndexCount,
|
||||||
|
@@ -44,7 +44,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private enum ReportCounterType
|
private enum ReportCounterType
|
||||||
{
|
{
|
||||||
Zero = 0,
|
Payload = 0,
|
||||||
InputVertices = 1,
|
InputVertices = 1,
|
||||||
InputPrimitives = 3,
|
InputPrimitives = 3,
|
||||||
VertexShaderInvocations = 5,
|
VertexShaderInvocations = 5,
|
||||||
@@ -169,8 +169,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case ReportCounterType.Zero:
|
case ReportCounterType.Payload:
|
||||||
resultHandler(null, 0);
|
resultHandler(null, (ulong)_state.State.SemaphorePayload);
|
||||||
break;
|
break;
|
||||||
case ReportCounterType.SamplesPassed:
|
case ReportCounterType.SamplesPassed:
|
||||||
counter = _context.Renderer.ReportCounter(CounterType.SamplesPassed, resultHandler, false);
|
counter = _context.Renderer.ReportCounter(CounterType.SamplesPassed, resultHandler, false);
|
||||||
|
@@ -1136,32 +1136,22 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
/// <param name="range">Texture view physical memory ranges</param>
|
/// <param name="range">Texture view physical memory ranges</param>
|
||||||
/// <param name="layerSize">Layer size on the given texture</param>
|
/// <param name="layerSize">Layer size on the given texture</param>
|
||||||
/// <param name="caps">Host GPU capabilities</param>
|
/// <param name="caps">Host GPU capabilities</param>
|
||||||
/// <param name="allowMs">Indicates that multisample textures are allowed to match non-multisample requested textures</param>
|
|
||||||
/// <param name="firstLayer">Texture view initial layer on this texture</param>
|
/// <param name="firstLayer">Texture view initial layer on this texture</param>
|
||||||
/// <param name="firstLevel">Texture view first mipmap level on this texture</param>
|
/// <param name="firstLevel">Texture view first mipmap level on this texture</param>
|
||||||
/// <returns>The level of compatiblilty a view with the given parameters created from this texture has</returns>
|
/// <returns>The level of compatiblilty a view with the given parameters created from this texture has</returns>
|
||||||
public TextureViewCompatibility IsViewCompatible(TextureInfo info, MultiRange range, int layerSize, Capabilities caps, bool allowMs, out int firstLayer, out int firstLevel)
|
public TextureViewCompatibility IsViewCompatible(TextureInfo info, MultiRange range, int layerSize, Capabilities caps, out int firstLayer, out int firstLevel)
|
||||||
{
|
{
|
||||||
TextureViewCompatibility result = TextureViewCompatibility.Full;
|
TextureViewCompatibility result = TextureViewCompatibility.Full;
|
||||||
|
|
||||||
result = TextureCompatibility.PropagateViewCompatibility(result, TextureCompatibility.ViewFormatCompatible(Info, info, caps));
|
result = TextureCompatibility.PropagateViewCompatibility(result, TextureCompatibility.ViewFormatCompatible(Info, info, caps));
|
||||||
if (result != TextureViewCompatibility.Incompatible)
|
if (result != TextureViewCompatibility.Incompatible)
|
||||||
{
|
{
|
||||||
bool msTargetCompatible = false;
|
result = TextureCompatibility.PropagateViewCompatibility(result, TextureCompatibility.ViewTargetCompatible(Info, info));
|
||||||
|
|
||||||
if (allowMs)
|
bool bothMs = Info.Target.IsMultisample() && info.Target.IsMultisample();
|
||||||
|
if (bothMs && (Info.SamplesInX != info.SamplesInX || Info.SamplesInY != info.SamplesInY))
|
||||||
{
|
{
|
||||||
msTargetCompatible = Info.Target == Target.Texture2DMultisample && info.Target == Target.Texture2D;
|
result = TextureViewCompatibility.Incompatible;
|
||||||
}
|
|
||||||
|
|
||||||
if (!msTargetCompatible)
|
|
||||||
{
|
|
||||||
result = TextureCompatibility.PropagateViewCompatibility(result, TextureCompatibility.ViewTargetCompatible(Info, info));
|
|
||||||
|
|
||||||
if (Info.SamplesInX != info.SamplesInX || Info.SamplesInY != info.SamplesInY)
|
|
||||||
{
|
|
||||||
result = TextureViewCompatibility.Incompatible;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == TextureViewCompatibility.Full && Info.FormatInfo.Format != info.FormatInfo.Format && !_context.Capabilities.SupportsMismatchingViewFormat)
|
if (result == TextureViewCompatibility.Full && Info.FormatInfo.Format != info.FormatInfo.Format && !_context.Capabilities.SupportsMismatchingViewFormat)
|
||||||
|
@@ -547,7 +547,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
range.Value,
|
range.Value,
|
||||||
sizeInfo.LayerSize,
|
sizeInfo.LayerSize,
|
||||||
_context.Capabilities,
|
_context.Capabilities,
|
||||||
flags.HasFlag(TextureSearchFlags.ForCopy),
|
|
||||||
out int firstLayer,
|
out int firstLayer,
|
||||||
out int firstLevel);
|
out int firstLevel);
|
||||||
|
|
||||||
@@ -662,7 +661,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
overlap.Range,
|
overlap.Range,
|
||||||
overlap.LayerSize,
|
overlap.LayerSize,
|
||||||
_context.Capabilities,
|
_context.Capabilities,
|
||||||
false,
|
|
||||||
out int firstLayer,
|
out int firstLayer,
|
||||||
out int firstLevel);
|
out int firstLevel);
|
||||||
|
|
||||||
|
@@ -2,7 +2,6 @@ using Ryujinx.Common;
|
|||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Texture;
|
using Ryujinx.Graphics.Texture;
|
||||||
using System;
|
using System;
|
||||||
using System.Numerics;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Image
|
namespace Ryujinx.Graphics.Gpu.Image
|
||||||
{
|
{
|
||||||
@@ -657,6 +656,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
|
|
||||||
case Target.Texture2DMultisample:
|
case Target.Texture2DMultisample:
|
||||||
case Target.Texture2DMultisampleArray:
|
case Target.Texture2DMultisampleArray:
|
||||||
|
if (rhs.Target == Target.Texture2D || rhs.Target == Target.Texture2DArray)
|
||||||
|
{
|
||||||
|
return TextureViewCompatibility.CopyOnly;
|
||||||
|
}
|
||||||
|
|
||||||
result = rhs.Target == Target.Texture2DMultisample ||
|
result = rhs.Target == Target.Texture2DMultisample ||
|
||||||
rhs.Target == Target.Texture2DMultisampleArray;
|
rhs.Target == Target.Texture2DMultisampleArray;
|
||||||
break;
|
break;
|
||||||
|
98
Ryujinx.Graphics.OpenGL/Image/IntermmediatePool.cs
Normal file
98
Ryujinx.Graphics.OpenGL/Image/IntermmediatePool.cs
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
using Ryujinx.Graphics.GAL;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.OpenGL.Image
|
||||||
|
{
|
||||||
|
class IntermmediatePool : IDisposable
|
||||||
|
{
|
||||||
|
private readonly Renderer _renderer;
|
||||||
|
private readonly List<TextureView> _entries;
|
||||||
|
|
||||||
|
public IntermmediatePool(Renderer renderer)
|
||||||
|
{
|
||||||
|
_renderer = renderer;
|
||||||
|
_entries = new List<TextureView>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextureView GetOrCreateWithAtLeast(
|
||||||
|
Target target,
|
||||||
|
int blockWidth,
|
||||||
|
int blockHeight,
|
||||||
|
int bytesPerPixel,
|
||||||
|
Format format,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
int depth,
|
||||||
|
int levels)
|
||||||
|
{
|
||||||
|
TextureView entry;
|
||||||
|
|
||||||
|
for (int i = 0; i < _entries.Count; i++)
|
||||||
|
{
|
||||||
|
entry = _entries[i];
|
||||||
|
|
||||||
|
if (entry.Target == target && entry.Format == format)
|
||||||
|
{
|
||||||
|
if (entry.Width < width || entry.Height < height || entry.Info.Depth < depth || entry.Info.Levels < levels)
|
||||||
|
{
|
||||||
|
width = Math.Max(width, entry.Width);
|
||||||
|
height = Math.Max(height, entry.Height);
|
||||||
|
depth = Math.Max(depth, entry.Info.Depth);
|
||||||
|
levels = Math.Max(levels, entry.Info.Levels);
|
||||||
|
|
||||||
|
entry.Dispose();
|
||||||
|
entry = CreateNew(target, blockWidth, blockHeight, bytesPerPixel, format, width, height, depth, levels);
|
||||||
|
_entries[i] = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = CreateNew(target, blockWidth, blockHeight, bytesPerPixel, format, width, height, depth, levels);
|
||||||
|
_entries.Add(entry);
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TextureView CreateNew(
|
||||||
|
Target target,
|
||||||
|
int blockWidth,
|
||||||
|
int blockHeight,
|
||||||
|
int bytesPerPixel,
|
||||||
|
Format format,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
int depth,
|
||||||
|
int levels)
|
||||||
|
{
|
||||||
|
return (TextureView)_renderer.CreateTexture(new TextureCreateInfo(
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
depth,
|
||||||
|
levels,
|
||||||
|
1,
|
||||||
|
blockWidth,
|
||||||
|
blockHeight,
|
||||||
|
bytesPerPixel,
|
||||||
|
format,
|
||||||
|
DepthStencilMode.Depth,
|
||||||
|
target,
|
||||||
|
SwizzleComponent.Red,
|
||||||
|
SwizzleComponent.Green,
|
||||||
|
SwizzleComponent.Blue,
|
||||||
|
SwizzleComponent.Alpha), 1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
foreach (TextureView entry in _entries)
|
||||||
|
{
|
||||||
|
entry.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
_entries.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -9,6 +9,8 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||||||
{
|
{
|
||||||
private readonly Renderer _renderer;
|
private readonly Renderer _renderer;
|
||||||
|
|
||||||
|
public IntermmediatePool IntermmediatePool { get; }
|
||||||
|
|
||||||
private int _srcFramebuffer;
|
private int _srcFramebuffer;
|
||||||
private int _dstFramebuffer;
|
private int _dstFramebuffer;
|
||||||
|
|
||||||
@@ -18,6 +20,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||||||
public TextureCopy(Renderer renderer)
|
public TextureCopy(Renderer renderer)
|
||||||
{
|
{
|
||||||
_renderer = renderer;
|
_renderer = renderer;
|
||||||
|
IntermmediatePool = new IntermmediatePool(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Copy(
|
public void Copy(
|
||||||
@@ -25,7 +28,30 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||||||
TextureView dst,
|
TextureView dst,
|
||||||
Extents2D srcRegion,
|
Extents2D srcRegion,
|
||||||
Extents2D dstRegion,
|
Extents2D dstRegion,
|
||||||
bool linearFilter)
|
bool linearFilter,
|
||||||
|
int srcLayer = 0,
|
||||||
|
int dstLayer = 0,
|
||||||
|
int srcLevel = 0,
|
||||||
|
int dstLevel = 0)
|
||||||
|
{
|
||||||
|
int levels = Math.Min(src.Info.Levels - srcLevel, dst.Info.Levels - dstLevel);
|
||||||
|
int layers = Math.Min(src.Info.GetLayers() - srcLayer, dst.Info.GetLayers() - dstLayer);
|
||||||
|
|
||||||
|
Copy(src, dst, srcRegion, dstRegion, linearFilter, srcLayer, dstLayer, srcLevel, dstLevel, layers, levels);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Copy(
|
||||||
|
TextureView src,
|
||||||
|
TextureView dst,
|
||||||
|
Extents2D srcRegion,
|
||||||
|
Extents2D dstRegion,
|
||||||
|
bool linearFilter,
|
||||||
|
int srcLayer,
|
||||||
|
int dstLayer,
|
||||||
|
int srcLevel,
|
||||||
|
int dstLevel,
|
||||||
|
int layers,
|
||||||
|
int levels)
|
||||||
{
|
{
|
||||||
TextureView srcConverted = src.Format.IsBgr() != dst.Format.IsBgr() ? BgraSwap(src) : src;
|
TextureView srcConverted = src.Format.IsBgr() != dst.Format.IsBgr() ? BgraSwap(src) : src;
|
||||||
|
|
||||||
@@ -34,22 +60,29 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||||||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, GetSrcFramebufferLazy());
|
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, GetSrcFramebufferLazy());
|
||||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, GetDstFramebufferLazy());
|
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, GetDstFramebufferLazy());
|
||||||
|
|
||||||
int levels = Math.Min(src.Info.Levels, dst.Info.Levels);
|
if (srcLevel != 0)
|
||||||
int layers = Math.Min(src.Info.GetLayers(), dst.Info.GetLayers());
|
{
|
||||||
|
srcRegion = srcRegion.Reduce(srcLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dstLevel != 0)
|
||||||
|
{
|
||||||
|
dstRegion = dstRegion.Reduce(dstLevel);
|
||||||
|
}
|
||||||
|
|
||||||
for (int level = 0; level < levels; level++)
|
for (int level = 0; level < levels; level++)
|
||||||
{
|
{
|
||||||
for (int layer = 0; layer < layers; layer++)
|
for (int layer = 0; layer < layers; layer++)
|
||||||
{
|
{
|
||||||
if (layers > 1)
|
if ((srcLayer | dstLayer) != 0 || layers > 1)
|
||||||
{
|
{
|
||||||
Attach(FramebufferTarget.ReadFramebuffer, src.Format, srcConverted.Handle, level, layer);
|
Attach(FramebufferTarget.ReadFramebuffer, src.Format, srcConverted.Handle, srcLevel + level, srcLayer + layer);
|
||||||
Attach(FramebufferTarget.DrawFramebuffer, dst.Format, dst.Handle, level, layer);
|
Attach(FramebufferTarget.DrawFramebuffer, dst.Format, dst.Handle, dstLevel + level, dstLayer + layer);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Attach(FramebufferTarget.ReadFramebuffer, src.Format, srcConverted.Handle, level);
|
Attach(FramebufferTarget.ReadFramebuffer, src.Format, srcConverted.Handle, srcLevel + level);
|
||||||
Attach(FramebufferTarget.DrawFramebuffer, dst.Format, dst.Handle, level);
|
Attach(FramebufferTarget.DrawFramebuffer, dst.Format, dst.Handle, dstLevel + level);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClearBufferMask mask = GetMask(src.Format);
|
ClearBufferMask mask = GetMask(src.Format);
|
||||||
@@ -484,6 +517,8 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||||||
|
|
||||||
_copyPboHandle = 0;
|
_copyPboHandle = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IntermmediatePool.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -115,14 +115,77 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
|||||||
{
|
{
|
||||||
TextureView destinationView = (TextureView)destination;
|
TextureView destinationView = (TextureView)destination;
|
||||||
|
|
||||||
_renderer.TextureCopy.CopyUnscaled(this, destinationView, 0, firstLayer, 0, firstLevel);
|
if (destinationView.Target.IsMultisample() || Target.IsMultisample())
|
||||||
|
{
|
||||||
|
Extents2D srcRegion = new Extents2D(0, 0, Width, Height);
|
||||||
|
Extents2D dstRegion = new Extents2D(0, 0, destinationView.Width, destinationView.Height);
|
||||||
|
|
||||||
|
TextureView intermmediate = _renderer.TextureCopy.IntermmediatePool.GetOrCreateWithAtLeast(
|
||||||
|
GetIntermmediateTarget(Target),
|
||||||
|
Info.BlockWidth,
|
||||||
|
Info.BlockHeight,
|
||||||
|
Info.BytesPerPixel,
|
||||||
|
Format,
|
||||||
|
Width,
|
||||||
|
Height,
|
||||||
|
Info.Depth,
|
||||||
|
Info.Levels);
|
||||||
|
|
||||||
|
GL.Disable(EnableCap.FramebufferSrgb);
|
||||||
|
|
||||||
|
_renderer.TextureCopy.Copy(this, intermmediate, srcRegion, srcRegion, true);
|
||||||
|
_renderer.TextureCopy.Copy(intermmediate, destinationView, srcRegion, dstRegion, true, 0, firstLayer, 0, firstLevel);
|
||||||
|
|
||||||
|
GL.Enable(EnableCap.FramebufferSrgb);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_renderer.TextureCopy.CopyUnscaled(this, destinationView, 0, firstLayer, 0, firstLevel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CopyTo(ITexture destination, int srcLayer, int dstLayer, int srcLevel, int dstLevel)
|
public void CopyTo(ITexture destination, int srcLayer, int dstLayer, int srcLevel, int dstLevel)
|
||||||
{
|
{
|
||||||
TextureView destinationView = (TextureView)destination;
|
TextureView destinationView = (TextureView)destination;
|
||||||
|
|
||||||
_renderer.TextureCopy.CopyUnscaled(this, destinationView, srcLayer, dstLayer, srcLevel, dstLevel, 1, 1);
|
if (destinationView.Target.IsMultisample() || Target.IsMultisample())
|
||||||
|
{
|
||||||
|
Extents2D srcRegion = new Extents2D(0, 0, Width, Height);
|
||||||
|
Extents2D dstRegion = new Extents2D(0, 0, destinationView.Width, destinationView.Height);
|
||||||
|
|
||||||
|
TextureView intermmediate = _renderer.TextureCopy.IntermmediatePool.GetOrCreateWithAtLeast(
|
||||||
|
GetIntermmediateTarget(Target),
|
||||||
|
Info.BlockWidth,
|
||||||
|
Info.BlockHeight,
|
||||||
|
Info.BytesPerPixel,
|
||||||
|
Format,
|
||||||
|
Math.Max(1, Width >> srcLevel),
|
||||||
|
Math.Max(1, Height >> srcLevel),
|
||||||
|
1,
|
||||||
|
1);
|
||||||
|
|
||||||
|
GL.Disable(EnableCap.FramebufferSrgb);
|
||||||
|
|
||||||
|
_renderer.TextureCopy.Copy(this, intermmediate, srcRegion, srcRegion, true, srcLayer, 0, srcLevel, 0, 1, 1);
|
||||||
|
_renderer.TextureCopy.Copy(intermmediate, destinationView, srcRegion, dstRegion, true, 0, dstLayer, 0, dstLevel, 1, 1);
|
||||||
|
|
||||||
|
GL.Enable(EnableCap.FramebufferSrgb);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_renderer.TextureCopy.CopyUnscaled(this, destinationView, srcLayer, dstLayer, srcLevel, dstLevel, 1, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Target GetIntermmediateTarget(Target srcTarget)
|
||||||
|
{
|
||||||
|
return srcTarget switch
|
||||||
|
{
|
||||||
|
Target.Texture2D => Target.Texture2DMultisample,
|
||||||
|
Target.Texture2DArray => Target.Texture2DMultisampleArray,
|
||||||
|
Target.Texture2DMultisampleArray => Target.Texture2DArray,
|
||||||
|
_ => Target.Texture2D
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CopyTo(ITexture destination, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter)
|
public void CopyTo(ITexture destination, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter)
|
||||||
|
@@ -429,8 +429,6 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
|||||||
Channel.PushHostCommandBuffer(CreateWaitCommandBuffer(header.Fence));
|
Channel.PushHostCommandBuffer(CreateWaitCommandBuffer(header.Fence));
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel.PushEntries(entries);
|
|
||||||
|
|
||||||
header.Fence.Id = _channelSyncpoint.Id;
|
header.Fence.Id = _channelSyncpoint.Id;
|
||||||
|
|
||||||
if (header.Flags.HasFlag(SubmitGpfifoFlags.FenceIncrement) || header.Flags.HasFlag(SubmitGpfifoFlags.IncrementWithValue))
|
if (header.Flags.HasFlag(SubmitGpfifoFlags.FenceIncrement) || header.Flags.HasFlag(SubmitGpfifoFlags.IncrementWithValue))
|
||||||
@@ -449,6 +447,8 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
|
|||||||
header.Fence.Value = _device.System.HostSyncpoint.ReadSyncpointMaxValue(header.Fence.Id);
|
header.Fence.Value = _device.System.HostSyncpoint.ReadSyncpointMaxValue(header.Fence.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Channel.PushEntries(entries);
|
||||||
|
|
||||||
if (header.Flags.HasFlag(SubmitGpfifoFlags.FenceIncrement))
|
if (header.Flags.HasFlag(SubmitGpfifoFlags.FenceIncrement))
|
||||||
{
|
{
|
||||||
Channel.PushHostCommandBuffer(CreateIncrementCommandBuffer(ref header.Fence, header.Flags));
|
Channel.PushHostCommandBuffer(CreateIncrementCommandBuffer(ref header.Fence, header.Flags));
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<RuntimeIdentifiers>win-x64;osx-x64;linux-x64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win10-x64;osx-x64;linux-x64</RuntimeIdentifiers>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<Version>1.0.0-dirty</Version>
|
<Version>1.0.0-dirty</Version>
|
||||||
|
@@ -19,6 +19,8 @@ namespace Ryujinx.Memory
|
|||||||
private ConcurrentDictionary<MemoryBlock, byte> _viewStorages;
|
private ConcurrentDictionary<MemoryBlock, byte> _viewStorages;
|
||||||
private int _viewCount;
|
private int _viewCount;
|
||||||
|
|
||||||
|
internal bool ForceWindows4KBView => _forceWindows4KBView;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Pointer to the memory block data.
|
/// Pointer to the memory block data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -145,7 +147,7 @@ namespace Ryujinx.Memory
|
|||||||
srcBlock.IncrementViewCount();
|
srcBlock.IncrementViewCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryManagement.MapView(srcBlock._sharedMemory, srcOffset, GetPointerInternal(dstOffset, size), size, _forceWindows4KBView);
|
MemoryManagement.MapView(srcBlock._sharedMemory, srcOffset, GetPointerInternal(dstOffset, size), size, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -156,7 +158,7 @@ namespace Ryujinx.Memory
|
|||||||
/// <param name="size">Size of the range to be unmapped</param>
|
/// <param name="size">Size of the range to be unmapped</param>
|
||||||
public void UnmapView(MemoryBlock srcBlock, ulong offset, ulong size)
|
public void UnmapView(MemoryBlock srcBlock, ulong offset, ulong size)
|
||||||
{
|
{
|
||||||
MemoryManagement.UnmapView(srcBlock._sharedMemory, GetPointerInternal(offset, size), size, _forceWindows4KBView);
|
MemoryManagement.UnmapView(srcBlock._sharedMemory, GetPointerInternal(offset, size), size, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -68,17 +68,17 @@ namespace Ryujinx.Memory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void MapView(IntPtr sharedMemory, ulong srcOffset, IntPtr address, ulong size, bool force4KBMap)
|
public static void MapView(IntPtr sharedMemory, ulong srcOffset, IntPtr address, ulong size, MemoryBlock owner)
|
||||||
{
|
{
|
||||||
if (OperatingSystem.IsWindows())
|
if (OperatingSystem.IsWindows())
|
||||||
{
|
{
|
||||||
if (force4KBMap)
|
if (owner.ForceWindows4KBView)
|
||||||
{
|
{
|
||||||
MemoryManagementWindows.MapView4KB(sharedMemory, srcOffset, address, (IntPtr)size);
|
MemoryManagementWindows.MapView4KB(sharedMemory, srcOffset, address, (IntPtr)size);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MemoryManagementWindows.MapView(sharedMemory, srcOffset, address, (IntPtr)size);
|
MemoryManagementWindows.MapView(sharedMemory, srcOffset, address, (IntPtr)size, owner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
|
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
|
||||||
@@ -91,17 +91,17 @@ namespace Ryujinx.Memory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void UnmapView(IntPtr sharedMemory, IntPtr address, ulong size, bool force4KBMap)
|
public static void UnmapView(IntPtr sharedMemory, IntPtr address, ulong size, MemoryBlock owner)
|
||||||
{
|
{
|
||||||
if (OperatingSystem.IsWindows())
|
if (OperatingSystem.IsWindows())
|
||||||
{
|
{
|
||||||
if (force4KBMap)
|
if (owner.ForceWindows4KBView)
|
||||||
{
|
{
|
||||||
MemoryManagementWindows.UnmapView4KB(address, (IntPtr)size);
|
MemoryManagementWindows.UnmapView4KB(address, (IntPtr)size);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MemoryManagementWindows.UnmapView(sharedMemory, address, (IntPtr)size);
|
MemoryManagementWindows.UnmapView(sharedMemory, address, (IntPtr)size, owner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
|
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
|
||||||
|
@@ -68,9 +68,9 @@ namespace Ryujinx.Memory
|
|||||||
return WindowsApi.VirtualFree(location, size, AllocationType.Decommit);
|
return WindowsApi.VirtualFree(location, size, AllocationType.Decommit);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void MapView(IntPtr sharedMemory, ulong srcOffset, IntPtr location, IntPtr size)
|
public static void MapView(IntPtr sharedMemory, ulong srcOffset, IntPtr location, IntPtr size, MemoryBlock owner)
|
||||||
{
|
{
|
||||||
_placeholders.MapView(sharedMemory, srcOffset, location, size);
|
_placeholders.MapView(sharedMemory, srcOffset, location, size, owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void MapView4KB(IntPtr sharedMemory, ulong srcOffset, IntPtr location, IntPtr size)
|
public static void MapView4KB(IntPtr sharedMemory, ulong srcOffset, IntPtr location, IntPtr size)
|
||||||
@@ -106,9 +106,9 @@ namespace Ryujinx.Memory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void UnmapView(IntPtr sharedMemory, IntPtr location, IntPtr size)
|
public static void UnmapView(IntPtr sharedMemory, IntPtr location, IntPtr size, MemoryBlock owner)
|
||||||
{
|
{
|
||||||
_placeholders.UnmapView(sharedMemory, location, size);
|
_placeholders.UnmapView(sharedMemory, location, size, owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void UnmapView4KB(IntPtr location, IntPtr size)
|
public static void UnmapView4KB(IntPtr location, IntPtr size)
|
||||||
@@ -154,7 +154,7 @@ namespace Ryujinx.Memory
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_placeholders.UnmapView(IntPtr.Zero, address, size);
|
_placeholders.UnreserveRange((ulong)address, (ulong)size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return WindowsApi.VirtualFree(address, IntPtr.Zero, AllocationType.Release);
|
return WindowsApi.VirtualFree(address, IntPtr.Zero, AllocationType.Release);
|
||||||
|
@@ -44,6 +44,50 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unreserves a range of memory that has been previously reserved with <see cref="ReserveRange"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="address">Start address of the region to unreserve</param>
|
||||||
|
/// <param name="size">Size in bytes of the region to unreserve</param>
|
||||||
|
/// <exception cref="WindowsApiException">Thrown when the Windows API returns an error unreserving the memory</exception>
|
||||||
|
public void UnreserveRange(ulong address, ulong size)
|
||||||
|
{
|
||||||
|
ulong endAddress = address + size;
|
||||||
|
|
||||||
|
var overlaps = Array.Empty<IntervalTreeNode<ulong, ulong>>();
|
||||||
|
int count;
|
||||||
|
|
||||||
|
lock (_mappings)
|
||||||
|
{
|
||||||
|
count = _mappings.Get(address, endAddress, ref overlaps);
|
||||||
|
|
||||||
|
for (int index = 0; index < count; index++)
|
||||||
|
{
|
||||||
|
var overlap = overlaps[index];
|
||||||
|
|
||||||
|
if (IsMapped(overlap.Value))
|
||||||
|
{
|
||||||
|
if (!WindowsApi.UnmapViewOfFile2(WindowsApi.CurrentProcessHandle, (IntPtr)overlap.Start, 2))
|
||||||
|
{
|
||||||
|
throw new WindowsApiException("UnmapViewOfFile2");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_mappings.Remove(overlap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 1)
|
||||||
|
{
|
||||||
|
CheckFreeResult(WindowsApi.VirtualFree(
|
||||||
|
(IntPtr)address,
|
||||||
|
(IntPtr)size,
|
||||||
|
AllocationType.Release | AllocationType.CoalescePlaceholders));
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveProtection(address, size);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maps a shared memory view on a previously reserved memory region.
|
/// Maps a shared memory view on a previously reserved memory region.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -51,13 +95,14 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
/// <param name="srcOffset">Offset in the shared memory to map</param>
|
/// <param name="srcOffset">Offset in the shared memory to map</param>
|
||||||
/// <param name="location">Address to map the view into</param>
|
/// <param name="location">Address to map the view into</param>
|
||||||
/// <param name="size">Size of the view in bytes</param>
|
/// <param name="size">Size of the view in bytes</param>
|
||||||
public void MapView(IntPtr sharedMemory, ulong srcOffset, IntPtr location, IntPtr size)
|
/// <param name="owner">Memory block that owns the mapping</param>
|
||||||
|
public void MapView(IntPtr sharedMemory, ulong srcOffset, IntPtr location, IntPtr size, MemoryBlock owner)
|
||||||
{
|
{
|
||||||
_partialUnmapLock.AcquireReaderLock(Timeout.Infinite);
|
_partialUnmapLock.AcquireReaderLock(Timeout.Infinite);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
UnmapViewInternal(sharedMemory, location, size);
|
UnmapViewInternal(sharedMemory, location, size, owner);
|
||||||
MapViewInternal(sharedMemory, srcOffset, location, size);
|
MapViewInternal(sharedMemory, srcOffset, location, size);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@@ -173,13 +218,14 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
/// <param name="sharedMemory">Shared memory that the view being unmapped belongs to</param>
|
/// <param name="sharedMemory">Shared memory that the view being unmapped belongs to</param>
|
||||||
/// <param name="location">Address to unmap</param>
|
/// <param name="location">Address to unmap</param>
|
||||||
/// <param name="size">Size of the region to unmap in bytes</param>
|
/// <param name="size">Size of the region to unmap in bytes</param>
|
||||||
public void UnmapView(IntPtr sharedMemory, IntPtr location, IntPtr size)
|
/// <param name="owner">Memory block that owns the mapping</param>
|
||||||
|
public void UnmapView(IntPtr sharedMemory, IntPtr location, IntPtr size, MemoryBlock owner)
|
||||||
{
|
{
|
||||||
_partialUnmapLock.AcquireReaderLock(Timeout.Infinite);
|
_partialUnmapLock.AcquireReaderLock(Timeout.Infinite);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
UnmapViewInternal(sharedMemory, location, size);
|
UnmapViewInternal(sharedMemory, location, size, owner);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -197,8 +243,9 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
/// <param name="sharedMemory">Shared memory that the view being unmapped belongs to</param>
|
/// <param name="sharedMemory">Shared memory that the view being unmapped belongs to</param>
|
||||||
/// <param name="location">Address to unmap</param>
|
/// <param name="location">Address to unmap</param>
|
||||||
/// <param name="size">Size of the region to unmap in bytes</param>
|
/// <param name="size">Size of the region to unmap in bytes</param>
|
||||||
|
/// <param name="owner">Memory block that owns the mapping</param>
|
||||||
/// <exception cref="WindowsApiException">Thrown when the Windows API returns an error unmapping or remapping the memory</exception>
|
/// <exception cref="WindowsApiException">Thrown when the Windows API returns an error unmapping or remapping the memory</exception>
|
||||||
private void UnmapViewInternal(IntPtr sharedMemory, IntPtr location, IntPtr size)
|
private void UnmapViewInternal(IntPtr sharedMemory, IntPtr location, IntPtr size, MemoryBlock owner)
|
||||||
{
|
{
|
||||||
ulong startAddress = (ulong)location;
|
ulong startAddress = (ulong)location;
|
||||||
ulong unmapSize = (ulong)size;
|
ulong unmapSize = (ulong)size;
|
||||||
@@ -272,7 +319,7 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CoalesceForUnmap(startAddress, unmapSize);
|
CoalesceForUnmap(startAddress, unmapSize, owner);
|
||||||
RemoveProtection(startAddress, unmapSize);
|
RemoveProtection(startAddress, unmapSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,15 +328,21 @@ namespace Ryujinx.Memory.WindowsShared
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="address">Address of the region that was unmapped</param>
|
/// <param name="address">Address of the region that was unmapped</param>
|
||||||
/// <param name="size">Size of the region that was unmapped in bytes</param>
|
/// <param name="size">Size of the region that was unmapped in bytes</param>
|
||||||
private void CoalesceForUnmap(ulong address, ulong size)
|
/// <param name="owner">Memory block that owns the mapping</param>
|
||||||
|
private void CoalesceForUnmap(ulong address, ulong size, MemoryBlock owner)
|
||||||
{
|
{
|
||||||
ulong endAddress = address + size;
|
ulong endAddress = address + size;
|
||||||
|
ulong blockAddress = (ulong)owner.Pointer;
|
||||||
|
ulong blockEnd = blockAddress + owner.Size;
|
||||||
var overlaps = Array.Empty<IntervalTreeNode<ulong, ulong>>();
|
var overlaps = Array.Empty<IntervalTreeNode<ulong, ulong>>();
|
||||||
int unmappedCount = 0;
|
int unmappedCount = 0;
|
||||||
|
|
||||||
lock (_mappings)
|
lock (_mappings)
|
||||||
{
|
{
|
||||||
int count = _mappings.Get(address - MinimumPageSize, endAddress + MinimumPageSize, ref overlaps);
|
int count = _mappings.Get(
|
||||||
|
Math.Max(address - MinimumPageSize, blockAddress),
|
||||||
|
Math.Min(endAddress + MinimumPageSize, blockEnd), ref overlaps);
|
||||||
|
|
||||||
if (count < 2)
|
if (count < 2)
|
||||||
{
|
{
|
||||||
// Nothing to coalesce if we only have 1 or no overlaps.
|
// Nothing to coalesce if we only have 1 or no overlaps.
|
||||||
|
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<RuntimeIdentifiers>win-x64;osx-x64;linux-x64</RuntimeIdentifiers>
|
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<Configurations>Debug;Release</Configurations>
|
<Configurations>Debug;Release</Configurations>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<RuntimeIdentifiers>win-x64;osx-x64;linux-x64</RuntimeIdentifiers>
|
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
|
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<RuntimeIdentifiers>win-x64;osx-x64;linux-x64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win10-x64;osx-x64;linux-x64</RuntimeIdentifiers>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<Version>1.0.0-dirty</Version>
|
<Version>1.0.0-dirty</Version>
|
||||||
|
Reference in New Issue
Block a user