Compare commits

..

11 Commits

Author SHA1 Message Date
Isaac Marovitz
121296834a Ava GUI: Several UI Fixes (#3991)
* Fix accessability violations in ListView

* Use accent colour for favourite star

* Hide progress bar when its done

* App Data Formating

- Added space before storage unit
- Changed so minutes have 0 decimals, and hours and days have 1

* Fix theming

* Fix mismatched corner radius

* Fix acceability violations in GridView

* More consistency between Grid and List View

* Fix margin

* Let whitespace defocus controls
2022-12-05 22:04:18 +00:00
gdkchan
bbb24d8c7e Restrict shader storage buffer search when match fails (#4011)
* Restrict storage buffer search when match fails

* Shader cache version bump
2022-12-05 19:11:32 +00:00
Andrey Sukharev
4da44e09cb Make structs readonly when applicable (#4002)
* Make all structs readonly when applicable. It should reduce amount of needless defensive copies

* Make structs with trivial boilerplate equality code record structs

* Remove unnecessary readonly modifiers from TextureCreateInfo

* Make BitMap structs readonly too
2022-12-05 14:47:39 +01:00
Mary-nyan
ae13f0ab4d misc: Fix obsolete warnings in Ryujinx.Graphics.Vulkan (#4020)
Was caused by some merges after the Silk.NET update
2022-12-05 12:57:11 +00:00
dependabot[bot]
a2a35f1be6 nuget: bump Microsoft.NET.Test.Sdk from 16.8.0 to 17.4.0 (#3900)
Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 16.8.0 to 17.4.0.
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Commits](https://github.com/microsoft/vstest/compare/v16.8.0...v17.4.0)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-05 08:17:40 +01:00
Shane Slattery
aedfadaaf7 Add InfoType.MesosphereCurrentProcess (#3792)
* Add InfoType.MesosphereCurrentProcess

* Make outHandle inlined

Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>

Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
2022-12-04 19:46:02 +00:00
Ethan Page
5c0fb0cec3 ui: Disallow checking for updates while emulation active (#3886)
* Disallow updating while game is running

* Reflected change on Avalonia

* Git has gone wonky

* Fix accidental indent
2022-12-04 20:17:11 +01:00
gdkchan
17a1cab5d2 Allow SNorm buffer texture formats on Vulkan (#3957)
* Allow SNorm buffer texture formats on Vulkan

* Shader cache version bump
2022-12-04 15:36:03 -03:00
gdkchan
73aed239c3 Implement non-MS to MS copies with draws (#3958)
* Implement non-MS to MS copies with draws, simplify MS to non-MS copies and supports any host sample count

* Remove unused program
2022-12-04 15:07:11 -03:00
riperiperi
9ac66336a2 GPU: Use lazy checks for specialization state (#4004)
* GPU: Use lazy checks for specialization state

This PR adds a new class, the SpecializationStateUpdater, that allows elements of specialization state to be updated individually, and signal the state is checked when it changes between draws, instead of building and checking it on every draw. This also avoids building spec state when

Most state updates have been moved behind the shader state update, so that their specialization state updates make it in before shaders are fetched.

Downside: Fields in GpuChannelGraphicsState are no longer readonly. To counteract copies that might be caused this I pass it as `ref` when possible, though maybe `in` would be better? Not really sure about the quirks of `in` and the difference probably won't show on a benchmark.

The result is around 2 extra FPS on SMO in the usual spot. Not much right now, but it will remove costs when we're doing more expensive specialization checks, such as fragment output type specialization for macos. It may also help more on other games with more draws.

* Address Feedback

* Oops
2022-12-04 18:41:17 +01:00
riperiperi
4965681e06 GPU: Swap bindings array instead of copying (#4003)
* GPU: Swap bindings array instead of copying

Reduces work on UpdateShaderState. Now the cost is a few reference moves for arrays, rather than copying data.

Downside: bindings arrays are no longer readonly.

* Micro optimisation

* Add missing docs

* Address Feedback
2022-12-04 18:18:40 +01:00
202 changed files with 1498 additions and 1313 deletions

View File

@@ -89,6 +89,7 @@ csharp_style_conditional_delegate_call = true:suggestion
# Modifier preferences
csharp_prefer_static_local_function = true:suggestion
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent
csharp_style_prefer_readonly_struct = true
# Code-block preferences
csharp_prefer_braces = true:silent

View File

@@ -1,6 +1,6 @@
namespace ARMeilleure.CodeGen.RegisterAllocators
{
struct AllocationResult
readonly struct AllocationResult
{
public int IntUsedRegisters { get; }
public int VecUsedRegisters { get; }

View File

@@ -11,7 +11,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{
private class ParallelCopy
{
private struct Copy
private readonly struct Copy
{
public Register Dest { get; }
public Register Source { get; }

View File

@@ -11,7 +11,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{
class HybridAllocator : IRegisterAllocator
{
private struct BlockInfo
private readonly struct BlockInfo
{
public bool HasCall { get; }

View File

@@ -3,7 +3,7 @@ using System;
namespace ARMeilleure.CodeGen.RegisterAllocators
{
struct RegisterMasks
readonly struct RegisterMasks
{
public int IntAvailableRegisters { get; }
public int VecAvailableRegisters { get; }

View File

@@ -1,6 +1,6 @@
namespace ARMeilleure.CodeGen.X86
{
struct IntrinsicInfo
readonly struct IntrinsicInfo
{
public X86Instruction Inst { get; }
public IntrinsicType Type { get; }

View File

@@ -2,7 +2,7 @@ using ARMeilleure.Instructions;
namespace ARMeilleure.Decoders
{
struct InstDescriptor
readonly struct InstDescriptor
{
public static InstDescriptor Undefined => new InstDescriptor(InstName.Und, InstEmit.Und);

View File

@@ -11,7 +11,7 @@ namespace ARMeilleure.Decoders
private const int FastLookupSize = 0x1000;
private struct InstInfo
private readonly struct InstInfo
{
public int Mask { get; }
public int Value { get; }

View File

@@ -6,7 +6,7 @@ namespace ARMeilleure.Diagnostics
{
static class Symbols
{
private struct RangedSymbol
private readonly struct RangedSymbol
{
public readonly ulong Start;
public readonly ulong End;

View File

@@ -3,7 +3,7 @@ using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.IntermediateRepresentation
{
struct PhiOperation
readonly struct PhiOperation
{
private readonly Operation _operation;

View File

@@ -2,7 +2,7 @@ using System;
namespace ARMeilleure.IntermediateRepresentation
{
struct Register : IEquatable<Register>
readonly struct Register : IEquatable<Register>
{
public int Index { get; }

View File

@@ -4,7 +4,7 @@ using System.Diagnostics.CodeAnalysis;
namespace ARMeilleure.Translation.Cache
{
struct CacheEntry : IComparable<CacheEntry>
readonly struct CacheEntry : IComparable<CacheEntry>
{
public int Offset { get; }
public int Size { get; }

View File

@@ -6,7 +6,7 @@ namespace ARMeilleure.Translation.Cache
{
class CacheMemoryAllocator
{
private struct MemoryBlock : IComparable<MemoryBlock>
private readonly struct MemoryBlock : IComparable<MemoryBlock>
{
public int Offset { get; }
public int Size { get; }

View File

@@ -2,7 +2,7 @@ using ARMeilleure.IntermediateRepresentation;
namespace ARMeilleure.Translation
{
struct CompilerContext
readonly struct CompilerContext
{
public ControlFlowGraph Cfg { get; }

View File

@@ -14,7 +14,7 @@ namespace ARMeilleure.Translation
private const int RegsCount = 32;
private const int RegsMask = RegsCount - 1;
private struct RegisterMask : IEquatable<RegisterMask>
private readonly struct RegisterMask : IEquatable<RegisterMask>
{
public long IntMask => Mask.GetElement(0);
public long VecMask => Mask.GetElement(1);

View File

@@ -293,7 +293,7 @@ namespace ARMeilleure.Translation
}
}
private struct Range
private readonly struct Range
{
public ulong Start { get; }
public ulong End { get; }

View File

@@ -4,7 +4,7 @@ using System.Runtime.InteropServices;
namespace SoundIOSharp
{
public struct SoundIOChannelLayout
public readonly struct SoundIOChannelLayout
{
public static int BuiltInCount
{

View File

@@ -1,6 +1,6 @@
namespace SoundIOSharp
{
public struct SoundIOSampleRateRange
public readonly struct SoundIOSampleRateRange
{
internal SoundIOSampleRateRange(int min, int max)
{

View File

@@ -58,5 +58,7 @@
<Color x:Key="SystemChromeWhiteColor">#FFFFFFFF</Color>
<Color x:Key="ThemeForegroundColor">#FFFFFFFF</Color>
<Color x:Key="MenuFlyoutPresenterBorderColor">#3D3D3D</Color>
<Color x:Key="AppListBackgroundColor">#0FFFFFFF</Color>
<Color x:Key="AppListHoverBackgroundColor">#1EFFFFFF</Color>
</Styles.Resources>
</Styles>

View File

@@ -50,5 +50,7 @@
<Color x:Key="SystemChromeWhiteColor">#FFFFFFFF</Color>
<Color x:Key="ThemeForegroundColor">#FF000000</Color>
<Color x:Key="MenuFlyoutPresenterBorderColor">#C1C1C1</Color>
<Color x:Key="AppListBackgroundColor">#b3ffffff</Color>
<Color x:Key="AppListHoverBackgroundColor">#80cccccc</Color>
</Styles.Resources>
</Styles>

View File

@@ -11,7 +11,8 @@
Height="340"
CanResize="False"
SizeToContent="Height"
mc:Ignorable="d">
mc:Ignorable="d"
Focusable="True">
<Grid
Margin="20"
HorizontalAlignment="Stretch"

View File

@@ -6,7 +6,8 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
Width="400"
mc:Ignorable="d">
mc:Ignorable="d"
Focusable="True">
<Grid
Margin="20"
HorizontalAlignment="Stretch"

View File

@@ -10,7 +10,8 @@
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
mc:Ignorable="d"
Focusable="True">
<UserControl.Resources>
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
<MenuFlyout x:Key="GameContextMenu" Opened="MenuBase_OnMenuOpened">
@@ -113,8 +114,8 @@
<Style Selector="ListBoxItem">
<Setter Property="Padding" Value="0" />
<Setter Property="Margin" Value="5" />
<Setter Property="CornerRadius" Value="5" />
<Setter Property="Background" Value="{DynamicResource SystemAccentColorDark3}" />
<Setter Property="CornerRadius" Value="4" />
<Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
<Style.Animations>
<Animation Duration="0:0:0.7">
<KeyFrame Cue="0%">
@@ -132,27 +133,18 @@
</Animation>
</Style.Animations>
</Style>
<Style Selector="ListBoxItem:selected /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
</Style>
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource AppListHoverBackgroundColor}" />
</Style>
</ListBox.Styles>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.Styles>
<Style Selector="ui|SymbolIcon.small.icon">
<Setter Property="FontSize" Value="15" />
</Style>
<Style Selector="ui|SymbolIcon.normal.icon">
<Setter Property="FontSize" Value="19" />
</Style>
<Style Selector="ui|SymbolIcon.large.icon">
<Setter Property="FontSize" Value="23" />
</Style>
<Style Selector="ui|SymbolIcon.huge.icon">
<Setter Property="FontSize" Value="26" />
</Style>
</Grid.Styles>
<Border
Margin="0"
Padding="{Binding $parent[UserControl].DataContext.GridItemPadding}"
Margin="10"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}"
@@ -160,57 +152,41 @@
Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}"
Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}"
ClipToBounds="True"
CornerRadius="5">
<Grid Margin="0">
CornerRadius="4">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Image
Grid.Row="0"
Margin="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
<StackPanel
<Panel
Grid.Row="1"
Height="50"
Margin="5"
Margin="0 10 0 0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
IsVisible="{Binding $parent[UserControl].DataContext.ShowNames}">
<TextBlock
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Text="{Binding TitleName}"
TextAlignment="Center"
TextWrapping="Wrap" />
</StackPanel>
</Panel>
</Grid>
</Border>
<ui:SymbolIcon
Margin="5"
Margin="5,5,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}"
Classes.icon="true"
Classes.large="{Binding $parent[UserControl].DataContext.IsGridLarge}"
Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}"
Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}"
Foreground="Yellow"
FontSize="16"
Foreground="{DynamicResource SystemAccentColor}"
IsVisible="{Binding Favorite}"
Symbol="StarFilled" />
<ui:SymbolIcon
Margin="5"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}"
Classes.icon="true"
Classes.large="{Binding $parent[UserControl].DataContext.IsGridLarge}"
Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}"
Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}"
Foreground="Black"
IsVisible="{Binding Favorite}"
Symbol="Star" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>

View File

@@ -10,7 +10,8 @@
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
mc:Ignorable="d"
Focusable="True">
<UserControl.Resources>
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
<MenuFlyout x:Key="GameContextMenu" Opened="MenuBase_OnMenuOpened">
@@ -115,8 +116,8 @@
<Setter Property="Padding" Value="0" />
<Setter Property="Margin" Value="0" />
<Setter Property="CornerRadius" Value="5" />
<Setter Property="BorderBrush" Value="{DynamicResource SystemAccentColorDark3}" />
<Setter Property="BorderThickness" Value="2" />
<Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
<Setter Property="BorderThickness" Value="2"/>
<Style.Animations>
<Animation Duration="0:0:0.7">
<KeyFrame Cue="0%">
@@ -134,6 +135,12 @@
</Animation>
</Style.Animations>
</Style>
<Style Selector="ListBoxItem:selected /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
</Style>
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter">
<Setter Property="Background" Value="{DynamicResource AppListHoverBackgroundColor}" />
</Style>
</ListBox.Styles>
<ListBox.ItemTemplate>
<DataTemplate>
@@ -152,9 +159,6 @@
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Image
Grid.RowSpan="3"
Grid.Column="0"
@@ -169,7 +173,7 @@
HorizontalAlignment="Left"
VerticalAlignment="Top"
Orientation="Vertical"
Spacing="5">
Spacing="5" >
<TextBlock
HorizontalAlignment="Stretch"
Text="{Binding TitleName}"
@@ -214,20 +218,10 @@
Margin="-5,-5,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
FontSize="20"
Foreground="Yellow"
FontSize="16"
Foreground="{DynamicResource SystemAccentColor}"
IsVisible="{Binding Favorite}"
Symbol="StarFilled" />
<ui:SymbolIcon
Grid.Row="0"
Grid.Column="0"
Margin="-5,-5,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
FontSize="20"
Foreground="Black"
IsVisible="{Binding Favorite}"
Symbol="Star" />
</Grid>
</Border>
</Grid>

View File

@@ -4,7 +4,8 @@
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"
mc:Ignorable="d">
mc:Ignorable="d"
Focusable="True">
<Grid
Margin="5,10,5,5"
HorizontalAlignment="Stretch"

View File

@@ -4,7 +4,8 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Ryujinx.Ava.Ui.Controls.NavigationDialogHost">
x:Class="Ryujinx.Ava.Ui.Controls.NavigationDialogHost"
Focusable="True">
<ui:Frame HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
x:Name="ContentFrame" />
</UserControl>

View File

@@ -4,7 +4,8 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:Locale="clr-namespace:Ryujinx.Ava.Common.Locale"
x:Class="Ryujinx.Ava.Ui.Controls.ProfileImageSelectionDialog">
x:Class="Ryujinx.Ava.Ui.Controls.ProfileImageSelectionDialog"
Focusable="True">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Center" Margin="5,10,5, 5">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />

View File

@@ -3,5 +3,6 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Ryujinx.Ava.Ui.Controls.RendererHost">
x:Class="Ryujinx.Ava.Ui.Controls.RendererHost"
Focusable="True">
</UserControl>

View File

@@ -9,7 +9,8 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
Height="400"
Width="550"
x:Class="Ryujinx.Ava.Ui.Controls.SaveManager">
x:Class="Ryujinx.Ava.Ui.Controls.SaveManager"
Focusable="True">
<UserControl.Resources>
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
</UserControl.Resources>

View File

@@ -8,7 +8,8 @@
Title="Ryujinx - Waiting"
SizeToContent="WidthAndHeight"
WindowStartupLocation="CenterOwner"
mc:Ignorable="d">
mc:Ignorable="d"
Focusable="True">
<Grid
Margin="20"
HorizontalAlignment="Stretch"

View File

@@ -12,7 +12,8 @@
Margin="0"
MinWidth="500"
Padding="0"
mc:Ignorable="d">
mc:Ignorable="d"
Focusable="True">
<UserControl.Resources>
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
</UserControl.Resources>

View File

@@ -10,7 +10,8 @@
xmlns:Locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.Ui.ViewModels"
x:Class="Ryujinx.Ava.Ui.Controls.UserRecoverer">
x:Class="Ryujinx.Ava.Ui.Controls.UserRecoverer"
Focusable="True">
<Design.DataContext>
<viewModels:UserProfileViewModel />
</Design.DataContext>

View File

@@ -12,7 +12,8 @@
d:DesignHeight="450"
MinWidth="500"
d:DesignWidth="800"
mc:Ignorable="d">
mc:Ignorable="d"
Focusable="True">
<UserControl.Resources>
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
</UserControl.Resources>

View File

@@ -435,9 +435,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
OnPropertyChanged();
}
}
public Thickness GridItemPadding => ShowNames ? new Thickness() : new Thickness(5);
public bool ShowMenuAndStatusBar
{
get => _showMenuAndStatusBar;
@@ -599,7 +597,6 @@ namespace Ryujinx.Ava.Ui.ViewModels
ConfigurationState.Instance.Ui.ShowNames.Value = value;
OnPropertyChanged();
OnPropertyChanged(nameof(GridItemPadding));
OnPropertyChanged(nameof(GridSizeScale));
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
@@ -716,7 +713,6 @@ namespace Ryujinx.Ava.Ui.ViewModels
OnPropertyChanged(nameof(IsGridLarge));
OnPropertyChanged(nameof(IsGridHuge));
OnPropertyChanged(nameof(ShowNames));
OnPropertyChanged(nameof(GridItemPadding));
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
}
@@ -780,6 +776,11 @@ namespace Ryujinx.Ava.Ui.ViewModels
{
_owner.LoadProgressBar.IsVisible = false;
}
if (e.NumAppsLoaded == e.NumAppsFound)
{
_owner.LoadProgressBar.IsVisible = false;
}
});
}

View File

@@ -15,7 +15,8 @@
CanResize="False"
SizeToContent="Width"
WindowStartupLocation="CenterOwner"
mc:Ignorable="d">
mc:Ignorable="d"
Focusable="True">
<Grid
Margin="15"
HorizontalAlignment="Stretch"

View File

@@ -11,7 +11,8 @@
WindowStartupLocation="CenterOwner"
Width="800" MinHeight="650" Height="650"
SizeToContent="Manual"
MinWidth="600">
MinWidth="600"
Focusable="True">
<Design.DataContext>
<viewModels:AmiiboWindowViewModel />
</Design.DataContext>

View File

@@ -11,7 +11,8 @@
xmlns:viewModels="clr-namespace:Ryujinx.Ava.Ui.ViewModels"
xmlns:controls="clr-namespace:Ryujinx.Ava.Ui.Controls"
x:CompileBindings="True"
x:DataType="viewModels:AvatarProfileViewModel">
x:DataType="viewModels:AvatarProfileViewModel"
Focusable="True">
<Design.DataContext>
<viewModels:AvatarProfileViewModel />
</Design.DataContext>

View File

@@ -12,7 +12,8 @@
MinWidth="500"
MinHeight="500"
WindowStartupLocation="CenterOwner"
mc:Ignorable="d">
mc:Ignorable="d"
Focusable="True">
<Window.Styles>
<Style Selector="TreeViewItem">
<Setter Property="IsExpanded" Value="True" />

View File

@@ -8,7 +8,8 @@
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
x:Class="Ryujinx.Ava.Ui.Windows.ContentDialogOverlayWindow"
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
Title="ContentDialogOverlayWindow">
Title="ContentDialogOverlayWindow"
Focusable="True">
<window:StyleableWindow.Styles>
<Style Selector="ui|ContentDialog /template/ Panel#LayoutRoot">
<Setter Property="Background"

View File

@@ -13,7 +13,8 @@
d:DesignHeight="800"
d:DesignWidth="800"
x:CompileBindings="False"
mc:Ignorable="d">
mc:Ignorable="d"
Focusable="True">
<Design.DataContext>
<viewModels:ControllerSettingsViewModel />
</Design.DataContext>

View File

@@ -14,7 +14,8 @@
MaxHeight="500"
SizeToContent="Height"
WindowStartupLocation="CenterOwner"
mc:Ignorable="d">
mc:Ignorable="d"
Focusable="True">
<Grid Name="DownloadableContentGrid" Margin="15">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />

View File

@@ -20,7 +20,7 @@ namespace Ryujinx.Ava.Ui.Windows
private const int CutOffLuminosity = 64;
private struct PaletteColor
private readonly struct PaletteColor
{
public int Qck { get; }
public byte R { get; }

View File

@@ -20,7 +20,8 @@
x:CompileBindings="True"
x:DataType="viewModels:MainWindowViewModel"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
mc:Ignorable="d"
Focusable="True">
<Window.Styles>
<Style Selector="TitleBar:fullscreen">
<Setter Property="Background" Value="#000000" />

View File

@@ -266,6 +266,7 @@ namespace Ryujinx.Ava.Ui.Windows
return;
}
CanUpdate = false;
ViewModel.LoadHeading = string.IsNullOrWhiteSpace(titleName) ? string.Format(LocaleManager.Instance["LoadingHeading"], AppHost.Device.Application.TitleName) : titleName;
ViewModel.TitleName = string.IsNullOrWhiteSpace(titleName) ? AppHost.Device.Application.TitleName : titleName;
@@ -371,6 +372,7 @@ namespace Ryujinx.Ava.Ui.Windows
ViewModel.ShowContent = true;
ViewModel.ShowLoadProgress = false;
ViewModel.IsLoadingIndeterminate = false;
CanUpdate = true;
Cursor = Cursor.Default;
if (MainContent.Content != _mainViewContent)

View File

@@ -6,7 +6,8 @@
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
mc:Ignorable="d"
x:Class="Ryujinx.Ava.Ui.Windows.MotionSettingsWindow">
x:Class="Ryujinx.Ava.Ui.Windows.MotionSettingsWindow"
Focusable="True">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />

View File

@@ -6,7 +6,8 @@
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
mc:Ignorable="d"
x:Class="Ryujinx.Ava.Ui.Windows.RumbleSettingsWindow">
x:Class="Ryujinx.Ava.Ui.Windows.RumbleSettingsWindow"
Focusable="True">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />

View File

@@ -18,7 +18,8 @@
WindowStartupLocation="CenterOwner"
x:CompileBindings="True"
x:DataType="viewModels:SettingsViewModel"
mc:Ignorable="d">
mc:Ignorable="d"
Focusable="True">
<Design.DataContext>
<viewModels:SettingsViewModel />
</Design.DataContext>

View File

@@ -14,7 +14,8 @@
MaxHeight="400"
SizeToContent="Height"
WindowStartupLocation="CenterOwner"
mc:Ignorable="d">
mc:Ignorable="d"
Focusable="True">
<Grid Margin="15">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />

View File

@@ -16,7 +16,7 @@ namespace Ryujinx.Common.Logging
public static event EventHandler<LogEventArgs> Updated;
public struct Log
public readonly struct Log
{
internal readonly LogLevel Level;

View File

@@ -7,7 +7,7 @@ namespace Ryujinx.Common.Memory
/// This is useful to keep the Array representation when possible to avoid copies.
/// </summary>
/// <typeparam name="T">Element Type</typeparam>
public ref struct SpanOrArray<T> where T : unmanaged
public readonly ref struct SpanOrArray<T> where T : unmanaged
{
public readonly T[] Array;
public readonly ReadOnlySpan<T> Span;

View File

@@ -17,7 +17,7 @@ namespace Ryujinx.Cpu
/// <summary>
/// Stores handlers for the various CPU exceptions.
/// </summary>
public struct ExceptionCallbacks
public readonly struct ExceptionCallbacks
{
/// <summary>
/// Handler for CPU interrupts triggered using <see cref="IExecutionContext.RequestInterrupt"/>.

View File

@@ -2,7 +2,7 @@
namespace Ryujinx.Graphics.Device
{
public struct RwCallback
public readonly struct RwCallback
{
public Action<int> Write { get; }
public Func<int> Read { get; }

View File

@@ -1,6 +1,6 @@
namespace Ryujinx.Graphics.GAL
{
public struct BlendDescriptor
public readonly struct BlendDescriptor
{
public bool Enable { get; }

View File

@@ -1,6 +1,6 @@
namespace Ryujinx.Graphics.GAL
{
public struct BufferAssignment
public readonly struct BufferAssignment
{
public readonly int Binding;
public readonly BufferRange Range;

View File

@@ -1,22 +1,14 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.GAL
{
[StructLayout(LayoutKind.Sequential, Size = 8)]
public struct BufferHandle : IEquatable<BufferHandle>
public readonly record struct BufferHandle
{
private readonly ulong _value;
public static BufferHandle Null => new BufferHandle(0);
private BufferHandle(ulong value) => _value = value;
public override bool Equals(object obj) => obj is BufferHandle handle && Equals(handle);
public bool Equals([AllowNull] BufferHandle other) => other._value == _value;
public override int GetHashCode() => _value.GetHashCode();
public static bool operator ==(BufferHandle left, BufferHandle right) => left.Equals(right);
public static bool operator !=(BufferHandle left, BufferHandle right) => !(left == right);
}
}

View File

@@ -1,6 +1,6 @@
namespace Ryujinx.Graphics.GAL
{
public struct BufferRange
public readonly struct BufferRange
{
private static readonly BufferRange _empty = new BufferRange(BufferHandle.Null, 0, 0);

View File

@@ -2,7 +2,7 @@ using Ryujinx.Graphics.Shader.Translation;
namespace Ryujinx.Graphics.GAL
{
public struct Capabilities
public readonly struct Capabilities
{
public readonly TargetApi Api;
public readonly string VendorName;
@@ -17,6 +17,7 @@ namespace Ryujinx.Graphics.GAL
public readonly bool Supports3DTextureCompression;
public readonly bool SupportsBgraFormat;
public readonly bool SupportsR4G4Format;
public readonly bool SupportsSnormBufferTextureFormat;
public readonly bool SupportsFragmentShaderInterlock;
public readonly bool SupportsFragmentShaderOrderingIntel;
public readonly bool SupportsGeometryShaderPassthrough;
@@ -52,6 +53,7 @@ namespace Ryujinx.Graphics.GAL
bool supports3DTextureCompression,
bool supportsBgraFormat,
bool supportsR4G4Format,
bool supportsSnormBufferTextureFormat,
bool supportsFragmentShaderInterlock,
bool supportsFragmentShaderOrderingIntel,
bool supportsGeometryShaderPassthrough,
@@ -84,6 +86,7 @@ namespace Ryujinx.Graphics.GAL
Supports3DTextureCompression = supports3DTextureCompression;
SupportsBgraFormat = supportsBgraFormat;
SupportsR4G4Format = supportsR4G4Format;
SupportsSnormBufferTextureFormat = supportsSnormBufferTextureFormat;
SupportsFragmentShaderInterlock = supportsFragmentShaderInterlock;
SupportsFragmentShaderOrderingIntel = supportsFragmentShaderOrderingIntel;
SupportsGeometryShaderPassthrough = supportsGeometryShaderPassthrough;

View File

@@ -1,32 +1,4 @@
using System;
namespace Ryujinx.Graphics.GAL
{
public struct ColorF : IEquatable<ColorF>
{
public float Red { get; }
public float Green { get; }
public float Blue { get; }
public float Alpha { get; }
public ColorF(float red, float green, float blue, float alpha)
{
Red = red;
Green = green;
Blue = blue;
Alpha = alpha;
}
public bool Equals(ColorF color) => Red == color.Red &&
Green == color.Green &&
Blue == color.Blue &&
Alpha == color.Alpha;
public override bool Equals(object obj) => (obj is ColorF color) && Equals(color);
public override int GetHashCode() => HashCode.Combine(Red, Green, Blue, Alpha);
public static bool operator ==(ColorF l, ColorF r) => l.Equals(r);
public static bool operator !=(ColorF l, ColorF r) => !l.Equals(r);
}
public readonly record struct ColorF(float Red, float Green, float Blue, float Alpha);
}

View File

@@ -1,6 +1,6 @@
namespace Ryujinx.Graphics.GAL
{
public struct DepthTestDescriptor
public readonly struct DepthTestDescriptor
{
public bool TestEnable { get; }
public bool WriteEnable { get; }

View File

@@ -1,6 +1,6 @@
namespace Ryujinx.Graphics.GAL
{
public struct DeviceInfo
public readonly struct DeviceInfo
{
public readonly string Id;
public readonly string Vendor;

View File

@@ -2,7 +2,7 @@ using Ryujinx.Common;
namespace Ryujinx.Graphics.GAL
{
public struct Extents2D
public readonly struct Extents2D
{
public int X1 { get; }
public int Y1 { get; }

View File

@@ -1,6 +1,6 @@
namespace Ryujinx.Graphics.GAL
{
public struct Extents2DF
public readonly struct Extents2DF
{
public float X1 { get; }
public float Y1 { get; }

View File

@@ -1,6 +1,6 @@
namespace Ryujinx.Graphics.GAL
{
public struct HardwareInfo
public readonly struct HardwareInfo
{
public string GpuVendor { get; }
public string GpuModel { get; }

View File

@@ -1,6 +1,6 @@
namespace Ryujinx.Graphics.GAL
{
public struct ImageCrop
public readonly struct ImageCrop
{
public int Left { get; }
public int Right { get; }

View File

@@ -1,6 +1,6 @@
namespace Ryujinx.Graphics.GAL
{
public struct MultisampleDescriptor
public readonly struct MultisampleDescriptor
{
public bool AlphaToCoverageEnable { get; }
public bool AlphaToCoverageDitherEnable { get; }

View File

@@ -6,7 +6,7 @@ namespace Ryujinx.Graphics.GAL
/// <summary>
/// Descriptor for a pipeline buffer binding.
/// </summary>
public struct BufferPipelineDescriptor
public readonly struct BufferPipelineDescriptor
{
public bool Enable { get; }
public int Stride { get; }

View File

@@ -1,6 +1,6 @@
namespace Ryujinx.Graphics.GAL
{
public struct Rectangle<T> where T : unmanaged
public readonly struct Rectangle<T> where T : unmanaged
{
public T X { get; }
public T Y { get; }

View File

@@ -1,6 +1,6 @@
namespace Ryujinx.Graphics.GAL
{
public struct SamplerCreateInfo
public readonly struct SamplerCreateInfo
{
public MinFilter MinFilter { get; }
public MagFilter MagFilter { get; }

View File

@@ -1,6 +1,6 @@
namespace Ryujinx.Graphics.GAL
{
public struct ScreenCaptureImageInfo
public readonly struct ScreenCaptureImageInfo
{
public ScreenCaptureImageInfo(int width, int height, bool isBgra, byte[] data, bool flipX, bool flipY)
{

View File

@@ -2,7 +2,7 @@
namespace Ryujinx.Graphics.GAL
{
public struct ShaderBindings
public readonly struct ShaderBindings
{
public IReadOnlyCollection<int> UniformBufferBindings { get; }
public IReadOnlyCollection<int> StorageBufferBindings { get; }

View File

@@ -3,7 +3,7 @@ using Ryujinx.Graphics.Shader.Translation;
namespace Ryujinx.Graphics.GAL
{
public struct ShaderSource
public readonly struct ShaderSource
{
public string Code { get; }
public byte[] BinaryCode { get; }

View File

@@ -1,6 +1,6 @@
namespace Ryujinx.Graphics.GAL
{
public struct StencilTestDescriptor
public readonly struct StencilTestDescriptor
{
public bool TestEnable { get; }

View File

@@ -4,7 +4,7 @@ using System.Numerics;
namespace Ryujinx.Graphics.GAL
{
public struct TextureCreateInfo : IEquatable<TextureCreateInfo>
public readonly struct TextureCreateInfo : IEquatable<TextureCreateInfo>
{
public int Width { get; }
public int Height { get; }
@@ -62,42 +62,42 @@ namespace Ryujinx.Graphics.GAL
SwizzleA = swizzleA;
}
public readonly int GetMipSize(int level)
public int GetMipSize(int level)
{
return GetMipStride(level) * GetLevelHeight(level) * GetLevelDepth(level);
}
public readonly int GetMipSize2D(int level)
public int GetMipSize2D(int level)
{
return GetMipStride(level) * GetLevelHeight(level);
}
public readonly int GetMipStride(int level)
public int GetMipStride(int level)
{
return BitUtils.AlignUp(GetLevelWidth(level) * BytesPerPixel, 4);
}
private readonly int GetLevelWidth(int level)
private int GetLevelWidth(int level)
{
return BitUtils.DivRoundUp(GetLevelSize(Width, level), BlockWidth);
}
private readonly int GetLevelHeight(int level)
private int GetLevelHeight(int level)
{
return BitUtils.DivRoundUp(GetLevelSize(Height, level), BlockHeight);
}
private readonly int GetLevelDepth(int level)
private int GetLevelDepth(int level)
{
return Target == Target.Texture3D ? GetLevelSize(Depth, level) : GetLayers();
}
public readonly int GetDepthOrLayers()
public int GetDepthOrLayers()
{
return Target == Target.Texture3D ? Depth : GetLayers();
}
public readonly int GetLayers()
public int GetLayers()
{
if (Target == Target.Texture2DArray ||
Target == Target.Texture2DMultisampleArray ||
@@ -113,7 +113,7 @@ namespace Ryujinx.Graphics.GAL
return 1;
}
public readonly int GetLevelsClamped()
public int GetLevelsClamped()
{
int maxSize = Width;

View File

@@ -1,40 +1,4 @@
using System;
namespace Ryujinx.Graphics.GAL
{
public struct VertexAttribDescriptor : IEquatable<VertexAttribDescriptor>
{
public int BufferIndex { get; }
public int Offset { get; }
public bool IsZero { get; }
public Format Format { get; }
public VertexAttribDescriptor(int bufferIndex, int offset, bool isZero, Format format)
{
BufferIndex = bufferIndex;
Offset = offset;
IsZero = isZero;
Format = format;
}
public override bool Equals(object obj)
{
return obj is VertexAttribDescriptor other && Equals(other);
}
public bool Equals(VertexAttribDescriptor other)
{
return BufferIndex == other.BufferIndex &&
Offset == other.Offset &&
IsZero == other.IsZero &&
Format == other.Format;
}
public override int GetHashCode()
{
return HashCode.Combine(BufferIndex, Offset, IsZero, Format);
}
}
public readonly record struct VertexAttribDescriptor(int BufferIndex, int Offset, bool IsZero, Format Format);
}

View File

@@ -1,6 +1,6 @@
namespace Ryujinx.Graphics.GAL
{
public struct VertexBufferDescriptor
public readonly struct VertexBufferDescriptor
{
public BufferRange Buffer { get; }

View File

@@ -1,6 +1,6 @@
namespace Ryujinx.Graphics.GAL
{
public struct Viewport
public readonly struct Viewport
{
public Rectangle<float> Region { get; }

View File

@@ -202,57 +202,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
_channel.BufferManager.SetComputeUniformBuffer(cb.Slot, cbDescriptor.PackAddress(), (uint)cbDescriptor.Size);
}
_channel.BufferManager.SetComputeStorageBufferBindings(info.SBuffers);
_channel.BufferManager.SetComputeUniformBufferBindings(info.CBuffers);
_channel.BufferManager.SetComputeBufferBindings(cs.Bindings);
int maxTextureBinding = -1;
int maxImageBinding = -1;
TextureBindingInfo[] textureBindings = _channel.TextureManager.RentComputeTextureBindings(info.Textures.Count);
for (int index = 0; index < info.Textures.Count; index++)
{
var descriptor = info.Textures[index];
Target target = ShaderTexture.GetTarget(descriptor.Type);
textureBindings[index] = new TextureBindingInfo(
target,
descriptor.Binding,
descriptor.CbufSlot,
descriptor.HandleIndex,
descriptor.Flags);
if (descriptor.Binding > maxTextureBinding)
{
maxTextureBinding = descriptor.Binding;
}
}
TextureBindingInfo[] imageBindings = _channel.TextureManager.RentComputeImageBindings(info.Images.Count);
for (int index = 0; index < info.Images.Count; index++)
{
var descriptor = info.Images[index];
Target target = ShaderTexture.GetTarget(descriptor.Type);
Format format = ShaderTexture.GetFormat(descriptor.Format);
imageBindings[index] = new TextureBindingInfo(
target,
format,
descriptor.Binding,
descriptor.CbufSlot,
descriptor.HandleIndex,
descriptor.Flags);
if (descriptor.Binding > maxImageBinding)
{
maxImageBinding = descriptor.Binding;
}
}
_channel.TextureManager.SetComputeMaxBindings(maxTextureBinding, maxImageBinding);
_channel.TextureManager.SetComputeBindings(cs.Bindings);
// Should never return false for mismatching spec state, since the shader was fetched above.
_channel.TextureManager.CommitComputeBindings(cs.SpecializationState);

View File

@@ -7,7 +7,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
/// <summary>
/// FIFO word.
/// </summary>
struct FifoWord
readonly struct FifoWord
{
/// <summary>
/// GPU virtual address where the word is located in memory.

View File

@@ -13,7 +13,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
/// <summary>
/// Macroo High-level implementation table entry.
/// </summary>
struct TableEntry
readonly struct TableEntry
{
/// <summary>
/// Name of the Macro function.

View File

@@ -19,6 +19,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
private readonly GpuChannel _channel;
private readonly DeviceStateWithShadow<ThreedClassState> _state;
private readonly DrawState _drawState;
private readonly SpecializationStateUpdater _currentSpecState;
private bool _topologySet;
private bool _instancedDrawPending;
@@ -44,12 +45,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// <param name="channel">GPU channel</param>
/// <param name="state">Channel state</param>
/// <param name="drawState">Draw state</param>
public DrawManager(GpuContext context, GpuChannel channel, DeviceStateWithShadow<ThreedClassState> state, DrawState drawState)
/// <param name="spec">Specialization state updater</param>
public DrawManager(GpuContext context, GpuChannel channel, DeviceStateWithShadow<ThreedClassState> state, DrawState drawState, SpecializationStateUpdater spec)
{
_context = context;
_channel = channel;
_state = state;
_drawState = drawState;
_currentSpecState = spec;
}
/// <summary>
@@ -132,6 +135,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_drawState.FirstIndex = firstIndex;
_drawState.IndexCount = indexCount;
_currentSpecState.SetHasConstantBufferDrawParameters(false);
engine.UpdateState();
@@ -256,6 +260,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
if (_drawState.Topology != topology || !_topologySet)
{
_context.Renderer.Pipeline.SetPrimitiveTopology(topology);
_currentSpecState.SetTopology(topology);
_drawState.Topology = topology;
_topologySet = true;
}
@@ -452,7 +457,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_state.State.FirstInstance = (uint)firstInstance;
_drawState.DrawIndexed = indexed;
_drawState.HasConstantBufferDrawParameters = true;
_currentSpecState.SetHasConstantBufferDrawParameters(true);
engine.UpdateState();
@@ -469,7 +474,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_state.State.FirstInstance = 0;
_drawState.DrawIndexed = false;
_drawState.HasConstantBufferDrawParameters = false;
if (renderEnable == ConditionalRenderEnabled.Host)
{
@@ -527,7 +531,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_drawState.DrawIndexed = indexed;
_drawState.DrawIndirect = true;
_drawState.HasConstantBufferDrawParameters = true;
_currentSpecState.SetHasConstantBufferDrawParameters(true);
engine.UpdateState();
@@ -561,7 +565,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_drawState.DrawIndexed = false;
_drawState.DrawIndirect = false;
_drawState.HasConstantBufferDrawParameters = false;
if (renderEnable == ConditionalRenderEnabled.Host)
{

View File

@@ -0,0 +1,280 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Shader;
using Ryujinx.Graphics.Shader;
namespace Ryujinx.Graphics.Gpu.Engine.Threed
{
/// <summary>
/// Maintains a "current" specialiation state, and provides a flag to check if it has changed meaningfully.
/// </summary>
internal class SpecializationStateUpdater
{
private GpuChannelGraphicsState _graphics;
private GpuChannelPoolState _pool;
private bool _usesDrawParameters;
private bool _usesTopology;
private bool _changed;
/// <summary>
/// Signal that the specialization state has changed.
/// </summary>
private void Signal()
{
_changed = true;
}
/// <summary>
/// Checks if the specialization state has changed since the last check.
/// </summary>
/// <returns>True if it has changed, false otherwise</returns>
public bool HasChanged()
{
if (_changed)
{
_changed = false;
return true;
}
else
{
return false;
}
}
/// <summary>
/// Sets the active shader, clearing the dirty state and recording if certain specializations are noteworthy.
/// </summary>
/// <param name="gs">The active shader</param>
public void SetShader(CachedShaderProgram gs)
{
_usesDrawParameters = gs.Shaders[1]?.Info.UsesDrawParameters ?? false;
_usesTopology = gs.SpecializationState.IsPrimitiveTopologyQueried();
_changed = false;
}
/// <summary>
/// Get the current graphics state.
/// </summary>
/// <returns>GPU graphics state</returns>
public ref GpuChannelGraphicsState GetGraphicsState()
{
return ref _graphics;
}
/// <summary>
/// Get the current pool state.
/// </summary>
/// <returns>GPU pool state</returns>
public ref GpuChannelPoolState GetPoolState()
{
return ref _pool;
}
/// <summary>
/// Early Z force enable.
/// </summary>
/// <param name="value">The new value</param>
public void SetEarlyZForce(bool value)
{
_graphics.EarlyZForce = value;
Signal();
}
/// <summary>
/// Primitive topology of current draw.
/// </summary>
/// <param name="value">The new value</param>
public void SetTopology(PrimitiveTopology value)
{
if (value != _graphics.Topology)
{
_graphics.Topology = value;
if (_usesTopology)
{
Signal();
}
}
}
/// <summary>
/// Tessellation mode.
/// </summary>
/// <param name="value">The new value</param>
public void SetTessellationMode(TessMode value)
{
if (value.Packed != _graphics.TessellationMode.Packed)
{
_graphics.TessellationMode = value;
Signal();
}
}
/// <summary>
/// Updates alpha-to-coverage state, and sets it as changed.
/// </summary>
/// <param name="enable">Whether alpha-to-coverage is enabled</param>
/// <param name="ditherEnable">Whether alpha-to-coverage dithering is enabled</param>
public void SetAlphaToCoverageEnable(bool enable, bool ditherEnable)
{
_graphics.AlphaToCoverageEnable = enable;
_graphics.AlphaToCoverageDitherEnable = ditherEnable;
Signal();
}
/// <summary>
/// Indicates whether the viewport transform is disabled.
/// </summary>
/// <param name="value">The new value</param>
public void SetViewportTransformDisable(bool value)
{
if (value != _graphics.ViewportTransformDisable)
{
_graphics.ViewportTransformDisable = value;
Signal();
}
}
/// <summary>
/// Depth mode zero to one or minus one to one.
/// </summary>
/// <param name="value">The new value</param>
public void SetDepthMode(bool value)
{
if (value != _graphics.DepthMode)
{
_graphics.DepthMode = value;
Signal();
}
}
/// <summary>
/// Indicates if the point size is set on the shader or is fixed.
/// </summary>
/// <param name="value">The new value</param>
public void SetProgramPointSizeEnable(bool value)
{
if (value != _graphics.ProgramPointSizeEnable)
{
_graphics.ProgramPointSizeEnable = value;
Signal();
}
}
/// <summary>
/// Point size used if <see cref="SetProgramPointSizeEnable" /> is provided false.
/// </summary>
/// <param name="value">The new value</param>
public void SetPointSize(float value)
{
if (value != _graphics.PointSize)
{
_graphics.PointSize = value;
Signal();
}
}
/// <summary>
/// Updates alpha test specialization state, and sets it as changed.
/// </summary>
/// <param name="enable">Whether alpha test is enabled</param>
/// <param name="reference">The value to compare with the fragment output alpha</param>
/// <param name="op">The comparison that decides if the fragment should be discarded</param>
public void SetAlphaTest(bool enable, float reference, CompareOp op)
{
_graphics.AlphaTestEnable = enable;
_graphics.AlphaTestReference = reference;
_graphics.AlphaTestCompare = op;
Signal();
}
/// <summary>
/// Updates the type of the vertex attributes consumed by the shader.
/// </summary>
/// <param name="state">The new state</param>
public void SetAttributeTypes(ref Array32<VertexAttribState> state)
{
bool changed = false;
ref Array32<AttributeType> attributeTypes = ref _graphics.AttributeTypes;
for (int location = 0; location < state.Length; location++)
{
VertexAttribType type = state[location].UnpackType();
AttributeType value = type switch
{
VertexAttribType.Sint => AttributeType.Sint,
VertexAttribType.Uint => AttributeType.Uint,
_ => AttributeType.Float
};
if (attributeTypes[location] != value)
{
attributeTypes[location] = value;
changed = true;
}
}
if (changed)
{
Signal();
}
}
/// <summary>
/// Indicates that the draw is writing the base vertex, base instance and draw index to Constant Buffer 0.
/// </summary>
/// <param name="value">The new value</param>
public void SetHasConstantBufferDrawParameters(bool value)
{
if (value != _graphics.HasConstantBufferDrawParameters)
{
_graphics.HasConstantBufferDrawParameters = value;
if (_usesDrawParameters)
{
Signal();
}
}
}
/// <summary>
/// Indicates that any storage buffer use is unaligned.
/// </summary>
/// <param name="value">The new value</param>
public void SetHasUnalignedStorageBuffer(bool value)
{
if (value != _graphics.HasUnalignedStorageBuffer)
{
_graphics.HasUnalignedStorageBuffer = value;
Signal();
}
}
/// <summary>
/// Sets the GPU pool state.
/// </summary>
/// <param name="state">The new state</param>
public void SetPoolState(GpuChannelPoolState state)
{
if (!state.Equals(_pool))
{
_pool = state;
Signal();
}
}
}
}

View File

@@ -11,7 +11,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// <summary>
/// State update callback entry, with the callback function and associated field names.
/// </summary>
struct StateUpdateCallbackEntry
readonly struct StateUpdateCallbackEntry
{
/// <summary>
/// Callback function, to be called if the register was written as the state needs to be updated.

View File

@@ -1,6 +1,7 @@
using Ryujinx.Common.Logging;
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Engine.GPFifo;
using Ryujinx.Graphics.Gpu.Engine.Types;
using Ryujinx.Graphics.Gpu.Image;
using Ryujinx.Graphics.Gpu.Shader;
@@ -16,9 +17,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// </summary>
class StateUpdater
{
public const int ShaderStateIndex = 16;
public const int ShaderStateIndex = 26;
public const int RasterizerStateIndex = 15;
public const int ScissorStateIndex = 18;
public const int ScissorStateIndex = 16;
public const int VertexBufferStateIndex = 0;
public const int PrimitiveRestartStateIndex = 12;
@@ -31,6 +32,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
private readonly ShaderProgramInfo[] _currentProgramInfo;
private ShaderSpecializationState _shaderSpecState;
private SpecializationStateUpdater _currentSpecState;
private ProgramPipelineState _pipeline;
@@ -54,15 +56,17 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// <param name="channel">GPU channel</param>
/// <param name="state">3D engine state</param>
/// <param name="drawState">Draw state</param>
public StateUpdater(GpuContext context, GpuChannel channel, DeviceStateWithShadow<ThreedClassState> state, DrawState drawState)
/// <param name="spec">Specialization state updater</param>
public StateUpdater(GpuContext context, GpuChannel channel, DeviceStateWithShadow<ThreedClassState> state, DrawState drawState, SpecializationStateUpdater spec)
{
_context = context;
_channel = channel;
_state = state;
_drawState = drawState;
_currentProgramInfo = new ShaderProgramInfo[Constants.ShaderStages];
_currentSpecState = spec;
// ShaderState must be updated after other state updates, as pipeline state is sent to the backend when compiling new shaders.
// ShaderState must be updated after other state updates, as specialization/pipeline state is used when fetching shaders.
// Render target state must appear after shader state as it depends on information from the currently bound shader.
// Rasterizer and scissor states are checked by render target clear, their indexes
// must be updated on the constants "RasterizerStateIndex" and "ScissorStateIndex" if modified.
@@ -101,6 +105,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
nameof(ThreedClassState.DepthTestFunc)),
new StateUpdateCallbackEntry(UpdateTessellationState,
nameof(ThreedClassState.TessMode),
nameof(ThreedClassState.TessOuterLevel),
nameof(ThreedClassState.TessInnerLevel),
nameof(ThreedClassState.PatchVertices)),
@@ -138,17 +143,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
new StateUpdateCallbackEntry(UpdateRasterizerState, nameof(ThreedClassState.RasterizeEnable)),
new StateUpdateCallbackEntry(UpdateShaderState,
nameof(ThreedClassState.ShaderBaseAddress),
nameof(ThreedClassState.ShaderState)),
new StateUpdateCallbackEntry(UpdateRenderTargetState,
nameof(ThreedClassState.RtColorState),
nameof(ThreedClassState.RtDepthStencilState),
nameof(ThreedClassState.RtControl),
nameof(ThreedClassState.RtDepthStencilSize),
nameof(ThreedClassState.RtDepthStencilEnable)),
new StateUpdateCallbackEntry(UpdateScissorState,
nameof(ThreedClassState.ScissorState),
nameof(ThreedClassState.ScreenScissorState)),
@@ -179,7 +173,21 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
new StateUpdateCallbackEntry(UpdateMultisampleState,
nameof(ThreedClassState.AlphaToCoverageDitherEnable),
nameof(ThreedClassState.MultisampleControl))
nameof(ThreedClassState.MultisampleControl)),
new StateUpdateCallbackEntry(UpdateEarlyZState,
nameof(ThreedClassState.EarlyZForce)),
new StateUpdateCallbackEntry(UpdateShaderState,
nameof(ThreedClassState.ShaderBaseAddress),
nameof(ThreedClassState.ShaderState)),
new StateUpdateCallbackEntry(UpdateRenderTargetState,
nameof(ThreedClassState.RtColorState),
nameof(ThreedClassState.RtDepthStencilState),
nameof(ThreedClassState.RtControl),
nameof(ThreedClassState.RtDepthStencilSize),
nameof(ThreedClassState.RtDepthStencilEnable)),
});
}
@@ -209,17 +217,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Update()
{
// If any state that the shader depends on changed,
// then we may need to compile/bind a different version
// of the shader for the new state.
if (_shaderSpecState != null)
{
if (!_shaderSpecState.MatchesGraphics(_channel, GetPoolState(), GetGraphicsState(), _vsUsesDrawParameters, false))
{
ForceShaderUpdate();
}
}
// The vertex buffer size is calculated using a different
// method when doing indexed draws, so we need to make sure
// to update the vertex buffers if we are doing a regular
@@ -271,6 +268,18 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_updateTracker.Update(ulong.MaxValue);
// If any state that the shader depends on changed,
// then we may need to compile/bind a different version
// of the shader for the new state.
if (_shaderSpecState != null && _currentSpecState.HasChanged())
{
if (!_shaderSpecState.MatchesGraphics(_channel, ref _currentSpecState.GetPoolState(), ref _currentSpecState.GetGraphicsState(), _vsUsesDrawParameters, false))
{
// Shader must be reloaded. _vtgWritesRtLayer should not change.
UpdateShaderState();
}
}
CommitBindings();
if (tfEnable && !_prevTfEnable)
@@ -302,7 +311,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
if (!_channel.TextureManager.CommitGraphicsBindings(_shaderSpecState) || (buffers.HasUnalignedStorageBuffers != hasUnaligned))
{
// Shader must be reloaded.
_currentSpecState.SetHasUnalignedStorageBuffer(buffers.HasUnalignedStorageBuffers);
// Shader must be reloaded. _vtgWritesRtLayer should not change.
UpdateShaderState();
}
@@ -351,6 +361,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_state.State.PatchVertices,
_state.State.TessOuterLevel.AsSpan(),
_state.State.TessInnerLevel.AsSpan());
_currentSpecState.SetTessellationMode(_state.State.TessMode);
}
/// <summary>
@@ -611,6 +623,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_state.State.AlphaTestEnable,
_state.State.AlphaTestRef,
_state.State.AlphaTestFunc);
_currentSpecState.SetAlphaTest(
_state.State.AlphaTestEnable,
_state.State.AlphaTestRef,
_state.State.AlphaTestFunc);
}
/// <summary>
@@ -710,6 +727,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_context.Renderer.Pipeline.SetDepthMode(GetDepthMode());
_context.Renderer.Pipeline.SetViewports(viewports, disableTransform);
_currentSpecState.SetViewportTransformDisable(_state.State.ViewportTransformEnable == 0);
_currentSpecState.SetDepthMode(GetDepthMode() == DepthMode.MinusOneToOne);
}
/// <summary>
@@ -847,6 +867,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_channel.TextureManager.SetGraphicsTexturePool(texturePool.Address.Pack(), texturePool.MaximumId);
_channel.TextureManager.SetGraphicsTextureBufferIndex((int)_state.State.TextureBufferIndex);
_currentSpecState.SetPoolState(GetPoolState());
}
/// <summary>
@@ -887,6 +909,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_pipeline.SetVertexAttribs(vertexAttribs);
_context.Renderer.Pipeline.SetVertexAttribs(vertexAttribs);
_currentSpecState.SetAttributeTypes(ref _state.State.VertexAttribState);
}
/// <summary>
@@ -914,6 +937,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
Origin origin = (_state.State.PointCoordReplace & 4) == 0 ? Origin.LowerLeft : Origin.UpperLeft;
_context.Renderer.Pipeline.SetPointParameters(size, isProgramPointSize, enablePointSprite, origin);
_currentSpecState.SetProgramPointSizeEnable(isProgramPointSize);
_currentSpecState.SetPointSize(size);
}
/// <summary>
@@ -1212,6 +1238,16 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
alphaToCoverageEnable,
_state.State.AlphaToCoverageDitherEnable,
alphaToOneEnable));
_currentSpecState.SetAlphaToCoverageEnable(alphaToCoverageEnable, _state.State.AlphaToCoverageDitherEnable);
}
/// <summary>
/// Updates the early z flag, based on guest state.
/// </summary>
private void UpdateEarlyZState()
{
_currentSpecState.SetEarlyZForce(_state.State.EarlyZForce);
}
/// <summary>
@@ -1239,10 +1275,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
addressesSpan[index] = baseAddress + shader.Offset;
}
GpuChannelPoolState poolState = GetPoolState();
GpuChannelGraphicsState graphicsState = GetGraphicsState();
CachedShaderProgram gs = shaderCache.GetGraphicsShader(ref _state.State, ref _pipeline, _channel, ref _currentSpecState.GetPoolState(), ref _currentSpecState.GetGraphicsState(), addresses);
CachedShaderProgram gs = shaderCache.GetGraphicsShader(ref _state.State, ref _pipeline, _channel, poolState, graphicsState, addresses);
// Consume the modified flag for spec state so that it isn't checked again.
_currentSpecState.SetShader(gs);
_shaderSpecState = gs.SpecializationState;
@@ -1257,88 +1293,24 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
UpdateUserClipState();
}
UpdateShaderBindings(gs.Bindings);
for (int stageIndex = 0; stageIndex < Constants.ShaderStages; stageIndex++)
{
UpdateStageBindings(stageIndex, gs.Shaders[stageIndex + 1]?.Info);
_currentProgramInfo[stageIndex] = gs.Shaders[stageIndex + 1]?.Info;
}
_context.Renderer.Pipeline.SetProgram(gs.HostProgram);
}
/// <summary>
/// Updates bindings consumed by the shader stage on the texture and buffer managers.
/// Updates bindings consumed by the shader on the texture and buffer managers.
/// </summary>
/// <param name="stage">Shader stage to have the bindings updated</param>
/// <param name="info">Shader stage bindings info</param>
private void UpdateStageBindings(int stage, ShaderProgramInfo info)
/// <param name="bindings">Bindings for the active shader</param>
private void UpdateShaderBindings(CachedShaderBindings bindings)
{
_currentProgramInfo[stage] = info;
if (info == null)
{
_channel.TextureManager.RentGraphicsTextureBindings(stage, 0);
_channel.TextureManager.RentGraphicsImageBindings(stage, 0);
_channel.BufferManager.SetGraphicsStorageBufferBindings(stage, null);
_channel.BufferManager.SetGraphicsUniformBufferBindings(stage, null);
return;
}
int maxTextureBinding = -1;
int maxImageBinding = -1;
Span<TextureBindingInfo> textureBindings = _channel.TextureManager.RentGraphicsTextureBindings(stage, info.Textures.Count);
if (info.UsesRtLayer)
{
_vtgWritesRtLayer = true;
}
for (int index = 0; index < info.Textures.Count; index++)
{
var descriptor = info.Textures[index];
Target target = ShaderTexture.GetTarget(descriptor.Type);
textureBindings[index] = new TextureBindingInfo(
target,
descriptor.Binding,
descriptor.CbufSlot,
descriptor.HandleIndex,
descriptor.Flags);
if (descriptor.Binding > maxTextureBinding)
{
maxTextureBinding = descriptor.Binding;
}
}
TextureBindingInfo[] imageBindings = _channel.TextureManager.RentGraphicsImageBindings(stage, info.Images.Count);
for (int index = 0; index < info.Images.Count; index++)
{
var descriptor = info.Images[index];
Target target = ShaderTexture.GetTarget(descriptor.Type);
Format format = ShaderTexture.GetFormat(descriptor.Format);
imageBindings[index] = new TextureBindingInfo(
target,
format,
descriptor.Binding,
descriptor.CbufSlot,
descriptor.HandleIndex,
descriptor.Flags);
if (descriptor.Binding > maxImageBinding)
{
maxImageBinding = descriptor.Binding;
}
}
_channel.TextureManager.SetGraphicsMaxBindings(maxTextureBinding, maxImageBinding);
_channel.BufferManager.SetGraphicsStorageBufferBindings(stage, info.SBuffers);
_channel.BufferManager.SetGraphicsUniformBufferBindings(stage, info.CBuffers);
_channel.TextureManager.SetGraphicsBindings(bindings);
_channel.BufferManager.SetGraphicsBufferBindings(bindings);
}
/// <summary>
@@ -1353,46 +1325,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
(int)_state.State.TextureBufferIndex);
}
/// <summary>
/// Gets the current GPU channel state for shader creation or compatibility verification.
/// </summary>
/// <returns>Current GPU channel state</returns>
private GpuChannelGraphicsState GetGraphicsState()
{
ref var vertexAttribState = ref _state.State.VertexAttribState;
Array32<AttributeType> attributeTypes = new Array32<AttributeType>();
for (int location = 0; location < attributeTypes.Length; location++)
{
VertexAttribType type = vertexAttribState[location].UnpackType();
attributeTypes[location] = type switch
{
VertexAttribType.Sint => AttributeType.Sint,
VertexAttribType.Uint => AttributeType.Uint,
_ => AttributeType.Float
};
}
return new GpuChannelGraphicsState(
_state.State.EarlyZForce,
_drawState.Topology,
_state.State.TessMode,
(_state.State.MultisampleControl & 1) != 0,
_state.State.AlphaToCoverageDitherEnable,
_state.State.ViewportTransformEnable == 0,
GetDepthMode() == DepthMode.MinusOneToOne,
_state.State.VertexProgramPointSize,
_state.State.PointSize,
_state.State.AlphaTestEnable,
_state.State.AlphaTestFunc,
_state.State.AlphaTestRef,
ref attributeTypes,
_drawState.HasConstantBufferDrawParameters,
_channel.BufferManager.HasUnalignedStorageBuffers);
}
/// <summary>
/// Gets the depth mode that is currently being used (zero to one or minus one to one).
/// </summary>

View File

@@ -67,12 +67,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_i2mClass = new InlineToMemoryClass(context, channel, initializeState: false);
var spec = new SpecializationStateUpdater();
var drawState = new DrawState();
_drawManager = new DrawManager(context, channel, _state, drawState);
_drawManager = new DrawManager(context, channel, _state, drawState, spec);
_semaphoreUpdater = new SemaphoreUpdater(context, channel, _state);
_cbUpdater = new ConstantBufferUpdater(channel, _state);
_stateUpdater = new StateUpdater(context, channel, _state, drawState);
_stateUpdater = new StateUpdater(context, channel, _state, drawState, spec);
// This defaults to "always", even without any register write.
// Reads just return 0, regardless of what was set there.

View File

@@ -5,7 +5,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <summary>
/// Represents texture format information.
/// </summary>
struct FormatInfo
readonly struct FormatInfo
{
/// <summary>
/// A default, generic RGBA8 texture format.

View File

@@ -7,7 +7,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Texture binding information.
/// This is used for textures that needs to be accessed from shaders.
/// </summary>
struct TextureBindingInfo
readonly struct TextureBindingInfo
{
/// <summary>
/// Shader sampler target type.

View File

@@ -37,8 +37,8 @@ namespace Ryujinx.Graphics.Gpu.Image
private TexturePool _cachedTexturePool;
private SamplerPool _cachedSamplerPool;
private readonly TextureBindingInfo[][] _textureBindings;
private readonly TextureBindingInfo[][] _imageBindings;
private TextureBindingInfo[][] _textureBindings;
private TextureBindingInfo[][] _imageBindings;
private struct TextureState
{
@@ -56,9 +56,6 @@ namespace Ryujinx.Graphics.Gpu.Image
private TextureState[] _textureState;
private TextureState[] _imageState;
private int[] _textureBindingsCount;
private int[] _imageBindingsCount;
private int _texturePoolSequence;
private int _samplerPoolSequence;
@@ -101,9 +98,6 @@ namespace Ryujinx.Graphics.Gpu.Image
_textureState = new TextureState[InitialTextureStateSize];
_imageState = new TextureState[InitialImageStateSize];
_textureBindingsCount = new int[stages];
_imageBindingsCount = new int[stages];
for (int stage = 0; stage < stages; stage++)
{
_textureBindings[stage] = new TextureBindingInfo[InitialTextureStateSize];
@@ -112,39 +106,15 @@ namespace Ryujinx.Graphics.Gpu.Image
}
/// <summary>
/// Rents the texture bindings array for a given stage, so that they can be modified.
/// Sets the texture and image bindings.
/// </summary>
/// <param name="stage">Shader stage number, or 0 for compute shaders</param>
/// <param name="count">The number of bindings needed</param>
/// <returns>The texture bindings array</returns>
public TextureBindingInfo[] RentTextureBindings(int stage, int count)
/// <param name="bindings">Bindings for the active shader</param>
public void SetBindings(CachedShaderBindings bindings)
{
if (count > _textureBindings[stage].Length)
{
Array.Resize(ref _textureBindings[stage], count);
}
_textureBindings = bindings.TextureBindings;
_imageBindings = bindings.ImageBindings;
_textureBindingsCount[stage] = count;
return _textureBindings[stage];
}
/// <summary>
/// Rents the image bindings array for a given stage, so that they can be modified.
/// </summary>
/// <param name="stage">Shader stage number, or 0 for compute shaders</param>
/// <param name="count">The number of bindings needed</param>
/// <returns>The image bindings array</returns>
public TextureBindingInfo[] RentImageBindings(int stage, int count)
{
if (count > _imageBindings[stage].Length)
{
Array.Resize(ref _imageBindings[stage], count);
}
_imageBindingsCount[stage] = count;
return _imageBindings[stage];
SetMaxBindings(bindings.MaxTextureBinding, bindings.MaxImageBinding);
}
/// <summary>
@@ -257,7 +227,7 @@ namespace Ryujinx.Graphics.Gpu.Image
case ShaderStage.Vertex:
int fragmentIndex = (int)ShaderStage.Fragment - 1;
index += _textureBindingsCount[fragmentIndex] + _imageBindingsCount[fragmentIndex];
index += _textureBindings[fragmentIndex].Length + _imageBindings[fragmentIndex].Length;
result = texture.ScaleFactor;
break;
@@ -284,7 +254,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// </summary>
private bool VertexRequiresScale()
{
for (int i = 0; i < _textureBindingsCount[0]; i++)
for (int i = 0; i < _textureBindings[0].Length; i++)
{
if ((_textureBindings[0][i].Flags & TextureUsageFlags.NeedsScaleValue) != 0)
{
@@ -292,7 +262,7 @@ namespace Ryujinx.Graphics.Gpu.Image
}
}
for (int i = 0; i < _imageBindingsCount[0]; i++)
for (int i = 0; i < _imageBindings[0].Length; i++)
{
if ((_imageBindings[0][i].Flags & TextureUsageFlags.NeedsScaleValue) != 0)
{
@@ -309,10 +279,10 @@ namespace Ryujinx.Graphics.Gpu.Image
private void CommitRenderScale()
{
// Stage 0 total: Compute or Vertex.
int total = _textureBindingsCount[0] + _imageBindingsCount[0];
int total = _textureBindings[0].Length + _imageBindings[0].Length;
int fragmentIndex = (int)ShaderStage.Fragment - 1;
int fragmentTotal = _isCompute ? 0 : (_textureBindingsCount[fragmentIndex] + _imageBindingsCount[fragmentIndex]);
int fragmentTotal = _isCompute ? 0 : (_textureBindings[fragmentIndex].Length + _imageBindings[fragmentIndex].Length);
if (total != 0 && fragmentTotal != _lastFragmentTotal && VertexRequiresScale())
{
@@ -481,7 +451,7 @@ namespace Ryujinx.Graphics.Gpu.Image
bool poolModified,
ShaderSpecializationState specState)
{
int textureCount = _textureBindingsCount[stageIndex];
int textureCount = _textureBindings[stageIndex].Length;
if (textureCount == 0)
{
return true;
@@ -609,7 +579,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <returns>True if all bound images match the current shader specialiation state, false otherwise</returns>
private bool CommitImageBindings(TexturePool pool, ShaderStage stage, int stageIndex, bool poolModified, ShaderSpecializationState specState)
{
int imageCount = _imageBindingsCount[stageIndex];
int imageCount = _imageBindings[stageIndex].Length;
if (imageCount == 0)
{
return true;
@@ -622,7 +592,7 @@ namespace Ryujinx.Graphics.Gpu.Image
}
// Scales for images appear after the texture ones.
int baseScaleIndex = _textureBindingsCount[stageIndex];
int baseScaleIndex = _textureBindings[stageIndex].Length;
int cachedTextureBufferIndex = -1;
int cachedSamplerBufferIndex = -1;

View File

@@ -16,7 +16,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// </summary>
class TextureCache : IDisposable
{
private struct OverlapInfo
private readonly struct OverlapInfo
{
public TextureViewCompatibility Compatibility { get; }
public int FirstLayer { get; }
@@ -1088,10 +1088,9 @@ namespace Ryujinx.Graphics.Gpu.Image
{
FormatInfo formatInfo = TextureCompatibility.ToHostCompatibleFormat(info, caps);
if (info.Target == Target.TextureBuffer)
if (info.Target == Target.TextureBuffer && !caps.SupportsSnormBufferTextureFormat)
{
// We assume that the host does not support signed normalized format
// (as is the case with OpenGL), so we just use a unsigned format.
// If the host does not support signed normalized formats, we use a signed integer format instead.
// The shader will need the appropriate conversion code to compensate.
switch (formatInfo.Format)
{

View File

@@ -14,7 +14,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <summary>
/// An overlapping texture group with a given view compatibility.
/// </summary>
struct TextureIncompatibleOverlap
readonly struct TextureIncompatibleOverlap
{
public readonly TextureGroup Group;
public readonly TextureViewCompatibility Compatibility;

View File

@@ -6,7 +6,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <summary>
/// Texture information.
/// </summary>
struct TextureInfo
readonly struct TextureInfo
{
/// <summary>
/// Address of the texture in GPU mapped memory.

View File

@@ -57,45 +57,21 @@ namespace Ryujinx.Graphics.Gpu.Image
}
/// <summary>
/// Rents the texture bindings array of the compute pipeline.
/// Sets the texture and image bindings for the compute pipeline.
/// </summary>
/// <param name="count">The number of bindings needed</param>
/// <returns>The texture bindings array</returns>
public TextureBindingInfo[] RentComputeTextureBindings(int count)
/// <param name="bindings">Bindings for the active shader</param>
public void SetComputeBindings(CachedShaderBindings bindings)
{
return _cpBindingsManager.RentTextureBindings(0, count);
_cpBindingsManager.SetBindings(bindings);
}
/// <summary>
/// Rents the texture bindings array for a given stage on the graphics pipeline.
/// Sets the texture and image bindings for the graphics pipeline.
/// </summary>
/// <param name="stage">The index of the shader stage to bind the textures</param>
/// <param name="count">The number of bindings needed</param>
/// <returns>The texture bindings array</returns>
public TextureBindingInfo[] RentGraphicsTextureBindings(int stage, int count)
/// <param name="bindings">Bindings for the active shader</param>
public void SetGraphicsBindings(CachedShaderBindings bindings)
{
return _gpBindingsManager.RentTextureBindings(stage, count);
}
/// <summary>
/// Rents the image bindings array of the compute pipeline.
/// </summary>
/// <param name="count">The number of bindings needed</param>
/// <returns>The image bindings array</returns>
public TextureBindingInfo[] RentComputeImageBindings(int count)
{
return _cpBindingsManager.RentImageBindings(0, count);
}
/// <summary>
/// Rents the image bindings array for a given stage on the graphics pipeline.
/// </summary>
/// <param name="stage">The index of the shader stage to bind the images</param>
/// <param name="count">The number of bindings needed</param>
/// <returns>The image bindings array</returns>
public TextureBindingInfo[] RentGraphicsImageBindings(int stage, int count)
{
return _gpBindingsManager.RentImageBindings(stage, count);
_gpBindingsManager.SetBindings(bindings);
}
/// <summary>
@@ -107,16 +83,6 @@ namespace Ryujinx.Graphics.Gpu.Image
_cpBindingsManager.SetTextureBufferIndex(index);
}
/// <summary>
/// Sets the max binding indexes on the compute pipeline.
/// </summary>
/// <param name="maxTextureBinding">The maximum texture binding</param>
/// <param name="maxImageBinding">The maximum image binding</param>
public void SetComputeMaxBindings(int maxTextureBinding, int maxImageBinding)
{
_cpBindingsManager.SetMaxBindings(maxTextureBinding, maxImageBinding);
}
/// <summary>
/// Sets the texture constant buffer index on the graphics pipeline.
/// </summary>
@@ -126,16 +92,6 @@ namespace Ryujinx.Graphics.Gpu.Image
_gpBindingsManager.SetTextureBufferIndex(index);
}
/// <summary>
/// Sets the max binding indexes on the graphics pipeline.
/// </summary>
/// <param name="maxTextureBinding">The maximum texture binding</param>
/// <param name="maxImageBinding">The maximum image binding</param>
public void SetGraphicsMaxBindings(int maxTextureBinding, int maxImageBinding)
{
_gpBindingsManager.SetMaxBindings(maxTextureBinding, maxImageBinding);
}
/// <summary>
/// Sets the current sampler pool on the compute pipeline.
/// </summary>

View File

@@ -5,7 +5,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <summary>
/// Memory range used for buffers.
/// </summary>
struct BufferBounds
readonly struct BufferBounds
{
/// <summary>
/// Region virtual address.

View File

@@ -1,10 +1,10 @@
using Ryujinx.Common;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Image;
using Ryujinx.Graphics.Gpu.Shader;
using Ryujinx.Graphics.Shader;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime.CompilerServices;
namespace Ryujinx.Graphics.Gpu.Memory
@@ -34,7 +34,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <summary>
/// Shader buffer binding information.
/// </summary>
public BufferDescriptor[] Bindings { get; }
public BufferDescriptor[] Bindings { get; private set; }
/// <summary>
/// Buffer regions.
@@ -78,7 +78,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// Sets shader buffer binding information.
/// </summary>
/// <param name="descriptors">Buffer binding information</param>
public void SetBindings(ReadOnlyCollection<BufferDescriptor> descriptors)
public void SetBindings(BufferDescriptor[] descriptors)
{
if (descriptors == null)
{
@@ -86,8 +86,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
return;
}
descriptors.CopyTo(Bindings, 0);
Count = descriptors.Count;
if ((Count = descriptors.Length) != 0)
{
Bindings = descriptors;
}
}
}
@@ -320,41 +322,26 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <summary>
/// Sets the binding points for the storage buffers bound on the compute pipeline.
/// </summary>
/// <param name="descriptors">Buffer descriptors with the binding point values</param>
public void SetComputeStorageBufferBindings(ReadOnlyCollection<BufferDescriptor> descriptors)
/// <param name="bindings">Bindings for the active shader</param>
public void SetComputeBufferBindings(CachedShaderBindings bindings)
{
_cpStorageBuffers.SetBindings(descriptors);
_cpStorageBuffers.SetBindings(bindings.StorageBufferBindings[0]);
_cpUniformBuffers.SetBindings(bindings.ConstantBufferBindings[0]);
}
/// <summary>
/// Sets the binding points for the storage buffers bound on the graphics pipeline.
/// </summary>
/// <param name="stage">Index of the shader stage</param>
/// <param name="descriptors">Buffer descriptors with the binding point values</param>
public void SetGraphicsStorageBufferBindings(int stage, ReadOnlyCollection<BufferDescriptor> descriptors)
/// <param name="bindings">Bindings for the active shader</param>
public void SetGraphicsBufferBindings(CachedShaderBindings bindings)
{
_gpStorageBuffers[stage].SetBindings(descriptors);
for (int i = 0; i < Constants.ShaderStages; i++)
{
_gpStorageBuffers[i].SetBindings(bindings.StorageBufferBindings[i]);
_gpUniformBuffers[i].SetBindings(bindings.ConstantBufferBindings[i]);
}
_gpStorageBuffersDirty = true;
}
/// <summary>
/// Sets the binding points for the uniform buffers bound on the compute pipeline.
/// </summary>
/// <param name="descriptors">Buffer descriptors with the binding point values</param>
public void SetComputeUniformBufferBindings(ReadOnlyCollection<BufferDescriptor> descriptors)
{
_cpUniformBuffers.SetBindings(descriptors);
}
/// <summary>
/// Sets the enabled uniform buffers mask on the graphics pipeline.
/// Each bit set on the mask indicates that the respective buffer index is enabled.
/// </summary>
/// <param name="stage">Index of the shader stage</param>
/// <param name="descriptors">Buffer descriptors with the binding point values</param>
public void SetGraphicsUniformBufferBindings(int stage, ReadOnlyCollection<BufferDescriptor> descriptors)
{
_gpUniformBuffers[stage].SetBindings(descriptors);
_gpUniformBuffersDirty = true;
}

View File

@@ -7,7 +7,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <summary>
/// A buffer binding to apply to a buffer texture.
/// </summary>
struct BufferTextureBinding
readonly struct BufferTextureBinding
{
/// <summary>
/// Shader stage accessing the texture.

View File

@@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// </summary>
class CounterCache
{
private struct CounterEntry
private readonly struct CounterEntry
{
public ulong Address { get; }
public ICounterEvent Event { get; }

View File

@@ -0,0 +1,103 @@
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Engine;
using Ryujinx.Graphics.Gpu.Image;
using Ryujinx.Graphics.Shader;
using System;
using System.Linq;
namespace Ryujinx.Graphics.Gpu.Shader
{
/// <summary>
/// A collection of shader bindings ready for insertion into the buffer and texture managers.
/// </summary>
internal class CachedShaderBindings
{
public TextureBindingInfo[][] TextureBindings { get; }
public TextureBindingInfo[][] ImageBindings { get; }
public BufferDescriptor[][] ConstantBufferBindings { get; }
public BufferDescriptor[][] StorageBufferBindings { get; }
public int MaxTextureBinding { get; }
public int MaxImageBinding { get; }
/// <summary>
/// Create a new cached shader bindings collection.
/// </summary>
/// <param name="isCompute">Whether the shader is for compute</param>
/// <param name="stages">The stages used by the shader</param>
public CachedShaderBindings(bool isCompute, CachedShaderStage[] stages)
{
int stageCount = isCompute ? 1 : Constants.ShaderStages;
TextureBindings = new TextureBindingInfo[stageCount][];
ImageBindings = new TextureBindingInfo[stageCount][];
ConstantBufferBindings = new BufferDescriptor[stageCount][];
StorageBufferBindings = new BufferDescriptor[stageCount][];
int maxTextureBinding = -1;
int maxImageBinding = -1;
int offset = isCompute ? 0 : 1;
for (int i = 0; i < stageCount; i++)
{
CachedShaderStage stage = stages[i + offset];
if (stage == null)
{
TextureBindings[i] = Array.Empty<TextureBindingInfo>();
ImageBindings[i] = Array.Empty<TextureBindingInfo>();
ConstantBufferBindings[i] = Array.Empty<BufferDescriptor>();
StorageBufferBindings[i] = Array.Empty<BufferDescriptor>();
continue;
}
TextureBindings[i] = stage.Info.Textures.Select(descriptor =>
{
Target target = ShaderTexture.GetTarget(descriptor.Type);
var result = new TextureBindingInfo(
target,
descriptor.Binding,
descriptor.CbufSlot,
descriptor.HandleIndex,
descriptor.Flags);
if (descriptor.Binding > maxTextureBinding)
{
maxTextureBinding = descriptor.Binding;
}
return result;
}).ToArray();
ImageBindings[i] = stage.Info.Images.Select(descriptor =>
{
Target target = ShaderTexture.GetTarget(descriptor.Type);
Format format = ShaderTexture.GetFormat(descriptor.Format);
var result = new TextureBindingInfo(
target,
format,
descriptor.Binding,
descriptor.CbufSlot,
descriptor.HandleIndex,
descriptor.Flags);
if (descriptor.Binding > maxImageBinding)
{
maxImageBinding = descriptor.Binding;
}
return result;
}).ToArray();
ConstantBufferBindings[i] = stage.Info.CBuffers.ToArray();
StorageBufferBindings[i] = stage.Info.SBuffers.ToArray();
}
MaxTextureBinding = maxTextureBinding;
MaxImageBinding = maxImageBinding;
}
}
}

View File

@@ -24,6 +24,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// </summary>
public CachedShaderStage[] Shaders { get; }
/// <summary>
/// Cached shader bindings, ready for placing into the bindings manager.
/// </summary>
public CachedShaderBindings Bindings { get; }
/// <summary>
/// Creates a new instance of the shader bundle.
/// </summary>
@@ -37,6 +42,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
Shaders = shaders;
SpecializationState.Prepare(shaders);
Bindings = new CachedShaderBindings(shaders.Length == 1, shaders);
}
/// <summary>

View File

@@ -24,7 +24,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
/// <summary>
/// Represents an operation to perform on the <see cref="_fileWriterWorkerQueue"/>.
/// </summary>
private struct CacheFileOperationTask
private readonly struct CacheFileOperationTask
{
/// <summary>
/// The type of operation to perform.
@@ -46,7 +46,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
/// <summary>
/// Background shader cache write information.
/// </summary>
private struct AddShaderData
private readonly struct AddShaderData
{
/// <summary>
/// Cached shader program.

View File

@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
private const ushort FileFormatVersionMajor = 1;
private const ushort FileFormatVersionMinor = 2;
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
private const uint CodeGenVersion = 3943;
private const uint CodeGenVersion = 4011;
private const string SharedTocFileName = "shared.toc";
private const string SharedDataFileName = "shared.data";

View File

@@ -3,7 +3,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
/// <summary>
/// Guest shader code and constant buffer data accessed by the shader.
/// </summary>
struct GuestCodeAndCbData
readonly struct GuestCodeAndCbData
{
/// <summary>
/// Maxwell binary shader code.

Some files were not shown because too many files have changed in this diff Show More