Compare commits

..

6 Commits

Author SHA1 Message Date
44862dce3e Stub unsupported BSD socket options (#5670)
* Stub unsupported BSD socket options

* Span.Clear
2023-09-19 19:35:56 +02:00
e601419bd4 make cheat list binding public (#5697) 2023-09-19 16:51:56 +00:00
d6bc0de785 use compiled bidning for localizations (#5684) 2023-09-18 22:20:59 +02:00
9f26fd3600 remove some usages of reflection binding (#5686) 2023-09-18 22:09:22 +02:00
88df636c87 Replace ShaderOutputLayer with equivalent ShaderViewportIndexLayerEXT capability (#5683) 2023-09-16 18:49:13 +02:00
7ccff037e8 Fix some Vulkan validation errors (mostly related to barriers) (#5603)
* Replace image barriers inside render pass with more generic memory barrier

* Remove forceStorage since it was creating images with storage bit for formats that are not StorageImage compatible

* Add missing flags on subpass dependency

* Don't call vkCmdSetScissor with a scissor count of 0

* One semaphore per swapchain image

* Remove compute stage from read to write barriers

* Try to improve Pipeline.Barrier nonsense

* Set PipelineStateFlags based on supported stages
2023-09-14 19:58:11 +02:00
20 changed files with 350 additions and 101 deletions

View File

@ -1,6 +1,7 @@
using Avalonia.Data;
using Avalonia.Data.Core;
using Avalonia.Markup.Xaml;
using Avalonia.Markup.Xaml.MarkupExtensions;
using Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings;
using System;
namespace Ryujinx.Ava.Common.Locale
@ -18,11 +19,20 @@ namespace Ryujinx.Ava.Common.Locale
{
LocaleKeys keyToUse = Key;
ReflectionBindingExtension binding = new($"[{keyToUse}]")
{
Mode = BindingMode.OneWay,
Source = LocaleManager.Instance,
};
var builder = new CompiledBindingPathBuilder();
builder.SetRawSource(LocaleManager.Instance)
.Property(new ClrPropertyInfo("Item",
obj => (LocaleManager.Instance[keyToUse]),
null,
typeof(string)), (weakRef, iPropInfo) =>
{
return PropertyInfoAccessorFactory.CreateInpcPropertyAccessor(weakRef, iPropInfo);
});
var path = builder.Build();
var binding = new CompiledBindingExtension(path);
return binding.ProvideValue(serviceProvider);
}

View File

@ -6,9 +6,11 @@
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="{locale:Locale ErrorWindowTitle}"
xmlns:views="using:Ryujinx.Ava.UI.Applet"
Width="450"
Height="340"
CanResize="False"
x:DataType="views:ErrorAppletWindow"
SizeToContent="Height"
mc:Ignorable="d"
Focusable="True">
@ -38,7 +40,7 @@
Grid.Column="1"
Margin="10"
VerticalAlignment="Stretch"
Text="{ReflectionBinding Message}"
Text="{Binding Message}"
TextWrapping="Wrap" />
<StackPanel
Name="ButtonStack"
@ -49,4 +51,4 @@
Orientation="Horizontal"
Spacing="10" />
</Grid>
</Window>
</Window>

View File

@ -4,7 +4,9 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="using:Ryujinx.Ava.UI.Controls"
Width="400"
x:DataType="views:SwkbdAppletDialog"
mc:Ignorable="d"
Focusable="True">
<Grid
@ -34,13 +36,13 @@
Grid.Row="1"
Grid.Column="1"
Margin="5"
Text="{ReflectionBinding MainText}"
Text="{Binding MainText}"
TextWrapping="Wrap" />
<TextBlock
Grid.Row="2"
Grid.Column="1"
Margin="5"
Text="{ReflectionBinding SecondaryText}"
Text="{Binding SecondaryText}"
TextWrapping="Wrap" />
<TextBox
Name="Input"
@ -50,7 +52,7 @@
VerticalAlignment="Center"
Focusable="True"
KeyUp="Message_KeyUp"
Text="{ReflectionBinding Message}"
Text="{Binding Message}"
TextInput="Message_TextInput"
TextWrapping="Wrap"
UseFloatingWatermark="True" />

View File

@ -46,7 +46,7 @@
<Setter Property="CornerRadius" Value="4" />
</Style>
<Style Selector="ListBoxItem:selected /template/ Rectangle#SelectionIndicator">
<Setter Property="MinHeight" Value="{ReflectionBinding $parent[UserControl].DataContext.GridItemSelectorSize}" />
<Setter Property="MinHeight" Value="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).GridItemSelectorSize}" />
</Style>
</ListBox.Styles>
<ListBox.ItemTemplate>
@ -56,10 +56,10 @@
Margin="10"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Classes.huge="{ReflectionBinding $parent[UserControl].DataContext.IsGridHuge}"
Classes.large="{ReflectionBinding $parent[UserControl].DataContext.IsGridLarge}"
Classes.normal="{ReflectionBinding $parent[UserControl].DataContext.IsGridMedium}"
Classes.small="{ReflectionBinding $parent[UserControl].DataContext.IsGridSmall}"
Classes.huge="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridHuge}"
Classes.large="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridLarge}"
Classes.normal="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridMedium}"
Classes.small="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridSmall}"
ClipToBounds="True"
CornerRadius="4">
<Grid>
@ -78,7 +78,7 @@
Margin="0,10,0,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
IsVisible="{ReflectionBinding $parent[UserControl].DataContext.ShowNames}">
IsVisible="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).ShowNames}">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
@ -101,4 +101,4 @@
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</UserControl>
</UserControl>

View File

@ -42,7 +42,7 @@
</ListBox.ItemsPanel>
<ListBox.Styles>
<Style Selector="ListBoxItem:selected /template/ Rectangle#SelectionIndicator">
<Setter Property="MinHeight" Value="{ReflectionBinding $parent[UserControl].DataContext.ListItemSelectorSize}" />
<Setter Property="MinHeight" Value="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).ListItemSelectorSize}" />
</Style>
</ListBox.Styles>
<ListBox.ItemTemplate>
@ -67,10 +67,10 @@
Grid.RowSpan="3"
Grid.Column="0"
Margin="0"
Classes.huge="{ReflectionBinding $parent[UserControl].DataContext.IsGridHuge}"
Classes.large="{ReflectionBinding $parent[UserControl].DataContext.IsGridLarge}"
Classes.normal="{ReflectionBinding $parent[UserControl].DataContext.IsGridMedium}"
Classes.small="{ReflectionBinding $parent[UserControl].DataContext.IsGridSmall}"
Classes.huge="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridHuge}"
Classes.large="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridLarge}"
Classes.normal="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridMedium}"
Classes.small="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridSmall}"
Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
<Border
Grid.Column="2"
@ -157,4 +157,4 @@
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</UserControl>
</UserControl>

View File

@ -11,6 +11,7 @@
Height="500"
MinWidth="500"
MinHeight="500"
x:DataType="window:CheatWindow"
WindowStartupLocation="CenterOwner"
mc:Ignorable="d"
Focusable="True">
@ -40,7 +41,7 @@
HorizontalAlignment="Center"
VerticalAlignment="Center"
LineHeight="18"
Text="{ReflectionBinding Heading}"
Text="{Binding Heading}"
TextAlignment="Center"
TextWrapping="Wrap" />
<TextBlock
@ -61,7 +62,7 @@
MinWidth="160"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{ReflectionBinding BuildId}"
Text="{Binding BuildId}"
IsReadOnly="True" />
<Border
Grid.Row="3"
@ -77,7 +78,7 @@
MinHeight="300"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ItemsSource="{ReflectionBinding LoadedCheats}">
ItemsSource="{Binding LoadedCheats}">
<TreeView.Styles>
<Styles>
<Style Selector="TreeViewItem:empty /template/ ItemsPresenter">
@ -120,18 +121,18 @@
Name="SaveButton"
MinWidth="90"
Margin="5"
Command="{ReflectionBinding Save}"
IsVisible="{ReflectionBinding !NoCheatsFound}">
Command="{Binding Save}"
IsVisible="{Binding !NoCheatsFound}">
<TextBlock Text="{locale:Locale SettingsButtonSave}" />
</Button>
<Button
Name="CancelButton"
MinWidth="90"
Margin="5"
Command="{ReflectionBinding Close}">
Command="{Binding Close}">
<TextBlock Text="{locale:Locale InputDialogCancel}" />
</Button>
</DockPanel>
</DockPanel>
</Grid>
</window:StyleableWindow>
</window:StyleableWindow>

View File

@ -17,7 +17,7 @@ namespace Ryujinx.Ava.UI.Windows
private readonly string _enabledCheatsPath;
public bool NoCheatsFound { get; }
private AvaloniaList<CheatsList> LoadedCheats { get; }
public AvaloniaList<CheatsList> LoadedCheats { get; }
public string Heading { get; }
public string BuildId { get; }

View File

@ -39,14 +39,14 @@
Name="EnableAllButton"
MinWidth="90"
Margin="5"
Command="{ReflectionBinding EnableAll}">
Command="{Binding EnableAll}">
<TextBlock Text="{locale:Locale DlcManagerEnableAllButton}" />
</Button>
<Button
Name="DisableAllButton"
MinWidth="90"
Margin="5"
Command="{ReflectionBinding DisableAll}">
Command="{Binding DisableAll}">
<TextBlock Text="{locale:Locale DlcManagerDisableAllButton}" />
</Button>
</StackPanel>
@ -157,14 +157,14 @@
Name="AddButton"
MinWidth="90"
Margin="5"
Command="{ReflectionBinding Add}">
Command="{Binding Add}">
<TextBlock Text="{locale:Locale SettingsTabGeneralAdd}" />
</Button>
<Button
Name="RemoveAllButton"
MinWidth="90"
Margin="5"
Command="{ReflectionBinding RemoveAll}">
Command="{Binding RemoveAll}">
<TextBlock Text="{locale:Locale DlcManagerRemoveAllButton}" />
</Button>
</StackPanel>
@ -189,4 +189,4 @@
</StackPanel>
</Panel>
</Grid>
</UserControl>
</UserControl>

View File

@ -89,6 +89,16 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
context.AddCapability(Capability.DrawParameters);
}
if (context.Definitions.Stage != ShaderStage.Fragment &&
context.Definitions.Stage != ShaderStage.Geometry &&
context.Definitions.Stage != ShaderStage.Compute &&
(context.Info.IoDefinitions.Contains(new IoDefinition(StorageKind.Output, IoVariable.Layer)) ||
context.Info.IoDefinitions.Contains(new IoDefinition(StorageKind.Output, IoVariable.ViewportIndex))))
{
context.AddExtension("SPV_EXT_shader_viewport_index_layer");
context.AddCapability(Capability.ShaderViewportIndexLayerEXT);
}
if (context.Info.IoDefinitions.Contains(new IoDefinition(StorageKind.Output, IoVariable.ViewportMask)))
{
context.AddExtension("SPV_NV_viewport_array2");
@ -277,14 +287,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
localSizeZ);
}
if (context.Definitions.Stage != ShaderStage.Fragment &&
context.Definitions.Stage != ShaderStage.Geometry &&
context.Definitions.Stage != ShaderStage.Compute &&
context.Info.IoDefinitions.Contains(new IoDefinition(StorageKind.Output, IoVariable.Layer)))
{
context.AddCapability(Capability.ShaderLayer);
}
if (context.Definitions.TransformFeedbackEnabled && context.Definitions.LastInVertexPipeline)
{
context.AddExecutionMode(spvFunc, ExecutionMode.Xfb);

View File

@ -257,14 +257,22 @@ namespace Ryujinx.Graphics.Vulkan
if (realIndex != -1)
{
_colors[realIndex].Storage?.InsertReadToWriteBarrier(cbs, AccessFlags.ColorAttachmentWriteBit, PipelineStageFlags.ColorAttachmentOutputBit);
_colors[realIndex].Storage?.InsertReadToWriteBarrier(
cbs,
AccessFlags.ColorAttachmentWriteBit,
PipelineStageFlags.ColorAttachmentOutputBit,
insideRenderPass: true);
}
}
}
public void InsertClearBarrierDS(CommandBufferScoped cbs)
{
_depthStencil?.Storage?.InsertReadToWriteBarrier(cbs, AccessFlags.DepthStencilAttachmentWriteBit, PipelineStageFlags.LateFragmentTestsBit);
_depthStencil?.Storage?.InsertReadToWriteBarrier(
cbs,
AccessFlags.DepthStencilAttachmentWriteBit,
PipelineStageFlags.LateFragmentTestsBit,
insideRenderPass: true);
}
}
}

View File

@ -41,6 +41,7 @@ namespace Ryujinx.Graphics.Vulkan
public readonly bool SupportsPreciseOcclusionQueries;
public readonly bool SupportsPipelineStatisticsQuery;
public readonly bool SupportsGeometryShader;
public readonly bool SupportsTessellationShader;
public readonly bool SupportsViewportArray2;
public readonly bool SupportsHostImportedMemory;
public readonly bool SupportsDepthClipControl;
@ -77,6 +78,7 @@ namespace Ryujinx.Graphics.Vulkan
bool supportsPreciseOcclusionQueries,
bool supportsPipelineStatisticsQuery,
bool supportsGeometryShader,
bool supportsTessellationShader,
bool supportsViewportArray2,
bool supportsHostImportedMemory,
bool supportsDepthClipControl,
@ -112,6 +114,7 @@ namespace Ryujinx.Graphics.Vulkan
SupportsPreciseOcclusionQueries = supportsPreciseOcclusionQueries;
SupportsPipelineStatisticsQuery = supportsPipelineStatisticsQuery;
SupportsGeometryShader = supportsGeometryShader;
SupportsTessellationShader = supportsTessellationShader;
SupportsViewportArray2 = supportsViewportArray2;
SupportsHostImportedMemory = supportsHostImportedMemory;
SupportsDepthClipControl = supportsDepthClipControl;

View File

@ -149,10 +149,22 @@ namespace Ryujinx.Graphics.Vulkan
DstAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit,
};
PipelineStageFlags pipelineStageFlags = PipelineStageFlags.VertexShaderBit | PipelineStageFlags.FragmentShaderBit;
if (Gd.Capabilities.SupportsGeometryShader)
{
pipelineStageFlags |= PipelineStageFlags.GeometryShaderBit;
}
if (Gd.Capabilities.SupportsTessellationShader)
{
pipelineStageFlags |= PipelineStageFlags.TessellationControlShaderBit | PipelineStageFlags.TessellationEvaluationShaderBit;
}
Gd.Api.CmdPipelineBarrier(
CommandBuffer,
PipelineStageFlags.FragmentShaderBit,
PipelineStageFlags.FragmentShaderBit,
pipelineStageFlags,
pipelineStageFlags,
0,
1,
memoryBarrier,

View File

@ -9,8 +9,12 @@ namespace Ryujinx.Graphics.Vulkan
{
static class PipelineConverter
{
private const AccessFlags SubpassSrcAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit | AccessFlags.ColorAttachmentWriteBit;
private const AccessFlags SubpassDstAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit | AccessFlags.ShaderReadBit;
private const AccessFlags SubpassAccessMask =
AccessFlags.MemoryReadBit |
AccessFlags.MemoryWriteBit |
AccessFlags.ShaderReadBit |
AccessFlags.ColorAttachmentWriteBit |
AccessFlags.DepthStencilAttachmentWriteBit;
public static unsafe DisposableRenderPass ToRenderPass(this ProgramPipelineState state, VulkanRenderer gd, Device device)
{
@ -132,8 +136,8 @@ namespace Ryujinx.Graphics.Vulkan
0,
PipelineStageFlags.AllGraphicsBit,
PipelineStageFlags.AllGraphicsBit,
SubpassSrcAccessMask,
SubpassDstAccessMask,
SubpassAccessMask,
SubpassAccessMask,
0);
}
@ -146,8 +150,8 @@ namespace Ryujinx.Graphics.Vulkan
0,
PipelineStageFlags.AllGraphicsBit,
PipelineStageFlags.AllGraphicsBit,
SubpassSrcAccessMask,
SubpassDstAccessMask,
SubpassAccessMask,
SubpassAccessMask,
0);
}

View File

@ -146,7 +146,10 @@ namespace Ryujinx.Graphics.Vulkan
private void RecordScissor(Vk api, CommandBuffer commandBuffer)
{
api.CmdSetScissor(commandBuffer, 0, (uint)ScissorsCount, _scissors.AsSpan());
if (ScissorsCount != 0)
{
api.CmdSetScissor(commandBuffer, 0, (uint)ScissorsCount, _scissors.AsSpan());
}
}
private readonly void RecordStencilMasks(Vk api, CommandBuffer commandBuffer)

View File

@ -78,7 +78,7 @@ namespace Ryujinx.Graphics.Vulkan
var sampleCountFlags = ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, (uint)info.Samples);
var usage = GetImageUsage(info.Format, info.Target, gd.Capabilities.SupportsShaderStorageImageMultisample, forceStorage: true);
var usage = GetImageUsage(info.Format, info.Target, gd.Capabilities.SupportsShaderStorageImageMultisample);
var flags = ImageCreateFlags.CreateMutableFormatBit;
@ -291,7 +291,7 @@ namespace Ryujinx.Graphics.Vulkan
}
}
public static ImageUsageFlags GetImageUsage(Format format, Target target, bool supportsMsStorage, bool forceStorage = false)
public static ImageUsageFlags GetImageUsage(Format format, Target target, bool supportsMsStorage)
{
var usage = DefaultUsageFlags;
@ -304,7 +304,7 @@ namespace Ryujinx.Graphics.Vulkan
usage |= ImageUsageFlags.ColorAttachmentBit;
}
if (((forceStorage && !format.IsDepthOrStencil()) || format.IsImageCompatible()) && (supportsMsStorage || !target.IsMultisample()))
if (format.IsImageCompatible() && (supportsMsStorage || !target.IsMultisample()))
{
usage |= ImageUsageFlags.StorageBit;
}
@ -440,25 +440,27 @@ namespace Ryujinx.Graphics.Vulkan
_lastModificationStage = stage;
}
public void InsertReadToWriteBarrier(CommandBufferScoped cbs, AccessFlags dstAccessFlags, PipelineStageFlags dstStageFlags)
public void InsertReadToWriteBarrier(CommandBufferScoped cbs, AccessFlags dstAccessFlags, PipelineStageFlags dstStageFlags, bool insideRenderPass)
{
if (_lastReadAccess != AccessFlags.None)
{
ImageAspectFlags aspectFlags = Info.Format.ConvertAspectFlags();
var lastReadStage = _lastReadStage;
TextureView.InsertImageBarrier(
if (insideRenderPass)
{
// We can't have barrier from compute inside a render pass,
// as it is invalid to specify compute in the subpass dependency stage mask.
lastReadStage &= ~PipelineStageFlags.ComputeShaderBit;
}
if (lastReadStage != PipelineStageFlags.None)
{
TextureView.InsertMemoryBarrier(
_gd.Api,
cbs.CommandBuffer,
_imageAuto.Get(cbs).Value,
_lastReadAccess,
dstAccessFlags,
_lastReadStage,
dstStageFlags,
aspectFlags,
0,
0,
_info.GetLayers(),
_info.Levels);
lastReadStage,
dstStageFlags);
_lastReadAccess = AccessFlags.None;
_lastReadStage = PipelineStageFlags.None;
@ -472,21 +474,13 @@ namespace Ryujinx.Graphics.Vulkan
if (_lastModificationAccess != AccessFlags.None)
{
ImageAspectFlags aspectFlags = Info.Format.ConvertAspectFlags();
TextureView.InsertImageBarrier(
TextureView.InsertMemoryBarrier(
_gd.Api,
cbs.CommandBuffer,
_imageAuto.Get(cbs).Value,
_lastModificationAccess,
dstAccessFlags,
_lastModificationStage,
dstStageFlags,
aspectFlags,
0,
0,
_info.GetLayers(),
_info.Levels);
dstStageFlags);
_lastModificationAccess = AccessFlags.None;
}

View File

@ -435,6 +435,34 @@ namespace Ryujinx.Graphics.Vulkan
ImageAspectFlags.ColorBit);
}
public static unsafe void InsertMemoryBarrier(
Vk api,
CommandBuffer commandBuffer,
AccessFlags srcAccessMask,
AccessFlags dstAccessMask,
PipelineStageFlags srcStageMask,
PipelineStageFlags dstStageMask)
{
MemoryBarrier memoryBarrier = new()
{
SType = StructureType.MemoryBarrier,
SrcAccessMask = srcAccessMask,
DstAccessMask = dstAccessMask,
};
api.CmdPipelineBarrier(
commandBuffer,
srcStageMask,
dstStageMask,
DependencyFlags.None,
1,
memoryBarrier,
0,
null,
0,
null);
}
public static unsafe void InsertImageBarrier(
Vk api,
CommandBuffer commandBuffer,

View File

@ -327,6 +327,7 @@ namespace Ryujinx.Graphics.Vulkan
features2.Features.OcclusionQueryPrecise,
_physicalDevice.PhysicalDeviceFeatures.PipelineStatisticsQuery,
_physicalDevice.PhysicalDeviceFeatures.GeometryShader,
_physicalDevice.PhysicalDeviceFeatures.TessellationShader,
_physicalDevice.IsDeviceExtensionPresent("VK_NV_viewport_array2"),
_physicalDevice.IsDeviceExtensionPresent(ExtExternalMemoryHost.ExtensionName),
supportsDepthClipControl && featuresDepthClipControl.DepthClipControl,

View File

@ -22,8 +22,10 @@ namespace Ryujinx.Graphics.Vulkan
private Image[] _swapchainImages;
private Auto<DisposableImageView>[] _swapchainImageViews;
private Semaphore _imageAvailableSemaphore;
private Semaphore _renderFinishedSemaphore;
private Semaphore[] _imageAvailableSemaphores;
private Semaphore[] _renderFinishedSemaphores;
private int _frameIndex;
private int _width;
private int _height;
@ -48,14 +50,6 @@ namespace Ryujinx.Graphics.Vulkan
_surface = surface;
CreateSwapchain();
var semaphoreCreateInfo = new SemaphoreCreateInfo
{
SType = StructureType.SemaphoreCreateInfo,
};
gd.Api.CreateSemaphore(device, semaphoreCreateInfo, null, out _imageAvailableSemaphore).ThrowOnError();
gd.Api.CreateSemaphore(device, semaphoreCreateInfo, null, out _renderFinishedSemaphore).ThrowOnError();
}
private void RecreateSwapchain()
@ -69,7 +63,22 @@ namespace Ryujinx.Graphics.Vulkan
}
// Destroy old Swapchain.
_gd.Api.DeviceWaitIdle(_device);
unsafe
{
for (int i = 0; i < _imageAvailableSemaphores.Length; i++)
{
_gd.Api.DestroySemaphore(_device, _imageAvailableSemaphores[i], null);
}
for (int i = 0; i < _renderFinishedSemaphores.Length; i++)
{
_gd.Api.DestroySemaphore(_device, _renderFinishedSemaphores[i], null);
}
}
_gd.SwapchainApi.DestroySwapchain(_device, oldSwapchain, Span<AllocationCallbacks>.Empty);
CreateSwapchain();
@ -151,6 +160,25 @@ namespace Ryujinx.Graphics.Vulkan
{
_swapchainImageViews[i] = CreateSwapchainImageView(_swapchainImages[i], surfaceFormat.Format);
}
var semaphoreCreateInfo = new SemaphoreCreateInfo
{
SType = StructureType.SemaphoreCreateInfo,
};
_imageAvailableSemaphores = new Semaphore[imageCount];
for (int i = 0; i < _imageAvailableSemaphores.Length; i++)
{
_gd.Api.CreateSemaphore(_device, semaphoreCreateInfo, null, out _imageAvailableSemaphores[i]).ThrowOnError();
}
_renderFinishedSemaphores = new Semaphore[imageCount];
for (int i = 0; i < _renderFinishedSemaphores.Length; i++)
{
_gd.Api.CreateSemaphore(_device, semaphoreCreateInfo, null, out _renderFinishedSemaphores[i]).ThrowOnError();
}
}
private unsafe Auto<DisposableImageView> CreateSwapchainImageView(Image swapchainImage, VkFormat format)
@ -185,6 +213,7 @@ namespace Ryujinx.Graphics.Vulkan
{
return new SurfaceFormatKHR(VkFormat.B8G8R8A8Unorm, ColorSpaceKHR.PaceSrgbNonlinearKhr);
}
var formatToReturn = availableFormats[0];
if (colorSpacePassthroughEnabled)
{
@ -212,6 +241,7 @@ namespace Ryujinx.Graphics.Vulkan
}
}
}
return formatToReturn;
}
@ -265,6 +295,7 @@ namespace Ryujinx.Graphics.Vulkan
_gd.PipelineInternal.AutoFlush.Present();
uint nextImage = 0;
int semaphoreIndex = _frameIndex++ % _imageAvailableSemaphores.Length;
while (true)
{
@ -272,7 +303,7 @@ namespace Ryujinx.Graphics.Vulkan
_device,
_swapchain,
ulong.MaxValue,
_imageAvailableSemaphore,
_imageAvailableSemaphores[semaphoreIndex],
new Fence(),
ref nextImage);
@ -411,12 +442,12 @@ namespace Ryujinx.Graphics.Vulkan
_gd.CommandBufferPool.Return(
cbs,
stackalloc[] { _imageAvailableSemaphore },
stackalloc[] { _imageAvailableSemaphores[semaphoreIndex] },
stackalloc[] { PipelineStageFlags.ColorAttachmentOutputBit },
stackalloc[] { _renderFinishedSemaphore });
stackalloc[] { _renderFinishedSemaphores[semaphoreIndex] });
// TODO: Present queue.
var semaphore = _renderFinishedSemaphore;
var semaphore = _renderFinishedSemaphores[semaphoreIndex];
var swapchain = _swapchain;
Result result;
@ -593,14 +624,21 @@ namespace Ryujinx.Graphics.Vulkan
{
unsafe
{
_gd.Api.DestroySemaphore(_device, _renderFinishedSemaphore, null);
_gd.Api.DestroySemaphore(_device, _imageAvailableSemaphore, null);
for (int i = 0; i < _swapchainImageViews.Length; i++)
{
_swapchainImageViews[i].Dispose();
}
for (int i = 0; i < _imageAvailableSemaphores.Length; i++)
{
_gd.Api.DestroySemaphore(_device, _imageAvailableSemaphores[i], null);
}
for (int i = 0; i < _renderFinishedSemaphores.Length; i++)
{
_gd.Api.DestroySemaphore(_device, _renderFinishedSemaphores[i], null);
}
_gd.SwapchainApi.DestroySwapchain(_device, _swapchain, null);
}

View File

@ -299,11 +299,21 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
{
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.EOPNOTSUPP;
return LinuxError.SUCCESS;
}
byte[] tempOptionValue = new byte[optionValue.Length];
@ -324,11 +334,20 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
{
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.EOPNOTSUPP;
return LinuxError.SUCCESS;
}
int value = optionValue.Length >= 4 ? MemoryMarshal.Read<int>(optionValue) : MemoryMarshal.Read<byte>(optionValue);

View File

@ -183,6 +183,104 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
{ BsdSocketOption.TcpKeepCnt, SocketOptionName.TcpKeepAliveRetryCount },
};
[Flags]
private enum OptionDir
{
Get = 1 << 0,
Set = 1 << 1,
GetSet = Get | Set,
}
private static readonly Dictionary<BsdSocketOption, OptionDir> _validSoSocketOptionMap = new()
{
{ BsdSocketOption.SoDebug, OptionDir.GetSet },
{ BsdSocketOption.SoAcceptConn, OptionDir.Get },
{ BsdSocketOption.SoReuseAddr, OptionDir.GetSet },
{ BsdSocketOption.SoKeepAlive, OptionDir.GetSet },
{ BsdSocketOption.SoDontRoute, OptionDir.GetSet },
{ BsdSocketOption.SoBroadcast, OptionDir.GetSet },
{ BsdSocketOption.SoUseLoopBack, OptionDir.GetSet },
{ BsdSocketOption.SoLinger, OptionDir.GetSet },
{ BsdSocketOption.SoOobInline, OptionDir.GetSet },
{ BsdSocketOption.SoReusePort, OptionDir.GetSet },
{ BsdSocketOption.SoTimestamp, OptionDir.GetSet },
{ BsdSocketOption.SoNoSigpipe, OptionDir.GetSet },
{ BsdSocketOption.SoAcceptFilter, OptionDir.GetSet },
{ BsdSocketOption.SoSndBuf, OptionDir.GetSet },
{ BsdSocketOption.SoRcvBuf, OptionDir.GetSet },
{ BsdSocketOption.SoSndLoWat, OptionDir.GetSet },
{ BsdSocketOption.SoRcvLoWat, OptionDir.GetSet },
{ BsdSocketOption.SoSndTimeo, OptionDir.GetSet },
{ BsdSocketOption.SoRcvTimeo, OptionDir.GetSet },
{ BsdSocketOption.SoError, OptionDir.Get },
{ BsdSocketOption.SoType, OptionDir.Get },
{ BsdSocketOption.SoLabel, OptionDir.Get },
{ BsdSocketOption.SoPeerLabel, OptionDir.Get },
{ BsdSocketOption.SoListenQLimit, OptionDir.Get },
{ BsdSocketOption.SoListenQLen, OptionDir.Get },
{ BsdSocketOption.SoListenIncQLen, OptionDir.Get },
{ BsdSocketOption.SoSetFib, OptionDir.Set },
{ BsdSocketOption.SoUserCookie, OptionDir.Set },
{ BsdSocketOption.SoProtocol, OptionDir.Get },
{ BsdSocketOption.SoBinTime, OptionDir.GetSet },
{ BsdSocketOption.SoNoOffload, OptionDir.Set },
{ BsdSocketOption.SoNoDdp, OptionDir.Set },
{ BsdSocketOption.SoReusePortLb, OptionDir.GetSet },
};
private static readonly Dictionary<BsdSocketOption, OptionDir> _validIpSocketOptionMap = new()
{
{ BsdSocketOption.IpOptions, OptionDir.GetSet },
{ BsdSocketOption.IpHdrIncl, OptionDir.GetSet },
{ BsdSocketOption.IpTos, OptionDir.GetSet },
{ BsdSocketOption.IpTtl, OptionDir.GetSet },
{ BsdSocketOption.IpRecvOpts, OptionDir.GetSet },
{ BsdSocketOption.IpRecvRetOpts, OptionDir.GetSet },
{ BsdSocketOption.IpRecvDstAddr, OptionDir.GetSet },
{ BsdSocketOption.IpRetOpts, OptionDir.GetSet },
{ BsdSocketOption.IpMulticastIf, OptionDir.GetSet },
{ BsdSocketOption.IpMulticastTtl, OptionDir.GetSet },
{ BsdSocketOption.IpMulticastLoop, OptionDir.GetSet },
{ BsdSocketOption.IpAddMembership, OptionDir.GetSet },
{ BsdSocketOption.IpDropMembership, OptionDir.GetSet },
{ BsdSocketOption.IpMulticastVif, OptionDir.GetSet },
{ BsdSocketOption.IpRsvpOn, OptionDir.GetSet },
{ BsdSocketOption.IpRsvpOff, OptionDir.GetSet },
{ BsdSocketOption.IpRsvpVifOn, OptionDir.GetSet },
{ BsdSocketOption.IpRsvpVifOff, OptionDir.GetSet },
{ BsdSocketOption.IpPortRange, OptionDir.GetSet },
{ BsdSocketOption.IpRecvIf, OptionDir.GetSet },
{ BsdSocketOption.IpIpsecPolicy, OptionDir.GetSet },
{ BsdSocketOption.IpOnesBcast, OptionDir.GetSet },
{ BsdSocketOption.IpBindany, OptionDir.GetSet },
{ BsdSocketOption.IpBindMulti, OptionDir.GetSet },
{ BsdSocketOption.IpRssListenBucket, OptionDir.GetSet },
{ BsdSocketOption.IpOrigDstAddr, OptionDir.GetSet },
{ BsdSocketOption.IpRecvTtl, OptionDir.GetSet },
{ BsdSocketOption.IpMinTtl, OptionDir.GetSet },
{ BsdSocketOption.IpDontFrag, OptionDir.GetSet },
{ BsdSocketOption.IpRecvTos, OptionDir.GetSet },
{ BsdSocketOption.IpAddSourceMembership, OptionDir.GetSet },
{ BsdSocketOption.IpDropSourceMembership, OptionDir.GetSet },
{ BsdSocketOption.IpBlockSource, OptionDir.GetSet },
{ BsdSocketOption.IpUnblockSource, OptionDir.GetSet },
};
private static readonly Dictionary<BsdSocketOption, OptionDir> _validTcpSocketOptionMap = new()
{
{ BsdSocketOption.TcpNoDelay, OptionDir.GetSet },
{ BsdSocketOption.TcpMaxSeg, OptionDir.GetSet },
{ BsdSocketOption.TcpNoPush, OptionDir.GetSet },
{ BsdSocketOption.TcpNoOpt, OptionDir.GetSet },
{ BsdSocketOption.TcpMd5Sig, OptionDir.GetSet },
{ BsdSocketOption.TcpInfo, OptionDir.GetSet },
{ BsdSocketOption.TcpCongestion, OptionDir.GetSet },
{ BsdSocketOption.TcpKeepInit, OptionDir.GetSet },
{ BsdSocketOption.TcpKeepIdle, OptionDir.GetSet },
{ BsdSocketOption.TcpKeepIntvl, OptionDir.GetSet },
{ BsdSocketOption.TcpKeepCnt, OptionDir.GetSet },
};
public static LinuxError ConvertError(WsaError errorCode)
{
if (OperatingSystem.IsMacOS())
@ -221,5 +319,29 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
return table.TryGetValue(option, out name);
}
public static LinuxError ValidateSocketOption(BsdSocketOption option, SocketOptionLevel level, bool write)
{
var table = level switch
{
SocketOptionLevel.Socket => _validSoSocketOptionMap,
SocketOptionLevel.IP => _validIpSocketOptionMap,
SocketOptionLevel.Tcp => _validTcpSocketOptionMap,
_ => null,
};
OptionDir dir = write ? OptionDir.Set : OptionDir.Get;
if (table == null || !table.TryGetValue(option, out OptionDir validDir))
{
return LinuxError.ENOPROTOOPT;
}
else if ((validDir & dir) != dir)
{
return LinuxError.EOPNOTSUPP;
}
return LinuxError.SUCCESS;
}
}
}