Compare commits

..

12 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
Andrey Sukharev
3868a00206 Use source generated regular expressions (#4005) 2022-12-04 00:43:23 +00:00
206 changed files with 1540 additions and 1332 deletions

View File

@@ -89,6 +89,7 @@ csharp_style_conditional_delegate_call = true:suggestion
# Modifier preferences # Modifier preferences
csharp_prefer_static_local_function = true:suggestion 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_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 # Code-block preferences
csharp_prefer_braces = true:silent csharp_prefer_braces = true:silent

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -2,7 +2,7 @@ using ARMeilleure.Instructions;
namespace ARMeilleure.Decoders namespace ARMeilleure.Decoders
{ {
struct InstDescriptor readonly struct InstDescriptor
{ {
public static InstDescriptor Undefined => new InstDescriptor(InstName.Und, InstEmit.Und); 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 const int FastLookupSize = 0x1000;
private struct InstInfo private readonly struct InstInfo
{ {
public int Mask { get; } public int Mask { get; }
public int Value { get; } public int Value { get; }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -14,7 +14,7 @@ namespace ARMeilleure.Translation
private const int RegsCount = 32; private const int RegsCount = 32;
private const int RegsMask = RegsCount - 1; 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 IntMask => Mask.GetElement(0);
public long VecMask => Mask.GetElement(1); 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 Start { get; }
public ulong End { get; } public ulong End { get; }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,7 +4,8 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"> mc:Ignorable="d"
Focusable="True">
<Grid <Grid
Margin="5,10,5,5" Margin="5,10,5,5"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"

View File

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

View File

@@ -4,7 +4,8 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" mc:Ignorable="d"
xmlns:Locale="clr-namespace:Ryujinx.Ava.Common.Locale" 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 HorizontalAlignment="Stretch" VerticalAlignment="Center" Margin="5,10,5, 5">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />

View File

@@ -3,5 +3,6 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" 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> </UserControl>

View File

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

View File

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

View File

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

View File

@@ -10,7 +10,8 @@
xmlns:Locale="clr-namespace:Ryujinx.Ava.Common.Locale" xmlns:Locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.Ui.ViewModels" 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> <Design.DataContext>
<viewModels:UserProfileViewModel /> <viewModels:UserProfileViewModel />
</Design.DataContext> </Design.DataContext>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -16,7 +16,7 @@ namespace Ryujinx.Common.Logging
public static event EventHandler<LogEventArgs> Updated; public static event EventHandler<LogEventArgs> Updated;
public struct Log public readonly struct Log
{ {
internal readonly LogLevel Level; 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. /// This is useful to keep the Array representation when possible to avoid copies.
/// </summary> /// </summary>
/// <typeparam name="T">Element Type</typeparam> /// <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 T[] Array;
public readonly ReadOnlySpan<T> Span; public readonly ReadOnlySpan<T> Span;

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,22 +1,14 @@
using System; using System.Runtime.InteropServices;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.GAL namespace Ryujinx.Graphics.GAL
{ {
[StructLayout(LayoutKind.Sequential, Size = 8)] [StructLayout(LayoutKind.Sequential, Size = 8)]
public struct BufferHandle : IEquatable<BufferHandle> public readonly record struct BufferHandle
{ {
private readonly ulong _value; private readonly ulong _value;
public static BufferHandle Null => new BufferHandle(0); public static BufferHandle Null => new BufferHandle(0);
private BufferHandle(ulong value) => _value = value; 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 namespace Ryujinx.Graphics.GAL
{ {
public struct BufferRange public readonly struct BufferRange
{ {
private static readonly BufferRange _empty = new BufferRange(BufferHandle.Null, 0, 0); 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 namespace Ryujinx.Graphics.GAL
{ {
public struct Capabilities public readonly struct Capabilities
{ {
public readonly TargetApi Api; public readonly TargetApi Api;
public readonly string VendorName; public readonly string VendorName;
@@ -17,6 +17,7 @@ namespace Ryujinx.Graphics.GAL
public readonly bool Supports3DTextureCompression; public readonly bool Supports3DTextureCompression;
public readonly bool SupportsBgraFormat; public readonly bool SupportsBgraFormat;
public readonly bool SupportsR4G4Format; public readonly bool SupportsR4G4Format;
public readonly bool SupportsSnormBufferTextureFormat;
public readonly bool SupportsFragmentShaderInterlock; public readonly bool SupportsFragmentShaderInterlock;
public readonly bool SupportsFragmentShaderOrderingIntel; public readonly bool SupportsFragmentShaderOrderingIntel;
public readonly bool SupportsGeometryShaderPassthrough; public readonly bool SupportsGeometryShaderPassthrough;
@@ -52,6 +53,7 @@ namespace Ryujinx.Graphics.GAL
bool supports3DTextureCompression, bool supports3DTextureCompression,
bool supportsBgraFormat, bool supportsBgraFormat,
bool supportsR4G4Format, bool supportsR4G4Format,
bool supportsSnormBufferTextureFormat,
bool supportsFragmentShaderInterlock, bool supportsFragmentShaderInterlock,
bool supportsFragmentShaderOrderingIntel, bool supportsFragmentShaderOrderingIntel,
bool supportsGeometryShaderPassthrough, bool supportsGeometryShaderPassthrough,
@@ -84,6 +86,7 @@ namespace Ryujinx.Graphics.GAL
Supports3DTextureCompression = supports3DTextureCompression; Supports3DTextureCompression = supports3DTextureCompression;
SupportsBgraFormat = supportsBgraFormat; SupportsBgraFormat = supportsBgraFormat;
SupportsR4G4Format = supportsR4G4Format; SupportsR4G4Format = supportsR4G4Format;
SupportsSnormBufferTextureFormat = supportsSnormBufferTextureFormat;
SupportsFragmentShaderInterlock = supportsFragmentShaderInterlock; SupportsFragmentShaderInterlock = supportsFragmentShaderInterlock;
SupportsFragmentShaderOrderingIntel = supportsFragmentShaderOrderingIntel; SupportsFragmentShaderOrderingIntel = supportsFragmentShaderOrderingIntel;
SupportsGeometryShaderPassthrough = supportsGeometryShaderPassthrough; SupportsGeometryShaderPassthrough = supportsGeometryShaderPassthrough;

View File

@@ -1,32 +1,4 @@
using System;
namespace Ryujinx.Graphics.GAL namespace Ryujinx.Graphics.GAL
{ {
public struct ColorF : IEquatable<ColorF> public readonly record struct ColorF(float Red, float Green, float Blue, float Alpha);
{
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);
}
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
namespace Ryujinx.Graphics.GAL 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 X { get; }
public T Y { get; } public T Y { get; }

View File

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

View File

@@ -1,6 +1,6 @@
namespace Ryujinx.Graphics.GAL 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) public ScreenCaptureImageInfo(int width, int height, bool isBgra, byte[] data, bool flipX, bool flipY)
{ {

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,40 +1,4 @@
using System;
namespace Ryujinx.Graphics.GAL namespace Ryujinx.Graphics.GAL
{ {
public struct VertexAttribDescriptor : IEquatable<VertexAttribDescriptor> public readonly record struct VertexAttribDescriptor(int BufferIndex, int Offset, bool IsZero, Format Format);
{
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);
}
}
} }

View File

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

View File

@@ -1,6 +1,6 @@
namespace Ryujinx.Graphics.GAL namespace Ryujinx.Graphics.GAL
{ {
public struct Viewport public readonly struct Viewport
{ {
public Rectangle<float> Region { get; } 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.SetComputeUniformBuffer(cb.Slot, cbDescriptor.PackAddress(), (uint)cbDescriptor.Size);
} }
_channel.BufferManager.SetComputeStorageBufferBindings(info.SBuffers); _channel.BufferManager.SetComputeBufferBindings(cs.Bindings);
_channel.BufferManager.SetComputeUniformBufferBindings(info.CBuffers);
int maxTextureBinding = -1; _channel.TextureManager.SetComputeBindings(cs.Bindings);
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);
// Should never return false for mismatching spec state, since the shader was fetched above. // Should never return false for mismatching spec state, since the shader was fetched above.
_channel.TextureManager.CommitComputeBindings(cs.SpecializationState); _channel.TextureManager.CommitComputeBindings(cs.SpecializationState);

View File

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

View File

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

View File

@@ -19,6 +19,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
private readonly GpuChannel _channel; private readonly GpuChannel _channel;
private readonly DeviceStateWithShadow<ThreedClassState> _state; private readonly DeviceStateWithShadow<ThreedClassState> _state;
private readonly DrawState _drawState; private readonly DrawState _drawState;
private readonly SpecializationStateUpdater _currentSpecState;
private bool _topologySet; private bool _topologySet;
private bool _instancedDrawPending; private bool _instancedDrawPending;
@@ -44,12 +45,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// <param name="channel">GPU channel</param> /// <param name="channel">GPU channel</param>
/// <param name="state">Channel state</param> /// <param name="state">Channel state</param>
/// <param name="drawState">Draw 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; _context = context;
_channel = channel; _channel = channel;
_state = state; _state = state;
_drawState = drawState; _drawState = drawState;
_currentSpecState = spec;
} }
/// <summary> /// <summary>
@@ -132,6 +135,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_drawState.FirstIndex = firstIndex; _drawState.FirstIndex = firstIndex;
_drawState.IndexCount = indexCount; _drawState.IndexCount = indexCount;
_currentSpecState.SetHasConstantBufferDrawParameters(false);
engine.UpdateState(); engine.UpdateState();
@@ -256,6 +260,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
if (_drawState.Topology != topology || !_topologySet) if (_drawState.Topology != topology || !_topologySet)
{ {
_context.Renderer.Pipeline.SetPrimitiveTopology(topology); _context.Renderer.Pipeline.SetPrimitiveTopology(topology);
_currentSpecState.SetTopology(topology);
_drawState.Topology = topology; _drawState.Topology = topology;
_topologySet = true; _topologySet = true;
} }
@@ -452,7 +457,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_state.State.FirstInstance = (uint)firstInstance; _state.State.FirstInstance = (uint)firstInstance;
_drawState.DrawIndexed = indexed; _drawState.DrawIndexed = indexed;
_drawState.HasConstantBufferDrawParameters = true; _currentSpecState.SetHasConstantBufferDrawParameters(true);
engine.UpdateState(); engine.UpdateState();
@@ -469,7 +474,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_state.State.FirstInstance = 0; _state.State.FirstInstance = 0;
_drawState.DrawIndexed = false; _drawState.DrawIndexed = false;
_drawState.HasConstantBufferDrawParameters = false;
if (renderEnable == ConditionalRenderEnabled.Host) if (renderEnable == ConditionalRenderEnabled.Host)
{ {
@@ -527,7 +531,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_drawState.DrawIndexed = indexed; _drawState.DrawIndexed = indexed;
_drawState.DrawIndirect = true; _drawState.DrawIndirect = true;
_drawState.HasConstantBufferDrawParameters = true; _currentSpecState.SetHasConstantBufferDrawParameters(true);
engine.UpdateState(); engine.UpdateState();
@@ -561,7 +565,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_drawState.DrawIndexed = false; _drawState.DrawIndexed = false;
_drawState.DrawIndirect = false; _drawState.DrawIndirect = false;
_drawState.HasConstantBufferDrawParameters = false;
if (renderEnable == ConditionalRenderEnabled.Host) 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> /// <summary>
/// State update callback entry, with the callback function and associated field names. /// State update callback entry, with the callback function and associated field names.
/// </summary> /// </summary>
struct StateUpdateCallbackEntry readonly struct StateUpdateCallbackEntry
{ {
/// <summary> /// <summary>
/// Callback function, to be called if the register was written as the state needs to be updated. /// 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.Logging;
using Ryujinx.Common.Memory; using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Engine.GPFifo;
using Ryujinx.Graphics.Gpu.Engine.Types; using Ryujinx.Graphics.Gpu.Engine.Types;
using Ryujinx.Graphics.Gpu.Image; using Ryujinx.Graphics.Gpu.Image;
using Ryujinx.Graphics.Gpu.Shader; using Ryujinx.Graphics.Gpu.Shader;
@@ -16,9 +17,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// </summary> /// </summary>
class StateUpdater class StateUpdater
{ {
public const int ShaderStateIndex = 16; public const int ShaderStateIndex = 26;
public const int RasterizerStateIndex = 15; public const int RasterizerStateIndex = 15;
public const int ScissorStateIndex = 18; public const int ScissorStateIndex = 16;
public const int VertexBufferStateIndex = 0; public const int VertexBufferStateIndex = 0;
public const int PrimitiveRestartStateIndex = 12; public const int PrimitiveRestartStateIndex = 12;
@@ -31,6 +32,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
private readonly ShaderProgramInfo[] _currentProgramInfo; private readonly ShaderProgramInfo[] _currentProgramInfo;
private ShaderSpecializationState _shaderSpecState; private ShaderSpecializationState _shaderSpecState;
private SpecializationStateUpdater _currentSpecState;
private ProgramPipelineState _pipeline; private ProgramPipelineState _pipeline;
@@ -54,15 +56,17 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// <param name="channel">GPU channel</param> /// <param name="channel">GPU channel</param>
/// <param name="state">3D engine state</param> /// <param name="state">3D engine state</param>
/// <param name="drawState">Draw 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; _context = context;
_channel = channel; _channel = channel;
_state = state; _state = state;
_drawState = drawState; _drawState = drawState;
_currentProgramInfo = new ShaderProgramInfo[Constants.ShaderStages]; _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. // 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 // Rasterizer and scissor states are checked by render target clear, their indexes
// must be updated on the constants "RasterizerStateIndex" and "ScissorStateIndex" if modified. // must be updated on the constants "RasterizerStateIndex" and "ScissorStateIndex" if modified.
@@ -101,6 +105,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
nameof(ThreedClassState.DepthTestFunc)), nameof(ThreedClassState.DepthTestFunc)),
new StateUpdateCallbackEntry(UpdateTessellationState, new StateUpdateCallbackEntry(UpdateTessellationState,
nameof(ThreedClassState.TessMode),
nameof(ThreedClassState.TessOuterLevel), nameof(ThreedClassState.TessOuterLevel),
nameof(ThreedClassState.TessInnerLevel), nameof(ThreedClassState.TessInnerLevel),
nameof(ThreedClassState.PatchVertices)), nameof(ThreedClassState.PatchVertices)),
@@ -138,17 +143,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
new StateUpdateCallbackEntry(UpdateRasterizerState, nameof(ThreedClassState.RasterizeEnable)), 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, new StateUpdateCallbackEntry(UpdateScissorState,
nameof(ThreedClassState.ScissorState), nameof(ThreedClassState.ScissorState),
nameof(ThreedClassState.ScreenScissorState)), nameof(ThreedClassState.ScreenScissorState)),
@@ -179,7 +173,21 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
new StateUpdateCallbackEntry(UpdateMultisampleState, new StateUpdateCallbackEntry(UpdateMultisampleState,
nameof(ThreedClassState.AlphaToCoverageDitherEnable), 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)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Update() 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 // The vertex buffer size is calculated using a different
// method when doing indexed draws, so we need to make sure // method when doing indexed draws, so we need to make sure
// to update the vertex buffers if we are doing a regular // 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); _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(); CommitBindings();
if (tfEnable && !_prevTfEnable) if (tfEnable && !_prevTfEnable)
@@ -302,7 +311,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
if (!_channel.TextureManager.CommitGraphicsBindings(_shaderSpecState) || (buffers.HasUnalignedStorageBuffers != hasUnaligned)) 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(); UpdateShaderState();
} }
@@ -351,6 +361,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_state.State.PatchVertices, _state.State.PatchVertices,
_state.State.TessOuterLevel.AsSpan(), _state.State.TessOuterLevel.AsSpan(),
_state.State.TessInnerLevel.AsSpan()); _state.State.TessInnerLevel.AsSpan());
_currentSpecState.SetTessellationMode(_state.State.TessMode);
} }
/// <summary> /// <summary>
@@ -611,6 +623,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_state.State.AlphaTestEnable, _state.State.AlphaTestEnable,
_state.State.AlphaTestRef, _state.State.AlphaTestRef,
_state.State.AlphaTestFunc); _state.State.AlphaTestFunc);
_currentSpecState.SetAlphaTest(
_state.State.AlphaTestEnable,
_state.State.AlphaTestRef,
_state.State.AlphaTestFunc);
} }
/// <summary> /// <summary>
@@ -710,6 +727,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_context.Renderer.Pipeline.SetDepthMode(GetDepthMode()); _context.Renderer.Pipeline.SetDepthMode(GetDepthMode());
_context.Renderer.Pipeline.SetViewports(viewports, disableTransform); _context.Renderer.Pipeline.SetViewports(viewports, disableTransform);
_currentSpecState.SetViewportTransformDisable(_state.State.ViewportTransformEnable == 0);
_currentSpecState.SetDepthMode(GetDepthMode() == DepthMode.MinusOneToOne);
} }
/// <summary> /// <summary>
@@ -847,6 +867,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_channel.TextureManager.SetGraphicsTexturePool(texturePool.Address.Pack(), texturePool.MaximumId); _channel.TextureManager.SetGraphicsTexturePool(texturePool.Address.Pack(), texturePool.MaximumId);
_channel.TextureManager.SetGraphicsTextureBufferIndex((int)_state.State.TextureBufferIndex); _channel.TextureManager.SetGraphicsTextureBufferIndex((int)_state.State.TextureBufferIndex);
_currentSpecState.SetPoolState(GetPoolState());
} }
/// <summary> /// <summary>
@@ -887,6 +909,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_pipeline.SetVertexAttribs(vertexAttribs); _pipeline.SetVertexAttribs(vertexAttribs);
_context.Renderer.Pipeline.SetVertexAttribs(vertexAttribs); _context.Renderer.Pipeline.SetVertexAttribs(vertexAttribs);
_currentSpecState.SetAttributeTypes(ref _state.State.VertexAttribState);
} }
/// <summary> /// <summary>
@@ -914,6 +937,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
Origin origin = (_state.State.PointCoordReplace & 4) == 0 ? Origin.LowerLeft : Origin.UpperLeft; Origin origin = (_state.State.PointCoordReplace & 4) == 0 ? Origin.LowerLeft : Origin.UpperLeft;
_context.Renderer.Pipeline.SetPointParameters(size, isProgramPointSize, enablePointSprite, origin); _context.Renderer.Pipeline.SetPointParameters(size, isProgramPointSize, enablePointSprite, origin);
_currentSpecState.SetProgramPointSizeEnable(isProgramPointSize);
_currentSpecState.SetPointSize(size);
} }
/// <summary> /// <summary>
@@ -1212,6 +1238,16 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
alphaToCoverageEnable, alphaToCoverageEnable,
_state.State.AlphaToCoverageDitherEnable, _state.State.AlphaToCoverageDitherEnable,
alphaToOneEnable)); 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> /// <summary>
@@ -1239,10 +1275,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
addressesSpan[index] = baseAddress + shader.Offset; addressesSpan[index] = baseAddress + shader.Offset;
} }
GpuChannelPoolState poolState = GetPoolState(); CachedShaderProgram gs = shaderCache.GetGraphicsShader(ref _state.State, ref _pipeline, _channel, ref _currentSpecState.GetPoolState(), ref _currentSpecState.GetGraphicsState(), addresses);
GpuChannelGraphicsState graphicsState = GetGraphicsState();
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; _shaderSpecState = gs.SpecializationState;
@@ -1257,88 +1293,24 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
UpdateUserClipState(); UpdateUserClipState();
} }
UpdateShaderBindings(gs.Bindings);
for (int stageIndex = 0; stageIndex < Constants.ShaderStages; stageIndex++) 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); _context.Renderer.Pipeline.SetProgram(gs.HostProgram);
} }
/// <summary> /// <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> /// </summary>
/// <param name="stage">Shader stage to have the bindings updated</param> /// <param name="bindings">Bindings for the active shader</param>
/// <param name="info">Shader stage bindings info</param> private void UpdateShaderBindings(CachedShaderBindings bindings)
private void UpdateStageBindings(int stage, ShaderProgramInfo info)
{ {
_currentProgramInfo[stage] = info; _channel.TextureManager.SetGraphicsBindings(bindings);
_channel.BufferManager.SetGraphicsBufferBindings(bindings);
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);
} }
/// <summary> /// <summary>
@@ -1353,46 +1325,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
(int)_state.State.TextureBufferIndex); (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> /// <summary>
/// Gets the depth mode that is currently being used (zero to one or minus one to one). /// Gets the depth mode that is currently being used (zero to one or minus one to one).
/// </summary> /// </summary>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -57,45 +57,21 @@ namespace Ryujinx.Graphics.Gpu.Image
} }
/// <summary> /// <summary>
/// Rents the texture bindings array of the compute pipeline. /// Sets the texture and image bindings for the compute pipeline.
/// </summary> /// </summary>
/// <param name="count">The number of bindings needed</param> /// <param name="bindings">Bindings for the active shader</param>
/// <returns>The texture bindings array</returns> public void SetComputeBindings(CachedShaderBindings bindings)
public TextureBindingInfo[] RentComputeTextureBindings(int count)
{ {
return _cpBindingsManager.RentTextureBindings(0, count); _cpBindingsManager.SetBindings(bindings);
} }
/// <summary> /// <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> /// </summary>
/// <param name="stage">The index of the shader stage to bind the textures</param> /// <param name="bindings">Bindings for the active shader</param>
/// <param name="count">The number of bindings needed</param> public void SetGraphicsBindings(CachedShaderBindings bindings)
/// <returns>The texture bindings array</returns>
public TextureBindingInfo[] RentGraphicsTextureBindings(int stage, int count)
{ {
return _gpBindingsManager.RentTextureBindings(stage, count); _gpBindingsManager.SetBindings(bindings);
}
/// <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);
} }
/// <summary> /// <summary>
@@ -107,16 +83,6 @@ namespace Ryujinx.Graphics.Gpu.Image
_cpBindingsManager.SetTextureBufferIndex(index); _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> /// <summary>
/// Sets the texture constant buffer index on the graphics pipeline. /// Sets the texture constant buffer index on the graphics pipeline.
/// </summary> /// </summary>
@@ -126,16 +92,6 @@ namespace Ryujinx.Graphics.Gpu.Image
_gpBindingsManager.SetTextureBufferIndex(index); _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> /// <summary>
/// Sets the current sampler pool on the compute pipeline. /// Sets the current sampler pool on the compute pipeline.
/// </summary> /// </summary>

View File

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

View File

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

View File

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

View File

@@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// </summary> /// </summary>
class CounterCache class CounterCache
{ {
private struct CounterEntry private readonly struct CounterEntry
{ {
public ulong Address { get; } public ulong Address { get; }
public ICounterEvent Event { 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> /// </summary>
public CachedShaderStage[] Shaders { get; } public CachedShaderStage[] Shaders { get; }
/// <summary>
/// Cached shader bindings, ready for placing into the bindings manager.
/// </summary>
public CachedShaderBindings Bindings { get; }
/// <summary> /// <summary>
/// Creates a new instance of the shader bundle. /// Creates a new instance of the shader bundle.
/// </summary> /// </summary>
@@ -37,6 +42,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
Shaders = shaders; Shaders = shaders;
SpecializationState.Prepare(shaders); SpecializationState.Prepare(shaders);
Bindings = new CachedShaderBindings(shaders.Length == 1, shaders);
} }
/// <summary> /// <summary>

View File

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

View File

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

View File

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

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