Compare commits

...

12 Commits

Author SHA1 Message Date
TSRBerry a3bef38416
Merge 4b79de6427 into 73f985d27c 2024-09-19 07:45:31 -04:00
jhorv 73f985d27c
Replace passing by IMemoryOwner<byte> with passing by concrete MemoryOwner<byte> (#7171)
* refactor(perf): pass MemoryOwner<byte> around as itself rather than IMemoryOwner<byte>

* fix(perf): get span via MemoryOwner<byte>.Span property instead of through Memory property

* fix: incorrect comment change
2024-09-18 23:00:54 -03:00
TSR Berry 4b79de6427
Update RyuSocks to v0.5.0-alpha 2024-09-06 00:44:47 +02:00
TSR Berry f88c612273
Pass SocksClientStream to SslStream constructor for ManagedProxySocket
This doesn't seem to work as expected yet.
2024-08-28 22:34:04 +02:00
TSR Berry eaf23843d4
Update RyuSocks to v0.4.0-alpha 2024-08-28 22:28:12 +02:00
TSR Berry f14df5cbb8
Add ManagedProxySocketPollManager impl 2024-08-14 03:55:00 +02:00
TSR Berry fe0c34c639
Update RyuSocks to v0.3.1-alpha 2024-08-14 03:54:59 +02:00
TSR Berry ac67adae86
[WIP] Add ManagedProxySocket implementation 2024-08-14 03:54:59 +02:00
TSR Berry c89a1b2d46
Move ConvertBsdSocketFlags() to WinSockHelper 2024-08-14 03:54:59 +02:00
TSR Berry 49acca8cf7
Add ProxyManager 2024-08-14 03:54:59 +02:00
TSR Berry aea32c29aa
Add RyuSocks NuGet package 2024-08-14 03:54:59 +02:00
TSR Berry 282892634e
sockets: Rename Refcount to RefCount 2024-08-14 03:54:59 +02:00
26 changed files with 894 additions and 143 deletions

View File

@ -36,6 +36,7 @@
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" /> <PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
<PackageVersion Include="Ryujinx.GtkSharp" Version="3.24.24.59-ryujinx" /> <PackageVersion Include="Ryujinx.GtkSharp" Version="3.24.24.59-ryujinx" />
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.30.0-build32" /> <PackageVersion Include="Ryujinx.SDL2-CS" Version="2.30.0-build32" />
<PackageVersion Include="RyuSocks" Version="0.5.0-alpha" />
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" /> <PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
<PackageVersion Include="shaderc.net" Version="0.1.0" /> <PackageVersion Include="shaderc.net" Version="0.1.0" />
<PackageVersion Include="SharpZipLib" Version="1.4.2" /> <PackageVersion Include="SharpZipLib" Version="1.4.2" />
@ -49,4 +50,4 @@
<PackageVersion Include="System.Management" Version="8.0.0" /> <PackageVersion Include="System.Management" Version="8.0.0" />
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" /> <PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,4 +1,4 @@
using System.Buffers; using Ryujinx.Common.Memory;
namespace Ryujinx.Graphics.GAL namespace Ryujinx.Graphics.GAL
{ {
@ -18,30 +18,30 @@ namespace Ryujinx.Graphics.GAL
PinnedSpan<byte> GetData(int layer, int level); PinnedSpan<byte> GetData(int layer, int level);
/// <summary> /// <summary>
/// Sets the texture data. The data passed as a <see cref="IMemoryOwner{Byte}" /> will be disposed when /// Sets the texture data. The data passed as a <see cref="MemoryOwner{Byte}" /> will be disposed when
/// the operation completes. /// the operation completes.
/// </summary> /// </summary>
/// <param name="data">Texture data bytes</param> /// <param name="data">Texture data bytes</param>
void SetData(IMemoryOwner<byte> data); void SetData(MemoryOwner<byte> data);
/// <summary> /// <summary>
/// Sets the texture data. The data passed as a <see cref="IMemoryOwner{Byte}" /> will be disposed when /// Sets the texture data. The data passed as a <see cref="MemoryOwner{Byte}" /> will be disposed when
/// the operation completes. /// the operation completes.
/// </summary> /// </summary>
/// <param name="data">Texture data bytes</param> /// <param name="data">Texture data bytes</param>
/// <param name="layer">Target layer</param> /// <param name="layer">Target layer</param>
/// <param name="level">Target level</param> /// <param name="level">Target level</param>
void SetData(IMemoryOwner<byte> data, int layer, int level); void SetData(MemoryOwner<byte> data, int layer, int level);
/// <summary> /// <summary>
/// Sets the texture data. The data passed as a <see cref="IMemoryOwner{Byte}" /> will be disposed when /// Sets the texture data. The data passed as a <see cref="MemoryOwner{Byte}" /> will be disposed when
/// the operation completes. /// the operation completes.
/// </summary> /// </summary>
/// <param name="data">Texture data bytes</param> /// <param name="data">Texture data bytes</param>
/// <param name="layer">Target layer</param> /// <param name="layer">Target layer</param>
/// <param name="level">Target level</param> /// <param name="level">Target level</param>
/// <param name="region">Target sub-region of the texture to update</param> /// <param name="region">Target sub-region of the texture to update</param>
void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region); void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region);
void SetStorage(BufferRange buffer); void SetStorage(BufferRange buffer);

View File

@ -1,6 +1,6 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL.Multithreading.Model; using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources; using Ryujinx.Graphics.GAL.Multithreading.Resources;
using System.Buffers;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{ {
@ -8,9 +8,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{ {
public readonly CommandType CommandType => CommandType.TextureSetData; public readonly CommandType CommandType => CommandType.TextureSetData;
private TableRef<ThreadedTexture> _texture; private TableRef<ThreadedTexture> _texture;
private TableRef<IMemoryOwner<byte>> _data; private TableRef<MemoryOwner<byte>> _data;
public void Set(TableRef<ThreadedTexture> texture, TableRef<IMemoryOwner<byte>> data) public void Set(TableRef<ThreadedTexture> texture, TableRef<MemoryOwner<byte>> data)
{ {
_texture = texture; _texture = texture;
_data = data; _data = data;

View File

@ -1,6 +1,6 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL.Multithreading.Model; using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources; using Ryujinx.Graphics.GAL.Multithreading.Resources;
using System.Buffers;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{ {
@ -8,11 +8,11 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{ {
public readonly CommandType CommandType => CommandType.TextureSetDataSlice; public readonly CommandType CommandType => CommandType.TextureSetDataSlice;
private TableRef<ThreadedTexture> _texture; private TableRef<ThreadedTexture> _texture;
private TableRef<IMemoryOwner<byte>> _data; private TableRef<MemoryOwner<byte>> _data;
private int _layer; private int _layer;
private int _level; private int _level;
public void Set(TableRef<ThreadedTexture> texture, TableRef<IMemoryOwner<byte>> data, int layer, int level) public void Set(TableRef<ThreadedTexture> texture, TableRef<MemoryOwner<byte>> data, int layer, int level)
{ {
_texture = texture; _texture = texture;
_data = data; _data = data;

View File

@ -1,6 +1,6 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL.Multithreading.Model; using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources; using Ryujinx.Graphics.GAL.Multithreading.Resources;
using System.Buffers;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{ {
@ -8,12 +8,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{ {
public readonly CommandType CommandType => CommandType.TextureSetDataSliceRegion; public readonly CommandType CommandType => CommandType.TextureSetDataSliceRegion;
private TableRef<ThreadedTexture> _texture; private TableRef<ThreadedTexture> _texture;
private TableRef<IMemoryOwner<byte>> _data; private TableRef<MemoryOwner<byte>> _data;
private int _layer; private int _layer;
private int _level; private int _level;
private Rectangle<int> _region; private Rectangle<int> _region;
public void Set(TableRef<ThreadedTexture> texture, TableRef<IMemoryOwner<byte>> data, int layer, int level, Rectangle<int> region) public void Set(TableRef<ThreadedTexture> texture, TableRef<MemoryOwner<byte>> data, int layer, int level, Rectangle<int> region)
{ {
_texture = texture; _texture = texture;
_data = data; _data = data;

View File

@ -1,6 +1,6 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL.Multithreading.Commands.Texture; using Ryujinx.Graphics.GAL.Multithreading.Commands.Texture;
using Ryujinx.Graphics.GAL.Multithreading.Model; using Ryujinx.Graphics.GAL.Multithreading.Model;
using System.Buffers;
namespace Ryujinx.Graphics.GAL.Multithreading.Resources namespace Ryujinx.Graphics.GAL.Multithreading.Resources
{ {
@ -111,21 +111,21 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data) public void SetData(MemoryOwner<byte> data)
{ {
_renderer.New<TextureSetDataCommand>().Set(Ref(this), Ref(data)); _renderer.New<TextureSetDataCommand>().Set(Ref(this), Ref(data));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data, int layer, int level) public void SetData(MemoryOwner<byte> data, int layer, int level)
{ {
_renderer.New<TextureSetDataSliceCommand>().Set(Ref(this), Ref(data), layer, level); _renderer.New<TextureSetDataSliceCommand>().Set(Ref(this), Ref(data), layer, level);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region) public void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{ {
_renderer.New<TextureSetDataSliceRegionCommand>().Set(Ref(this), Ref(data), layer, level, region); _renderer.New<TextureSetDataSliceRegionCommand>().Set(Ref(this), Ref(data), layer, level, region);
_renderer.QueueCommand(); _renderer.QueueCommand();

View File

@ -1,10 +1,10 @@
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.Device; using Ryujinx.Graphics.Device;
using Ryujinx.Graphics.Gpu.Engine.Threed; using Ryujinx.Graphics.Gpu.Engine.Threed;
using Ryujinx.Graphics.Gpu.Memory; using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Texture; using Ryujinx.Graphics.Texture;
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -353,7 +353,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
if (target != null) if (target != null)
{ {
IMemoryOwner<byte> data; MemoryOwner<byte> data;
if (srcLinear) if (srcLinear)
{ {
data = LayoutConverter.ConvertLinearStridedToLinear( data = LayoutConverter.ConvertLinearStridedToLinear(

View File

@ -7,7 +7,6 @@ using Ryujinx.Graphics.Texture.Astc;
using Ryujinx.Memory; using Ryujinx.Memory;
using Ryujinx.Memory.Range; using Ryujinx.Memory.Range;
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
@ -662,7 +661,7 @@ namespace Ryujinx.Graphics.Gpu.Image
} }
} }
IMemoryOwner<byte> result = ConvertToHostCompatibleFormat(data); MemoryOwner<byte> result = ConvertToHostCompatibleFormat(data);
if (ScaleFactor != 1f && AllowScaledSetData()) if (ScaleFactor != 1f && AllowScaledSetData())
{ {
@ -685,7 +684,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Uploads new texture data to the host GPU. /// Uploads new texture data to the host GPU.
/// </summary> /// </summary>
/// <param name="data">New data</param> /// <param name="data">New data</param>
public void SetData(IMemoryOwner<byte> data) public void SetData(MemoryOwner<byte> data)
{ {
BlacklistScale(); BlacklistScale();
@ -704,7 +703,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="data">New data</param> /// <param name="data">New data</param>
/// <param name="layer">Target layer</param> /// <param name="layer">Target layer</param>
/// <param name="level">Target level</param> /// <param name="level">Target level</param>
public void SetData(IMemoryOwner<byte> data, int layer, int level) public void SetData(MemoryOwner<byte> data, int layer, int level)
{ {
BlacklistScale(); BlacklistScale();
@ -722,7 +721,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="layer">Target layer</param> /// <param name="layer">Target layer</param>
/// <param name="level">Target level</param> /// <param name="level">Target level</param>
/// <param name="region">Target sub-region of the texture to update</param> /// <param name="region">Target sub-region of the texture to update</param>
public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region) public void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{ {
BlacklistScale(); BlacklistScale();
@ -740,7 +739,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="level">Mip level to convert</param> /// <param name="level">Mip level to convert</param>
/// <param name="single">True to convert a single slice</param> /// <param name="single">True to convert a single slice</param>
/// <returns>Converted data</returns> /// <returns>Converted data</returns>
public IMemoryOwner<byte> ConvertToHostCompatibleFormat(ReadOnlySpan<byte> data, int level = 0, bool single = false) public MemoryOwner<byte> ConvertToHostCompatibleFormat(ReadOnlySpan<byte> data, int level = 0, bool single = false)
{ {
int width = Info.Width; int width = Info.Width;
int height = Info.Height; int height = Info.Height;
@ -755,7 +754,7 @@ namespace Ryujinx.Graphics.Gpu.Image
int sliceDepth = single ? 1 : depth; int sliceDepth = single ? 1 : depth;
IMemoryOwner<byte> linear; MemoryOwner<byte> linear;
if (Info.IsLinear) if (Info.IsLinear)
{ {
@ -788,7 +787,7 @@ namespace Ryujinx.Graphics.Gpu.Image
data); data);
} }
IMemoryOwner<byte> result = linear; MemoryOwner<byte> result = linear;
// Handle compressed cases not supported by the host: // Handle compressed cases not supported by the host:
// - ASTC is usually not supported on desktop cards. // - ASTC is usually not supported on desktop cards.
@ -832,19 +831,19 @@ namespace Ryujinx.Graphics.Gpu.Image
case Format.Etc2RgbaUnorm: case Format.Etc2RgbaUnorm:
using (result) using (result)
{ {
return ETC2Decoder.DecodeRgba(result.Memory.Span, width, height, sliceDepth, levels, layers); return ETC2Decoder.DecodeRgba(result.Span, width, height, sliceDepth, levels, layers);
} }
case Format.Etc2RgbPtaSrgb: case Format.Etc2RgbPtaSrgb:
case Format.Etc2RgbPtaUnorm: case Format.Etc2RgbPtaUnorm:
using (result) using (result)
{ {
return ETC2Decoder.DecodePta(result.Memory.Span, width, height, sliceDepth, levels, layers); return ETC2Decoder.DecodePta(result.Span, width, height, sliceDepth, levels, layers);
} }
case Format.Etc2RgbSrgb: case Format.Etc2RgbSrgb:
case Format.Etc2RgbUnorm: case Format.Etc2RgbUnorm:
using (result) using (result)
{ {
return ETC2Decoder.DecodeRgb(result.Memory.Span, width, height, sliceDepth, levels, layers); return ETC2Decoder.DecodeRgb(result.Span, width, height, sliceDepth, levels, layers);
} }
} }
} }
@ -856,43 +855,43 @@ namespace Ryujinx.Graphics.Gpu.Image
case Format.Bc1RgbaUnorm: case Format.Bc1RgbaUnorm:
using (result) using (result)
{ {
return BCnDecoder.DecodeBC1(result.Memory.Span, width, height, sliceDepth, levels, layers); return BCnDecoder.DecodeBC1(result.Span, width, height, sliceDepth, levels, layers);
} }
case Format.Bc2Srgb: case Format.Bc2Srgb:
case Format.Bc2Unorm: case Format.Bc2Unorm:
using (result) using (result)
{ {
return BCnDecoder.DecodeBC2(result.Memory.Span, width, height, sliceDepth, levels, layers); return BCnDecoder.DecodeBC2(result.Span, width, height, sliceDepth, levels, layers);
} }
case Format.Bc3Srgb: case Format.Bc3Srgb:
case Format.Bc3Unorm: case Format.Bc3Unorm:
using (result) using (result)
{ {
return BCnDecoder.DecodeBC3(result.Memory.Span, width, height, sliceDepth, levels, layers); return BCnDecoder.DecodeBC3(result.Span, width, height, sliceDepth, levels, layers);
} }
case Format.Bc4Snorm: case Format.Bc4Snorm:
case Format.Bc4Unorm: case Format.Bc4Unorm:
using (result) using (result)
{ {
return BCnDecoder.DecodeBC4(result.Memory.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc4Snorm); return BCnDecoder.DecodeBC4(result.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc4Snorm);
} }
case Format.Bc5Snorm: case Format.Bc5Snorm:
case Format.Bc5Unorm: case Format.Bc5Unorm:
using (result) using (result)
{ {
return BCnDecoder.DecodeBC5(result.Memory.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc5Snorm); return BCnDecoder.DecodeBC5(result.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc5Snorm);
} }
case Format.Bc6HSfloat: case Format.Bc6HSfloat:
case Format.Bc6HUfloat: case Format.Bc6HUfloat:
using (result) using (result)
{ {
return BCnDecoder.DecodeBC6(result.Memory.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc6HSfloat); return BCnDecoder.DecodeBC6(result.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc6HSfloat);
} }
case Format.Bc7Srgb: case Format.Bc7Srgb:
case Format.Bc7Unorm: case Format.Bc7Unorm:
using (result) using (result)
{ {
return BCnDecoder.DecodeBC7(result.Memory.Span, width, height, sliceDepth, levels, layers); return BCnDecoder.DecodeBC7(result.Span, width, height, sliceDepth, levels, layers);
} }
} }
} }
@ -900,7 +899,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
using (result) using (result)
{ {
var converted = PixelConverter.ConvertR4G4ToR4G4B4A4(result.Memory.Span, width); var converted = PixelConverter.ConvertR4G4ToR4G4B4A4(result.Span, width);
if (_context.Capabilities.SupportsR4G4B4A4Format) if (_context.Capabilities.SupportsR4G4B4A4Format)
{ {
@ -910,7 +909,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
using (converted) using (converted)
{ {
return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(converted.Memory.Span, width); return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(converted.Span, width);
} }
} }
} }
@ -921,7 +920,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
using (result) using (result)
{ {
return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result.Memory.Span, width); return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result.Span, width);
} }
} }
} }
@ -933,24 +932,24 @@ namespace Ryujinx.Graphics.Gpu.Image
case Format.R5G6B5Unorm: case Format.R5G6B5Unorm:
using (result) using (result)
{ {
return PixelConverter.ConvertR5G6B5ToR8G8B8A8(result.Memory.Span, width); return PixelConverter.ConvertR5G6B5ToR8G8B8A8(result.Span, width);
} }
case Format.B5G5R5A1Unorm: case Format.B5G5R5A1Unorm:
case Format.R5G5B5X1Unorm: case Format.R5G5B5X1Unorm:
case Format.R5G5B5A1Unorm: case Format.R5G5B5A1Unorm:
using (result) using (result)
{ {
return PixelConverter.ConvertR5G5B5ToR8G8B8A8(result.Memory.Span, width, Format == Format.R5G5B5X1Unorm); return PixelConverter.ConvertR5G5B5ToR8G8B8A8(result.Span, width, Format == Format.R5G5B5X1Unorm);
} }
case Format.A1B5G5R5Unorm: case Format.A1B5G5R5Unorm:
using (result) using (result)
{ {
return PixelConverter.ConvertA1B5G5R5ToR8G8B8A8(result.Memory.Span, width); return PixelConverter.ConvertA1B5G5R5ToR8G8B8A8(result.Span, width);
} }
case Format.R4G4B4A4Unorm: case Format.R4G4B4A4Unorm:
using (result) using (result)
{ {
return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result.Memory.Span, width); return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result.Span, width);
} }
} }
} }

View File

@ -1,3 +1,4 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Memory; using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Texture; using Ryujinx.Graphics.Texture;
@ -5,7 +6,6 @@ using Ryujinx.Memory;
using Ryujinx.Memory.Range; using Ryujinx.Memory.Range;
using Ryujinx.Memory.Tracking; using Ryujinx.Memory.Tracking;
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@ -445,7 +445,7 @@ namespace Ryujinx.Graphics.Gpu.Image
ReadOnlySpan<byte> data = dataSpan[(offset - spanBase)..]; ReadOnlySpan<byte> data = dataSpan[(offset - spanBase)..];
IMemoryOwner<byte> result = Storage.ConvertToHostCompatibleFormat(data, info.BaseLevel + level, true); MemoryOwner<byte> result = Storage.ConvertToHostCompatibleFormat(data, info.BaseLevel + level, true);
Storage.SetData(result, info.BaseLayer + layer, info.BaseLevel + level); Storage.SetData(result, info.BaseLayer + layer, info.BaseLevel + level);
} }

View File

@ -1,7 +1,7 @@
using OpenTK.Graphics.OpenGL; using OpenTK.Graphics.OpenGL;
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using System; using System;
using System.Buffers;
namespace Ryujinx.Graphics.OpenGL.Image namespace Ryujinx.Graphics.OpenGL.Image
{ {
@ -55,9 +55,9 @@ namespace Ryujinx.Graphics.OpenGL.Image
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data) public void SetData(MemoryOwner<byte> data)
{ {
var dataSpan = data.Memory.Span; var dataSpan = data.Span;
Buffer.SetData(_buffer, _bufferOffset, dataSpan[..Math.Min(dataSpan.Length, _bufferSize)]); Buffer.SetData(_buffer, _bufferOffset, dataSpan[..Math.Min(dataSpan.Length, _bufferSize)]);
@ -65,13 +65,13 @@ namespace Ryujinx.Graphics.OpenGL.Image
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data, int layer, int level) public void SetData(MemoryOwner<byte> data, int layer, int level)
{ {
throw new NotSupportedException(); throw new NotSupportedException();
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region) public void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{ {
throw new NotSupportedException(); throw new NotSupportedException();
} }

View File

@ -1,8 +1,8 @@
using OpenTK.Graphics.OpenGL; using OpenTK.Graphics.OpenGL;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using System; using System;
using System.Buffers;
using System.Diagnostics; using System.Diagnostics;
namespace Ryujinx.Graphics.OpenGL.Image namespace Ryujinx.Graphics.OpenGL.Image
@ -448,13 +448,13 @@ namespace Ryujinx.Graphics.OpenGL.Image
} }
} }
public void SetData(IMemoryOwner<byte> data) public void SetData(MemoryOwner<byte> data)
{ {
using (data = EnsureDataFormat(data)) using (data = EnsureDataFormat(data))
{ {
unsafe unsafe
{ {
var dataSpan = data.Memory.Span; var dataSpan = data.Span;
fixed (byte* ptr = dataSpan) fixed (byte* ptr = dataSpan)
{ {
ReadFrom((IntPtr)ptr, dataSpan.Length); ReadFrom((IntPtr)ptr, dataSpan.Length);
@ -463,13 +463,13 @@ namespace Ryujinx.Graphics.OpenGL.Image
} }
} }
public void SetData(IMemoryOwner<byte> data, int layer, int level) public void SetData(MemoryOwner<byte> data, int layer, int level)
{ {
using (data = EnsureDataFormat(data)) using (data = EnsureDataFormat(data))
{ {
unsafe unsafe
{ {
fixed (byte* ptr = data.Memory.Span) fixed (byte* ptr = data.Span)
{ {
int width = Math.Max(Info.Width >> level, 1); int width = Math.Max(Info.Width >> level, 1);
int height = Math.Max(Info.Height >> level, 1); int height = Math.Max(Info.Height >> level, 1);
@ -480,7 +480,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
} }
} }
public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region) public void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{ {
using (data = EnsureDataFormat(data)) using (data = EnsureDataFormat(data))
{ {
@ -489,7 +489,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
unsafe unsafe
{ {
fixed (byte* ptr = data.Memory.Span) fixed (byte* ptr = data.Span)
{ {
ReadFrom2D( ReadFrom2D(
(IntPtr)ptr, (IntPtr)ptr,
@ -522,13 +522,13 @@ namespace Ryujinx.Graphics.OpenGL.Image
ReadFrom2D(data, layer, level, x, y, width, height, mipSize); ReadFrom2D(data, layer, level, x, y, width, height, mipSize);
} }
private IMemoryOwner<byte> EnsureDataFormat(IMemoryOwner<byte> data) private MemoryOwner<byte> EnsureDataFormat(MemoryOwner<byte> data)
{ {
if (Format == Format.S8UintD24Unorm) if (Format == Format.S8UintD24Unorm)
{ {
using (data) using (data)
{ {
return FormatConverter.ConvertS8D24ToD24S8(data.Memory.Span); return FormatConverter.ConvertS8D24ToD24S8(data.Span);
} }
} }

View File

@ -1,7 +1,7 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Silk.NET.Vulkan; using Silk.NET.Vulkan;
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using Format = Ryujinx.Graphics.GAL.Format; using Format = Ryujinx.Graphics.GAL.Format;
using VkFormat = Silk.NET.Vulkan.Format; using VkFormat = Silk.NET.Vulkan.Format;
@ -84,20 +84,20 @@ namespace Ryujinx.Graphics.Vulkan
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data) public void SetData(MemoryOwner<byte> data)
{ {
_gd.SetBufferData(_bufferHandle, _offset, data.Memory.Span); _gd.SetBufferData(_bufferHandle, _offset, data.Span);
data.Dispose(); data.Dispose();
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data, int layer, int level) public void SetData(MemoryOwner<byte> data, int layer, int level)
{ {
throw new NotSupportedException(); throw new NotSupportedException();
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region) public void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{ {
throw new NotSupportedException(); throw new NotSupportedException();
} }

View File

@ -1,7 +1,7 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Silk.NET.Vulkan; using Silk.NET.Vulkan;
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
@ -746,23 +746,23 @@ namespace Ryujinx.Graphics.Vulkan
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data) public void SetData(MemoryOwner<byte> data)
{ {
SetData(data.Memory.Span, 0, 0, Info.GetLayers(), Info.Levels, singleSlice: false); SetData(data.Span, 0, 0, Info.GetLayers(), Info.Levels, singleSlice: false);
data.Dispose(); data.Dispose();
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data, int layer, int level) public void SetData(MemoryOwner<byte> data, int layer, int level)
{ {
SetData(data.Memory.Span, layer, level, 1, 1, singleSlice: true); SetData(data.Span, layer, level, 1, 1, singleSlice: true);
data.Dispose(); data.Dispose();
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region) public void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{ {
SetData(data.Memory.Span, layer, level, 1, 1, singleSlice: true, region); SetData(data.Span, layer, level, 1, 1, singleSlice: true, region);
data.Dispose(); data.Dispose();
} }

View File

@ -103,7 +103,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
{ {
lock (_lock) lock (_lock)
{ {
oldFile.Refcount++; oldFile.RefCount++;
return RegisterFileDescriptor(oldFile); return RegisterFileDescriptor(oldFile);
} }
@ -118,9 +118,9 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
if (file != null) if (file != null)
{ {
file.Refcount--; file.RefCount--;
if (file.Refcount <= 0) if (file.RefCount <= 0)
{ {
file.Dispose(); file.Dispose();
} }

View File

@ -1,6 +1,7 @@
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl; using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl;
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Proxy;
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types; using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types;
using Ryujinx.Memory; using Ryujinx.Memory;
using System; using System;
@ -20,6 +21,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
{ {
EventFileDescriptorPollManager.Instance, EventFileDescriptorPollManager.Instance,
ManagedSocketPollManager.Instance, ManagedSocketPollManager.Instance,
ManagedProxySocketPollManager.Instance,
}; };
private BsdContext _context; private BsdContext _context;
@ -95,10 +97,8 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
} }
} }
ISocket newBsdSocket = new ManagedSocket(netDomain, (SocketType)type, protocol) ISocket newBsdSocket = ProxyManager.GetSocket(netDomain, (SocketType)type, protocol);
{ newBsdSocket.Blocking = !creationFlags.HasFlag(BsdSocketCreationFlags.NonBlocking);
Blocking = !creationFlags.HasFlag(BsdSocketCreationFlags.NonBlocking),
};
LinuxError errno = LinuxError.SUCCESS; LinuxError errno = LinuxError.SUCCESS;

View File

@ -6,7 +6,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
interface IFileDescriptor : IDisposable interface IFileDescriptor : IDisposable
{ {
bool Blocking { get; set; } bool Blocking { get; set; }
int Refcount { get; set; } int RefCount { get; set; }
LinuxError Read(out int readSize, Span<byte> buffer); LinuxError Read(out int readSize, Span<byte> buffer);

View File

@ -32,7 +32,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
UpdateEventStates(); UpdateEventStates();
} }
public int Refcount { get; set; } public int RefCount { get; set; }
public void Dispose() public void Dispose()
{ {

View File

@ -0,0 +1,472 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types;
using RyuSocks;
using RyuSocks.Auth;
using RyuSocks.Commands;
using RyuSocks.Types;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
{
class ManagedProxySocket : ISocket
{
private static readonly Dictionary<AuthMethod, IProxyAuth> _authMethods = new()
{
{ AuthMethod.NoAuth, new NoAuth() },
};
private readonly bool _isUdpSocket;
private readonly bool _acceptedConnection;
public SocksClient ProxyClient { get; }
public bool Blocking { get => ProxyClient.Blocking; set => ProxyClient.Blocking = value; }
public int RefCount { get; set; }
public IPEndPoint RemoteEndPoint => (IPEndPoint)ProxyClient.ProxiedRemoteEndPoint;
public IPEndPoint LocalEndPoint => (IPEndPoint)ProxyClient.ProxiedLocalEndPoint;
public AddressFamily AddressFamily => ProxyClient.AddressFamily;
public SocketType SocketType => ProxyClient.SocketType;
public ProtocolType ProtocolType => ProxyClient.ProtocolType;
public IntPtr Handle => throw new NotSupportedException("Can't get the handle of a proxy socket.");
public ManagedProxySocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, EndPoint proxyEndpoint)
{
if (addressFamily != proxyEndpoint.AddressFamily && addressFamily != AddressFamily.Unspecified)
{
throw new ArgumentException(
$"Invalid {nameof(System.Net.Sockets.AddressFamily)}", nameof(addressFamily));
}
if (socketType != SocketType.Stream && socketType != SocketType.Dgram)
{
throw new ArgumentException(
$"Invalid {nameof(System.Net.Sockets.SocketType)}", nameof(socketType));
}
if (protocolType != ProtocolType.Tcp && protocolType != ProtocolType.Udp)
{
throw new ArgumentException(
$"Invalid {nameof(System.Net.Sockets.ProtocolType)}", nameof(protocolType));
}
_isUdpSocket = socketType == SocketType.Dgram && protocolType == ProtocolType.Udp;
ProxyClient = proxyEndpoint switch
{
IPEndPoint ipEndPoint => new SocksClient(ipEndPoint) { OfferedAuthMethods = _authMethods },
DnsEndPoint dnsEndPoint => new SocksClient(dnsEndPoint) { OfferedAuthMethods = _authMethods },
_ => throw new ArgumentException($"Unsupported {nameof(EndPoint)} type", nameof(proxyEndpoint))
};
ProxyClient.Authenticate();
RefCount = 1;
}
private ManagedProxySocket(SocksClient proxyClient)
{
ProxyClient = proxyClient;
_acceptedConnection = true;
RefCount = 1;
}
private static LinuxError ToLinuxError(ReplyField proxyReply)
{
return proxyReply switch
{
ReplyField.Succeeded => LinuxError.SUCCESS,
ReplyField.ServerFailure => LinuxError.ECONNRESET,
ReplyField.ConnectionNotAllowed => LinuxError.ECONNREFUSED,
ReplyField.NetworkUnreachable => LinuxError.ENETUNREACH,
ReplyField.HostUnreachable => LinuxError.EHOSTUNREACH,
ReplyField.ConnectionRefused => LinuxError.ECONNREFUSED,
ReplyField.TTLExpired => LinuxError.EHOSTUNREACH,
ReplyField.CommandNotSupported => LinuxError.EOPNOTSUPP,
ReplyField.AddressTypeNotSupported => LinuxError.EAFNOSUPPORT,
_ => throw new ArgumentOutOfRangeException(nameof(proxyReply))
};
}
public void Dispose()
{
ProxyClient.Dispose();
}
public LinuxError Read(out int readSize, Span<byte> buffer)
{
return Receive(out readSize, buffer, BsdSocketFlags.None);
}
public LinuxError Write(out int writeSize, ReadOnlySpan<byte> buffer)
{
return Send(out writeSize, buffer, BsdSocketFlags.None);
}
public LinuxError Receive(out int receiveSize, Span<byte> buffer, BsdSocketFlags flags)
{
LinuxError result;
bool shouldBlockAfterOperation = false;
if (Blocking && flags.HasFlag(BsdSocketFlags.DontWait))
{
Blocking = false;
shouldBlockAfterOperation = true;
}
byte[] proxyBuffer = new byte[buffer.Length + ProxyClient.GetRequiredWrapperSpace()];
try
{
receiveSize = ProxyClient.Receive(
proxyBuffer,
WinSockHelper.ConvertBsdSocketFlags(flags),
out SocketError errorCode
);
proxyBuffer[..receiveSize].CopyTo(buffer);
result = WinSockHelper.ConvertError((WsaError)errorCode);
}
catch (ProxyException exception)
{
Logger.Error?.Print(
LogClass.ServiceBsd,
$"An error occured while trying to receive data: {exception}"
);
receiveSize = -1;
result = ToLinuxError(exception.ReplyCode);
}
catch (SocketException exception)
{
receiveSize = -1;
result = WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
}
if (shouldBlockAfterOperation)
{
Blocking = true;
}
return result;
}
public LinuxError ReceiveFrom(out int receiveSize, Span<byte> buffer, int size, BsdSocketFlags flags, out IPEndPoint remoteEndPoint)
{
LinuxError result;
remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
bool shouldBlockAfterOperation = false;
byte[] proxyBuffer = new byte[size + ProxyClient.GetRequiredWrapperSpace()];
if (Blocking && flags.HasFlag(BsdSocketFlags.DontWait))
{
Blocking = false;
shouldBlockAfterOperation = true;
}
try
{
EndPoint temp = new IPEndPoint(IPAddress.Any, 0);
receiveSize = ProxyClient.ReceiveFrom(proxyBuffer, WinSockHelper.ConvertBsdSocketFlags(flags), ref temp);
remoteEndPoint = (IPEndPoint)temp;
result = LinuxError.SUCCESS;
}
catch (ProxyException exception)
{
Logger.Error?.Print(
LogClass.ServiceBsd,
$"An error occured while trying to receive data: {exception}"
);
receiveSize = -1;
result = ToLinuxError(exception.ReplyCode);
}
catch (SocketException exception)
{
receiveSize = -1;
result = WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
}
if (shouldBlockAfterOperation)
{
Blocking = true;
}
return result;
}
public LinuxError Send(out int sendSize, ReadOnlySpan<byte> buffer, BsdSocketFlags flags)
{
try
{
sendSize = ProxyClient.Send(buffer, WinSockHelper.ConvertBsdSocketFlags(flags));
return LinuxError.SUCCESS;
}
catch (ProxyException exception)
{
Logger.Error?.Print(
LogClass.ServiceBsd,
$"An error occured while trying to send data: {exception}"
);
sendSize = -1;
return ToLinuxError(exception.ReplyCode);
}
catch (SocketException exception)
{
sendSize = -1;
return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
}
}
public LinuxError SendTo(out int sendSize, ReadOnlySpan<byte> buffer, int size, BsdSocketFlags flags, IPEndPoint remoteEndPoint)
{
try
{
// NOTE: sendSize might be larger than size and/or buffer.Length.
sendSize = ProxyClient.SendTo(buffer[..size], WinSockHelper.ConvertBsdSocketFlags(flags), remoteEndPoint);
return LinuxError.SUCCESS;
}
catch (ProxyException exception)
{
Logger.Error?.Print(
LogClass.ServiceBsd,
$"An error occured while trying to send data: {exception}"
);
sendSize = -1;
return ToLinuxError(exception.ReplyCode);
}
catch (SocketException exception)
{
sendSize = -1;
return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
}
}
public LinuxError RecvMMsg(out int vlen, BsdMMsgHdr message, BsdSocketFlags flags, TimeVal timeout)
{
throw new NotImplementedException();
}
public LinuxError SendMMsg(out int vlen, BsdMMsgHdr message, BsdSocketFlags flags)
{
throw new NotImplementedException();
}
/// <summary>
/// Adapted from <see cref="ManagedSocket.GetSocketOption"/>
/// </summary>
public LinuxError GetSocketOption(BsdSocketOption option, SocketOptionLevel level, Span<byte> optionValue)
{
try
{
LinuxError result = WinSockHelper.ValidateSocketOption(option, level, write: false);
if (result != LinuxError.SUCCESS)
{
Logger.Warning?.Print(LogClass.ServiceBsd, $"Invalid GetSockOpt Option: {option} Level: {level}");
return result;
}
if (!WinSockHelper.TryConvertSocketOption(option, level, out SocketOptionName optionName))
{
Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported GetSockOpt Option: {option} Level: {level}");
optionValue.Clear();
return LinuxError.SUCCESS;
}
byte[] tempOptionValue = new byte[optionValue.Length];
ProxyClient.GetSocketOption(level, optionName, tempOptionValue);
tempOptionValue.AsSpan().CopyTo(optionValue);
return LinuxError.SUCCESS;
}
catch (SocketException exception)
{
return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
}
}
/// <summary>
/// Adapted from <see cref="ManagedSocket.SetSocketOption"/>
/// </summary>
public LinuxError SetSocketOption(BsdSocketOption option, SocketOptionLevel level, ReadOnlySpan<byte> optionValue)
{
try
{
LinuxError result = WinSockHelper.ValidateSocketOption(option, level, write: true);
if (result != LinuxError.SUCCESS)
{
Logger.Warning?.Print(LogClass.ServiceBsd, $"Invalid SetSockOpt Option: {option} Level: {level}");
return result;
}
if (!WinSockHelper.TryConvertSocketOption(option, level, out SocketOptionName optionName))
{
Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported SetSockOpt Option: {option} Level: {level}");
return LinuxError.SUCCESS;
}
byte[] value = optionValue.ToArray();
ProxyClient.SetSocketOption(level, optionName, value);
return LinuxError.SUCCESS;
}
catch (SocketException exception)
{
return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
}
}
public bool Poll(int microSeconds, SelectMode mode)
{
return ProxyClient.Poll(microSeconds, mode);
}
public LinuxError Bind(IPEndPoint localEndPoint)
{
ProxyClient.RequestCommand = _isUdpSocket ? ProxyCommand.UdpAssociate : ProxyCommand.Bind;
try
{
ProxyClient.Bind(localEndPoint);
}
catch (ProxyException exception)
{
Logger.Error?.Print(
LogClass.ServiceBsd,
$"Request for {ProxyClient.RequestCommand} command failed: {exception}"
);
return ToLinuxError(exception.ReplyCode);
}
catch (SocketException exception)
{
return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
}
return LinuxError.SUCCESS;
}
public LinuxError Connect(IPEndPoint remoteEndPoint)
{
ProxyClient.RequestCommand = ProxyCommand.Connect;
try
{
ProxyClient.Connect(remoteEndPoint.Address, remoteEndPoint.Port);
}
catch (ProxyException exception)
{
Logger.Error?.Print(
LogClass.ServiceBsd,
$"Request for {ProxyClient.RequestCommand} command failed: {exception}"
);
return ToLinuxError(exception.ReplyCode);
}
catch (SocketException exception)
{
return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
}
return LinuxError.SUCCESS;
}
public LinuxError Listen(int backlog)
{
// NOTE: Only one client can connect with the default SOCKS5 commands.
if (ProxyClient.RequestCommand != ProxyCommand.Bind)
{
return LinuxError.EOPNOTSUPP;
}
return LinuxError.SUCCESS;
}
public LinuxError Accept(out ISocket newSocket)
{
newSocket = null;
if (ProxyClient.RequestCommand != ProxyCommand.Bind)
{
return LinuxError.EOPNOTSUPP;
}
// NOTE: Only one client can connect with the default SOCKS5 commands.
if (_acceptedConnection)
{
return LinuxError.EOPNOTSUPP;
}
try
{
SocksClient newProxyClient = ProxyClient.Accept();
newSocket = new ManagedProxySocket(newProxyClient);
}
catch (ProxyException exception)
{
Logger.Error?.Print(
LogClass.ServiceBsd,
$"Failed to accept client connection: {exception}"
);
return ToLinuxError(exception.ReplyCode);
}
catch (SocketException exception)
{
return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
}
return LinuxError.SUCCESS;
}
public void Disconnect()
{
ProxyClient.Disconnect();
}
public LinuxError Shutdown(BsdSocketShutdownFlags how)
{
try
{
ProxyClient.Shutdown((SocketShutdown)how);
return LinuxError.SUCCESS;
}
catch (SocketException exception)
{
return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
}
}
public void Close()
{
ProxyClient.Close();
}
}
}

View File

@ -0,0 +1,211 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types;
using System.Collections.Generic;
using System.Net.Sockets;
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
{
class ManagedProxySocketPollManager : IPollManager
{
private static ManagedProxySocketPollManager _instance;
public static ManagedProxySocketPollManager Instance
{
get
{
_instance ??= new ManagedProxySocketPollManager();
return _instance;
}
}
public bool IsCompatible(PollEvent evnt)
{
return evnt.FileDescriptor is ManagedProxySocket;
}
public LinuxError Poll(List<PollEvent> events, int timeoutMilliseconds, out int updatedCount)
{
Dictionary<SelectMode, List<ManagedProxySocket>> eventDict = new()
{
{ SelectMode.SelectRead, [] },
{ SelectMode.SelectWrite, [] },
{ SelectMode.SelectError, [] },
};
updatedCount = 0;
foreach (PollEvent evnt in events)
{
ManagedProxySocket socket = (ManagedProxySocket)evnt.FileDescriptor;
bool isValidEvent = evnt.Data.InputEvents == 0;
eventDict[SelectMode.SelectError].Add(socket);
if ((evnt.Data.InputEvents & PollEventTypeMask.Input) != 0)
{
eventDict[SelectMode.SelectRead].Add(socket);
isValidEvent = true;
}
if ((evnt.Data.InputEvents & PollEventTypeMask.UrgentInput) != 0)
{
eventDict[SelectMode.SelectRead].Add(socket);
isValidEvent = true;
}
if ((evnt.Data.InputEvents & PollEventTypeMask.Output) != 0)
{
eventDict[SelectMode.SelectWrite].Add(socket);
isValidEvent = true;
}
if (!isValidEvent)
{
Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported Poll input event type: {evnt.Data.InputEvents}");
return LinuxError.EINVAL;
}
}
try
{
int actualTimeoutMicroseconds = timeoutMilliseconds == -1 ? -1 : timeoutMilliseconds * 1000;
int totalEvents = eventDict[SelectMode.SelectRead].Count + eventDict[SelectMode.SelectWrite].Count + eventDict[SelectMode.SelectError].Count;
// TODO: Maybe check all events first, wait for the timeout and then check the failed ones again?
int timeoutMicrosecondsPerEvent = actualTimeoutMicroseconds == -1 ? -1 : actualTimeoutMicroseconds / totalEvents;
foreach ((SelectMode selectMode, List<ManagedProxySocket> eventList) in eventDict)
{
List<ManagedProxySocket> newEventList = [];
foreach (ManagedProxySocket eventSocket in eventList)
{
if (eventSocket.Poll(timeoutMicrosecondsPerEvent, selectMode))
{
newEventList.Add(eventSocket);
}
}
eventDict[selectMode] = newEventList;
}
}
catch (SocketException exception)
{
return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
}
foreach (PollEvent evnt in events)
{
ManagedProxySocket socket = ((ManagedProxySocket)evnt.FileDescriptor);
PollEventTypeMask outputEvents = evnt.Data.OutputEvents & ~evnt.Data.InputEvents;
if (eventDict[SelectMode.SelectError].Contains(socket))
{
outputEvents |= PollEventTypeMask.Error;
// TODO: Check ProxyClient.Connected and ProxyClient.IsBound when implemented.
// See ManagedSocketPollManager
}
if (eventDict[SelectMode.SelectRead].Contains(socket))
{
if ((evnt.Data.InputEvents & PollEventTypeMask.Input) != 0)
{
outputEvents |= PollEventTypeMask.Input;
}
}
if (eventDict[SelectMode.SelectWrite].Contains(socket))
{
outputEvents |= PollEventTypeMask.Output;
}
evnt.Data.OutputEvents = outputEvents;
}
updatedCount = eventDict[SelectMode.SelectRead].Count + eventDict[SelectMode.SelectWrite].Count + eventDict[SelectMode.SelectError].Count;
return LinuxError.SUCCESS;
}
public LinuxError Select(List<PollEvent> events, int timeout, out int updatedCount)
{
Dictionary<SelectMode, List<ManagedProxySocket>> eventDict = new()
{
{ SelectMode.SelectRead, [] },
{ SelectMode.SelectWrite, [] },
{ SelectMode.SelectError, [] },
};
updatedCount = 0;
foreach (PollEvent pollEvent in events)
{
ManagedProxySocket socket = (ManagedProxySocket)pollEvent.FileDescriptor;
if (pollEvent.Data.InputEvents.HasFlag(PollEventTypeMask.Input))
{
eventDict[SelectMode.SelectRead].Add(socket);
}
if (pollEvent.Data.InputEvents.HasFlag(PollEventTypeMask.Output))
{
eventDict[SelectMode.SelectWrite].Add(socket);
}
if (pollEvent.Data.InputEvents.HasFlag(PollEventTypeMask.Error))
{
eventDict[SelectMode.SelectError].Add(socket);
}
}
int totalEvents = eventDict[SelectMode.SelectRead].Count + eventDict[SelectMode.SelectWrite].Count + eventDict[SelectMode.SelectError].Count;
// TODO: Maybe check all events first, wait for the timeout and then check the failed ones again?
int timeoutMicrosecondsPerEvent = timeout == -1 ? -1 : timeout / totalEvents;
foreach ((SelectMode selectMode, List<ManagedProxySocket> eventList) in eventDict)
{
List<ManagedProxySocket> newEventList = [];
foreach (ManagedProxySocket eventSocket in eventList)
{
if (eventSocket.Poll(timeoutMicrosecondsPerEvent, selectMode))
{
newEventList.Add(eventSocket);
}
}
eventDict[selectMode] = newEventList;
}
updatedCount = eventDict[SelectMode.SelectRead].Count + eventDict[SelectMode.SelectWrite].Count + eventDict[SelectMode.SelectError].Count;
foreach (PollEvent pollEvent in events)
{
ManagedProxySocket socket = (ManagedProxySocket)pollEvent.FileDescriptor;
if (eventDict[SelectMode.SelectRead].Contains(socket))
{
pollEvent.Data.OutputEvents |= PollEventTypeMask.Input;
}
if (eventDict[SelectMode.SelectWrite].Contains(socket))
{
pollEvent.Data.OutputEvents |= PollEventTypeMask.Output;
}
if (eventDict[SelectMode.SelectError].Contains(socket))
{
pollEvent.Data.OutputEvents |= PollEventTypeMask.Error;
}
}
return LinuxError.SUCCESS;
}
}
}

View File

@ -11,7 +11,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
{ {
class ManagedSocket : ISocket class ManagedSocket : ISocket
{ {
public int Refcount { get; set; } public int RefCount { get; set; }
public AddressFamily AddressFamily => Socket.AddressFamily; public AddressFamily AddressFamily => Socket.AddressFamily;
@ -32,57 +32,13 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
public ManagedSocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType) public ManagedSocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
{ {
Socket = new Socket(addressFamily, socketType, protocolType); Socket = new Socket(addressFamily, socketType, protocolType);
Refcount = 1; RefCount = 1;
} }
private ManagedSocket(Socket socket) private ManagedSocket(Socket socket)
{ {
Socket = socket; Socket = socket;
Refcount = 1; RefCount = 1;
}
private static SocketFlags ConvertBsdSocketFlags(BsdSocketFlags bsdSocketFlags)
{
SocketFlags socketFlags = SocketFlags.None;
if (bsdSocketFlags.HasFlag(BsdSocketFlags.Oob))
{
socketFlags |= SocketFlags.OutOfBand;
}
if (bsdSocketFlags.HasFlag(BsdSocketFlags.Peek))
{
socketFlags |= SocketFlags.Peek;
}
if (bsdSocketFlags.HasFlag(BsdSocketFlags.DontRoute))
{
socketFlags |= SocketFlags.DontRoute;
}
if (bsdSocketFlags.HasFlag(BsdSocketFlags.Trunc))
{
socketFlags |= SocketFlags.Truncated;
}
if (bsdSocketFlags.HasFlag(BsdSocketFlags.CTrunc))
{
socketFlags |= SocketFlags.ControlDataTruncated;
}
bsdSocketFlags &= ~(BsdSocketFlags.Oob |
BsdSocketFlags.Peek |
BsdSocketFlags.DontRoute |
BsdSocketFlags.DontWait |
BsdSocketFlags.Trunc |
BsdSocketFlags.CTrunc);
if (bsdSocketFlags != BsdSocketFlags.None)
{
Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported socket flags: {bsdSocketFlags}");
}
return socketFlags;
} }
public LinuxError Accept(out ISocket newSocket) public LinuxError Accept(out ISocket newSocket)
@ -199,7 +155,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
shouldBlockAfterOperation = true; shouldBlockAfterOperation = true;
} }
receiveSize = Socket.Receive(buffer, ConvertBsdSocketFlags(flags)); receiveSize = Socket.Receive(buffer, WinSockHelper.ConvertBsdSocketFlags(flags));
result = LinuxError.SUCCESS; result = LinuxError.SUCCESS;
} }
@ -243,7 +199,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
return LinuxError.EOPNOTSUPP; return LinuxError.EOPNOTSUPP;
} }
receiveSize = Socket.ReceiveFrom(buffer[..size], ConvertBsdSocketFlags(flags), ref temp); receiveSize = Socket.ReceiveFrom(buffer[..size], WinSockHelper.ConvertBsdSocketFlags(flags), ref temp);
remoteEndPoint = (IPEndPoint)temp; remoteEndPoint = (IPEndPoint)temp;
result = LinuxError.SUCCESS; result = LinuxError.SUCCESS;
@ -267,7 +223,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
{ {
try try
{ {
sendSize = Socket.Send(buffer, ConvertBsdSocketFlags(flags)); sendSize = Socket.Send(buffer, WinSockHelper.ConvertBsdSocketFlags(flags));
return LinuxError.SUCCESS; return LinuxError.SUCCESS;
} }
@ -283,7 +239,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
{ {
try try
{ {
sendSize = Socket.SendTo(buffer[..size], ConvertBsdSocketFlags(flags), remoteEndPoint); sendSize = Socket.SendTo(buffer[..size], WinSockHelper.ConvertBsdSocketFlags(flags), remoteEndPoint);
return LinuxError.SUCCESS; return LinuxError.SUCCESS;
} }
@ -493,7 +449,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
try try
{ {
int receiveSize = Socket.Receive(ConvertMessagesToBuffer(message), ConvertBsdSocketFlags(flags), out SocketError socketError); int receiveSize = Socket.Receive(ConvertMessagesToBuffer(message), WinSockHelper.ConvertBsdSocketFlags(flags), out SocketError socketError);
if (receiveSize > 0) if (receiveSize > 0)
{ {
@ -531,7 +487,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
try try
{ {
int sendSize = Socket.Send(ConvertMessagesToBuffer(message), ConvertBsdSocketFlags(flags), out SocketError socketError); int sendSize = Socket.Send(ConvertMessagesToBuffer(message), WinSockHelper.ConvertBsdSocketFlags(flags), out SocketError socketError);
if (sendSize > 0) if (sendSize > 0)
{ {

View File

@ -1,3 +1,4 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types; using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -343,5 +344,49 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
return LinuxError.SUCCESS; return LinuxError.SUCCESS;
} }
public static SocketFlags ConvertBsdSocketFlags(BsdSocketFlags bsdSocketFlags)
{
SocketFlags socketFlags = SocketFlags.None;
if (bsdSocketFlags.HasFlag(BsdSocketFlags.Oob))
{
socketFlags |= SocketFlags.OutOfBand;
}
if (bsdSocketFlags.HasFlag(BsdSocketFlags.Peek))
{
socketFlags |= SocketFlags.Peek;
}
if (bsdSocketFlags.HasFlag(BsdSocketFlags.DontRoute))
{
socketFlags |= SocketFlags.DontRoute;
}
if (bsdSocketFlags.HasFlag(BsdSocketFlags.Trunc))
{
socketFlags |= SocketFlags.Truncated;
}
if (bsdSocketFlags.HasFlag(BsdSocketFlags.CTrunc))
{
socketFlags |= SocketFlags.ControlDataTruncated;
}
bsdSocketFlags &= ~(BsdSocketFlags.Oob |
BsdSocketFlags.Peek |
BsdSocketFlags.DontRoute |
BsdSocketFlags.DontWait |
BsdSocketFlags.Trunc |
BsdSocketFlags.CTrunc);
if (bsdSocketFlags != BsdSocketFlags.None)
{
Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported socket flags: {bsdSocketFlags}");
}
return socketFlags;
}
} }
} }

View File

@ -0,0 +1,52 @@
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Proxy
{
public static class ProxyManager
{
private static readonly Dictionary<string, EndPoint> _proxyEndpoints = new();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static string GetKey(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
{
return string.Join("-", new[] { (int)addressFamily, (int)socketType, (int)protocolType });
}
internal static ISocket GetSocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
{
if (_proxyEndpoints.TryGetValue(GetKey(addressFamily, socketType, protocolType), out EndPoint endPoint))
{
return new ManagedProxySocket(addressFamily, socketType, protocolType, endPoint);
}
return new ManagedSocket(addressFamily, socketType, protocolType);
}
public static void AddOrUpdate(EndPoint endPoint,
AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
{
_proxyEndpoints[GetKey(addressFamily, socketType, protocolType)] = endPoint;
}
public static void AddOrUpdate(IPAddress address, int port,
AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
{
_proxyEndpoints[GetKey(addressFamily, socketType, protocolType)] = new IPEndPoint(address, port);
}
public static void AddOrUpdate(string host, int port,
AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
{
_proxyEndpoints[GetKey(addressFamily, socketType, protocolType)] = new DnsEndPoint(host, port);
}
public static bool Remove(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
{
return _proxyEndpoints.Remove(GetKey(addressFamily, socketType, protocolType));
}
}
}

View File

@ -1,6 +1,7 @@
using Ryujinx.HLE.HOS.Services.Sockets.Bsd; using Ryujinx.HLE.HOS.Services.Sockets.Bsd;
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl; using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl;
using Ryujinx.HLE.HOS.Services.Ssl.Types; using Ryujinx.HLE.HOS.Services.Ssl.Types;
using RyuSocks;
using System; using System;
using System.IO; using System.IO;
using System.Net; using System.Net;
@ -111,12 +112,25 @@ namespace Ryujinx.HLE.HOS.Services.Ssl.SslService
{ {
return hostName; return hostName;
} }
// Thrown by ManagedProxySocket when accessing RemoteEndPoint before connecting to a remote.
catch (NullReferenceException)
{
return hostName;
}
} }
public ResultCode Handshake(string hostName) public ResultCode Handshake(string hostName)
{ {
StartSslOperation(); StartSslOperation();
_stream = new SslStream(new NetworkStream(((ManagedSocket)Socket).Socket, false), false, null, null);
Stream socketStream = Socket switch
{
ManagedSocket managedSocket => new NetworkStream(managedSocket.Socket, false),
ManagedProxySocket proxySocket => new SocksClientStream(proxySocket.ProxyClient, false),
_ => throw new NotSupportedException($"{typeof(Socket)} is not supported.")
};
_stream = new SslStream(socketStream, false, null, null);
hostName = RetrieveHostName(hostName); hostName = RetrieveHostName(hostName);
_stream.AuthenticateAsClient(hostName, null, TranslateSslVersion(_sslVersion), false); _stream.AuthenticateAsClient(hostName, null, TranslateSslVersion(_sslVersion), false);
EndSslOperation(); EndSslOperation();

View File

@ -14,7 +14,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
{ {
private readonly MemoryOwner<byte> _rawDataOwner; private readonly MemoryOwner<byte> _rawDataOwner;
private Span<byte> Raw => _rawDataOwner.Memory.Span; private Span<byte> Raw => _rawDataOwner.Span;
private ref ParcelHeader Header => ref MemoryMarshal.Cast<byte, ParcelHeader>(Raw)[0]; private ref ParcelHeader Header => ref MemoryMarshal.Cast<byte, ParcelHeader>(Raw)[0];

View File

@ -29,6 +29,7 @@
<PackageReference Include="SkiaSharp" /> <PackageReference Include="SkiaSharp" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux" /> <PackageReference Include="SkiaSharp.NativeAssets.Linux" />
<PackageReference Include="NetCoreServer" /> <PackageReference Include="NetCoreServer" />
<PackageReference Include="RyuSocks" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -1,5 +1,5 @@
using Ryujinx.Common.Memory;
using System; using System;
using System.Buffers;
namespace Ryujinx.Memory namespace Ryujinx.Memory
{ {
@ -7,7 +7,7 @@ namespace Ryujinx.Memory
{ {
private readonly IWritableBlock _block; private readonly IWritableBlock _block;
private readonly ulong _va; private readonly ulong _va;
private readonly IMemoryOwner<byte> _memoryOwner; private readonly MemoryOwner<byte> _memoryOwner;
private readonly bool _tracked; private readonly bool _tracked;
private bool NeedsWriteback => _block != null; private bool NeedsWriteback => _block != null;
@ -22,7 +22,7 @@ namespace Ryujinx.Memory
Memory = memory; Memory = memory;
} }
public WritableRegion(IWritableBlock block, ulong va, IMemoryOwner<byte> memoryOwner, bool tracked = false) public WritableRegion(IWritableBlock block, ulong va, MemoryOwner<byte> memoryOwner, bool tracked = false)
: this(block, va, memoryOwner.Memory, tracked) : this(block, va, memoryOwner.Memory, tracked)
{ {
_memoryOwner = memoryOwner; _memoryOwner = memoryOwner;