Compare commits

..

6 Commits

Author SHA1 Message Date
1b28ecd63e Vulkan: Simplify MultiFenceHolder and managing them (#4845)
* Vulkan: Simplify waitable add/remove

Removal of unnecessary hashset and dictionary

* Thread safety for GetBufferData in PersistentFlushBuffer

* Fix WaitForFencesImpl thread safety

* Proper methods for risky reference increments

* Wrong type of CB.

* Address feedback
2023-05-08 12:45:12 +02:00
895d9b53bc Vulkan: Batch vertex buffer updates (#4843)
* Vulkan: Batch vertex buffer updates

Some games can bind a large number of vertex buffers for draws. This PR allows for vertex buffers to be updated with one call rather than one per buffer.

This mostly affects the AMD Mesa driver, the testing platform was Steam Deck with Super Mario Odyssey. It was taking about 12% before, should be greatly reduced now.

A small optimization has been added to avoid looking up the same buffer multiple times, as a common pattern is for the same buffer to be bound many times in a row with different ranges.

* Only rebind vertex buffers if they have changed

* Address feedback
2023-05-08 10:59:26 +02:00
0e06aace45 misc: Avoid copy of ApplicationControlProperty (#4849)
Avoid more giant copy when passing it around.
2023-05-08 01:50:07 +02:00
adf4ebcd60 Ava: Fix SystemTimeOffset calculation (#4848)
* Ava: Fix SystemTimeOffset calculation

During testing of #4822, Mary pointed out the way we calculate time offset is wrong in our Avalonia UI. This PR fixed that.
The axaml file is autoformatted too.

* DateTime.Now in local var
2023-05-08 00:31:08 +02:00
470a8031a4 time: Update for 15.0.0 changes and fixes long standing issues (#4822)
* time: Update for 15.0.0 changes

Last time we did an upgrade on the time service was during 9.x era, it was about time to take back that reverse again!

15.0.0 added a new structure on the shared memory to get steady clock raw timepoints with a granularity in nanoseconds.

This commit implements this new part.

I plan to write a follow up with a bit of refactoring of this ancient part of the emulator.

As always, reverse and work done by your truly.

PS: As a reminder, if this change is reused anywhere else, work should be credited as Ryujinx and not my person.

* time: Do not set setup value to posix time

This should fix local and network clock returning 0 under usage with
shared memory.

This probably fix #2430.

* Address gdkchan's comment

* Fix internal offset not working since changes and ensure that user clock have a valid clock id

* time: Report auto correcting clock and hardcode steady clock unique id

Fix Pokemon Sword Pokejobs for real.

* Address gdkchan's comment
2023-05-08 00:15:58 +02:00
5440d4ad5c misc: Switch ProcessResult to a class (#4846)
This avoid giant copies being performed when being returned or passed.
2023-05-07 20:50:45 +00:00
18 changed files with 395 additions and 190 deletions

View File

@ -238,8 +238,9 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
} }
public DateTimeOffset DateOffset { get; set; } public DateTimeOffset CurrentDate { get; set; }
public TimeSpan TimeOffset { get; set; } public TimeSpan CurrentTime { get; set; }
internal AvaloniaList<TimeZone> TimeZones { get; set; } internal AvaloniaList<TimeZone> TimeZones { get; set; }
public AvaloniaList<string> GameDirectories { get; set; } public AvaloniaList<string> GameDirectories { get; set; }
public ObservableCollection<ComboBoxItem> AvailableGpus { get; set; } public ObservableCollection<ComboBoxItem> AvailableGpus { get; set; }
@ -397,10 +398,11 @@ namespace Ryujinx.Ava.UI.ViewModels
Language = (int)config.System.Language.Value; Language = (int)config.System.Language.Value;
TimeZone = config.System.TimeZone; TimeZone = config.System.TimeZone;
DateTime dateTimeOffset = DateTime.Now.AddSeconds(config.System.SystemTimeOffset); DateTime currentDateTime = DateTime.Now;
CurrentDate = currentDateTime.Date;
CurrentTime = currentDateTime.TimeOfDay.Add(TimeSpan.FromSeconds(config.System.SystemTimeOffset));
DateOffset = dateTimeOffset.Date;
TimeOffset = dateTimeOffset.TimeOfDay;
EnableVsync = config.Graphics.EnableVsync; EnableVsync = config.Graphics.EnableVsync;
EnableFsIntegrityChecks = config.System.EnableFsIntegrityChecks; EnableFsIntegrityChecks = config.System.EnableFsIntegrityChecks;
ExpandDramSize = config.System.ExpandRam; ExpandDramSize = config.System.ExpandRam;
@ -487,9 +489,7 @@ namespace Ryujinx.Ava.UI.ViewModels
config.System.TimeZone.Value = TimeZone; config.System.TimeZone.Value = TimeZone;
} }
TimeSpan systemTimeOffset = DateOffset - DateTime.Now; config.System.SystemTimeOffset.Value = Convert.ToInt64((CurrentDate.ToUnixTimeSeconds() + CurrentTime.TotalSeconds) - DateTimeOffset.Now.ToUnixTimeSeconds());
config.System.SystemTimeOffset.Value = systemTimeOffset.Seconds;
config.Graphics.EnableVsync.Value = EnableVsync; config.Graphics.EnableVsync.Value = EnableVsync;
config.System.EnableFsIntegrityChecks.Value = EnableFsIntegrityChecks; config.System.EnableFsIntegrityChecks.Value = EnableFsIntegrityChecks;
config.System.ExpandRam.Value = ExpandDramSize; config.System.ExpandRam.Value = ExpandDramSize;

View File

@ -3,12 +3,12 @@
xmlns="https://github.com/avaloniaui" xmlns="https://github.com/avaloniaui"
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:locale="clr-namespace:Ryujinx.Ava.Common.Locale" xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
mc:Ignorable="d"
x:CompileBindings="True" x:CompileBindings="True"
x:DataType="viewModels:SettingsViewModel"> x:DataType="viewModels:SettingsViewModel"
mc:Ignorable="d">
<Design.DataContext> <Design.DataContext>
<viewModels:SettingsViewModel /> <viewModels:SettingsViewModel />
</Design.DataContext> </Design.DataContext>
@ -27,13 +27,15 @@
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabSystemCore}" /> <TextBlock Classes="h1" Text="{locale:Locale SettingsTabSystemCore}" />
<StackPanel Margin="10,0,0,0" Orientation="Vertical"> <StackPanel Margin="10,0,0,0" Orientation="Vertical">
<StackPanel Margin="0,0,0,10" Orientation="Horizontal"> <StackPanel Margin="0,0,0,10" Orientation="Horizontal">
<TextBlock VerticalAlignment="Center" <TextBlock
Text="{locale:Locale SettingsTabSystemSystemRegion}" Width="250"
Width="250" /> VerticalAlignment="Center"
<ComboBox SelectedIndex="{Binding Region}" Text="{locale:Locale SettingsTabSystemSystemRegion}" />
ToolTip.Tip="{locale:Locale RegionTooltip}" <ComboBox
HorizontalContentAlignment="Left" Width="350"
Width="350"> HorizontalContentAlignment="Left"
SelectedIndex="{Binding Region}"
ToolTip.Tip="{locale:Locale RegionTooltip}">
<ComboBoxItem> <ComboBoxItem>
<TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionJapan}" /> <TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionJapan}" />
</ComboBoxItem> </ComboBoxItem>
@ -58,20 +60,21 @@
</ComboBox> </ComboBox>
</StackPanel> </StackPanel>
<StackPanel Margin="0,0,0,10" Orientation="Horizontal"> <StackPanel Margin="0,0,0,10" Orientation="Horizontal">
<TextBlock VerticalAlignment="Center" <TextBlock
Text="{locale:Locale SettingsTabSystemSystemLanguage}" Width="250"
ToolTip.Tip="{locale:Locale LanguageTooltip}" VerticalAlignment="Center"
Width="250" /> Text="{locale:Locale SettingsTabSystemSystemLanguage}"
<ComboBox SelectedIndex="{Binding Language}" ToolTip.Tip="{locale:Locale LanguageTooltip}" />
ToolTip.Tip="{locale:Locale LanguageTooltip}" <ComboBox
HorizontalContentAlignment="Left" Width="350"
Width="350"> HorizontalContentAlignment="Left"
SelectedIndex="{Binding Language}"
ToolTip.Tip="{locale:Locale LanguageTooltip}">
<ComboBoxItem> <ComboBoxItem>
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageJapanese}" /> <TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageJapanese}" />
</ComboBoxItem> </ComboBoxItem>
<ComboBoxItem> <ComboBoxItem>
<TextBlock <TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageAmericanEnglish}" />
Text="{locale:Locale SettingsTabSystemSystemLanguageAmericanEnglish}" />
</ComboBoxItem> </ComboBoxItem>
<ComboBoxItem> <ComboBoxItem>
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageFrench}" /> <TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageFrench}" />
@ -104,71 +107,67 @@
<TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageTaiwanese}" /> <TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageTaiwanese}" />
</ComboBoxItem> </ComboBoxItem>
<ComboBoxItem> <ComboBoxItem>
<TextBlock <TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageBritishEnglish}" />
Text="{locale:Locale SettingsTabSystemSystemLanguageBritishEnglish}" />
</ComboBoxItem> </ComboBoxItem>
<ComboBoxItem> <ComboBoxItem>
<TextBlock <TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageCanadianFrench}" />
Text="{locale:Locale SettingsTabSystemSystemLanguageCanadianFrench}" />
</ComboBoxItem> </ComboBoxItem>
<ComboBoxItem> <ComboBoxItem>
<TextBlock <TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageLatinAmericanSpanish}" />
Text="{locale:Locale SettingsTabSystemSystemLanguageLatinAmericanSpanish}" />
</ComboBoxItem> </ComboBoxItem>
<ComboBoxItem> <ComboBoxItem>
<TextBlock <TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageSimplifiedChinese}" />
Text="{locale:Locale SettingsTabSystemSystemLanguageSimplifiedChinese}" />
</ComboBoxItem> </ComboBoxItem>
<ComboBoxItem> <ComboBoxItem>
<TextBlock <TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageTraditionalChinese}" />
Text="{locale:Locale SettingsTabSystemSystemLanguageTraditionalChinese}" />
</ComboBoxItem> </ComboBoxItem>
<ComboBoxItem> <ComboBoxItem>
<TextBlock <TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageBrazilianPortuguese}" />
Text="{locale:Locale SettingsTabSystemSystemLanguageBrazilianPortuguese}" />
</ComboBoxItem> </ComboBoxItem>
</ComboBox> </ComboBox>
</StackPanel> </StackPanel>
<StackPanel Margin="0,0,0,10" Orientation="Horizontal"> <StackPanel Margin="0,0,0,10" Orientation="Horizontal">
<TextBlock VerticalAlignment="Center" <TextBlock
Text="{locale:Locale SettingsTabSystemSystemTimeZone}" Width="250"
ToolTip.Tip="{locale:Locale TimezoneTooltip}" VerticalAlignment="Center"
Width="250" /> Text="{locale:Locale SettingsTabSystemSystemTimeZone}"
ToolTip.Tip="{locale:Locale TimezoneTooltip}" />
<AutoCompleteBox <AutoCompleteBox
Name="TimeZoneBox" Name="TimeZoneBox"
Width="350" Width="350"
MaxDropDownHeight="500"
FilterMode="Contains" FilterMode="Contains"
Items="{Binding TimeZones}" Items="{Binding TimeZones}"
MaxDropDownHeight="500"
SelectionChanged="TimeZoneBox_OnSelectionChanged" SelectionChanged="TimeZoneBox_OnSelectionChanged"
Text="{Binding Path=TimeZone, Mode=OneWay}" Text="{Binding Path=TimeZone, Mode=OneWay}"
TextChanged="TimeZoneBox_OnTextChanged" TextChanged="TimeZoneBox_OnTextChanged"
ToolTip.Tip="{locale:Locale TimezoneTooltip}" /> ToolTip.Tip="{locale:Locale TimezoneTooltip}" />
</StackPanel> </StackPanel>
<StackPanel Margin="0,0,0,10" Orientation="Horizontal"> <StackPanel Margin="0,0,0,10" Orientation="Horizontal">
<TextBlock VerticalAlignment="Center" <TextBlock
Text="{locale:Locale SettingsTabSystemSystemTime}" Width="250"
ToolTip.Tip="{locale:Locale TimeTooltip}" VerticalAlignment="Center"
Width="250"/> Text="{locale:Locale SettingsTabSystemSystemTime}"
<DatePicker VerticalAlignment="Center" SelectedDate="{Binding DateOffset}" ToolTip.Tip="{locale:Locale TimeTooltip}" />
ToolTip.Tip="{locale:Locale TimeTooltip}" <DatePicker
Width="350" /> Width="350"
VerticalAlignment="Center"
SelectedDate="{Binding CurrentDate}"
ToolTip.Tip="{locale:Locale TimeTooltip}" />
</StackPanel> </StackPanel>
<StackPanel Margin="250,0,0,10" Orientation="Horizontal"> <StackPanel Margin="250,0,0,10" Orientation="Horizontal">
<TimePicker <TimePicker
Width="350"
VerticalAlignment="Center" VerticalAlignment="Center"
ClockIdentifier="24HourClock" ClockIdentifier="24HourClock"
SelectedTime="{Binding TimeOffset}" SelectedTime="{Binding CurrentTime}"
Width="350"
ToolTip.Tip="{locale:Locale TimeTooltip}" /> ToolTip.Tip="{locale:Locale TimeTooltip}" />
</StackPanel> </StackPanel>
<CheckBox IsChecked="{Binding EnableVsync}"> <CheckBox IsChecked="{Binding EnableVsync}">
<TextBlock Text="{locale:Locale SettingsTabSystemEnableVsync}" <TextBlock Text="{locale:Locale SettingsTabSystemEnableVsync}" ToolTip.Tip="{locale:Locale VSyncToggleTooltip}" />
ToolTip.Tip="{locale:Locale VSyncToggleTooltip}" />
</CheckBox> </CheckBox>
<CheckBox IsChecked="{Binding EnableFsIntegrityChecks}"> <CheckBox IsChecked="{Binding EnableFsIntegrityChecks}">
<TextBlock Text="{locale:Locale SettingsTabSystemEnableFsIntegrityChecks}" <TextBlock Text="{locale:Locale SettingsTabSystemEnableFsIntegrityChecks}" ToolTip.Tip="{locale:Locale FsIntegrityToggleTooltip}" />
ToolTip.Tip="{locale:Locale FsIntegrityToggleTooltip}" />
</CheckBox> </CheckBox>
</StackPanel> </StackPanel>
<Separator Height="1" /> <Separator Height="1" />
@ -180,12 +179,10 @@
Margin="10,0,0,0" Margin="10,0,0,0"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
Orientation="Vertical"> Orientation="Vertical">
<CheckBox IsChecked="{Binding ExpandDramSize}" <CheckBox IsChecked="{Binding ExpandDramSize}" ToolTip.Tip="{locale:Locale DRamTooltip}">
ToolTip.Tip="{locale:Locale DRamTooltip}">
<TextBlock Text="{locale:Locale SettingsTabSystemExpandDramSize}" /> <TextBlock Text="{locale:Locale SettingsTabSystemExpandDramSize}" />
</CheckBox> </CheckBox>
<CheckBox IsChecked="{Binding IgnoreMissingServices}" <CheckBox IsChecked="{Binding IgnoreMissingServices}" ToolTip.Tip="{locale:Locale IgnoreMissingServicesTooltip}">
ToolTip.Tip="{locale:Locale IgnoreMissingServicesTooltip}">
<TextBlock Text="{locale:Locale SettingsTabSystemIgnoreMissingServices}" /> <TextBlock Text="{locale:Locale SettingsTabSystemIgnoreMissingServices}" />
</CheckBox> </CheckBox>
</StackPanel> </StackPanel>

View File

@ -105,6 +105,23 @@ namespace Ryujinx.Graphics.Vulkan
} }
} }
public bool TryIncrementReferenceCount()
{
int lastValue;
do
{
lastValue = _referenceCount;
if (lastValue == 0)
{
return false;
}
}
while (Interlocked.CompareExchange(ref _referenceCount, lastValue + 1, lastValue) != lastValue);
return true;
}
public void IncrementReferenceCount() public void IncrementReferenceCount()
{ {
if (Interlocked.Increment(ref _referenceCount) == 1) if (Interlocked.Increment(ref _referenceCount) == 1)

View File

@ -599,9 +599,10 @@ namespace Ryujinx.Graphics.Vulkan
Auto<DisposableBuffer> dst, Auto<DisposableBuffer> dst,
int srcOffset, int srcOffset,
int dstOffset, int dstOffset,
int size) int size,
bool registerSrcUsage = true)
{ {
var srcBuffer = src.Get(cbs, srcOffset, size).Value; var srcBuffer = registerSrcUsage ? src.Get(cbs, srcOffset, size).Value : src.GetUnsafe().Value;
var dstBuffer = dst.Get(cbs, dstOffset, size).Value; var dstBuffer = dst.Get(cbs, dstOffset, size).Value;
InsertBufferBarrier( InsertBufferBarrier(

View File

@ -31,7 +31,7 @@ namespace Ryujinx.Graphics.Vulkan
public SemaphoreHolder Semaphore; public SemaphoreHolder Semaphore;
public List<IAuto> Dependants; public List<IAuto> Dependants;
public HashSet<MultiFenceHolder> Waitables; public List<MultiFenceHolder> Waitables;
public HashSet<SemaphoreHolder> Dependencies; public HashSet<SemaphoreHolder> Dependencies;
public void Initialize(Vk api, Device device, CommandPool pool) public void Initialize(Vk api, Device device, CommandPool pool)
@ -47,7 +47,7 @@ namespace Ryujinx.Graphics.Vulkan
api.AllocateCommandBuffers(device, allocateInfo, out CommandBuffer); api.AllocateCommandBuffers(device, allocateInfo, out CommandBuffer);
Dependants = new List<IAuto>(); Dependants = new List<IAuto>();
Waitables = new HashSet<MultiFenceHolder>(); Waitables = new List<MultiFenceHolder>();
Dependencies = new HashSet<SemaphoreHolder>(); Dependencies = new HashSet<SemaphoreHolder>();
} }
} }
@ -143,8 +143,10 @@ namespace Ryujinx.Graphics.Vulkan
public void AddWaitable(int cbIndex, MultiFenceHolder waitable) public void AddWaitable(int cbIndex, MultiFenceHolder waitable)
{ {
ref var entry = ref _commandBuffers[cbIndex]; ref var entry = ref _commandBuffers[cbIndex];
waitable.AddFence(cbIndex, entry.Fence); if (waitable.AddFence(cbIndex, entry.Fence))
entry.Waitables.Add(waitable); {
entry.Waitables.Add(waitable);
}
} }
public bool HasWaitableOnRentedCommandBuffer(MultiFenceHolder waitable, int offset, int size) public bool HasWaitableOnRentedCommandBuffer(MultiFenceHolder waitable, int offset, int size)
@ -156,7 +158,7 @@ namespace Ryujinx.Graphics.Vulkan
ref var entry = ref _commandBuffers[i]; ref var entry = ref _commandBuffers[i];
if (entry.InUse && if (entry.InUse &&
entry.Waitables.Contains(waitable) && waitable.HasFence(i) &&
waitable.IsBufferRangeInUse(i, offset, size)) waitable.IsBufferRangeInUse(i, offset, size))
{ {
return true; return true;
@ -331,7 +333,7 @@ namespace Ryujinx.Graphics.Vulkan
foreach (var waitable in entry.Waitables) foreach (var waitable in entry.Waitables)
{ {
waitable.RemoveFence(cbIndex, entry.Fence); waitable.RemoveFence(cbIndex);
waitable.RemoveBufferUses(cbIndex); waitable.RemoveBufferUses(cbIndex);
} }

View File

@ -32,6 +32,25 @@ namespace Ryujinx.Graphics.Vulkan
return _fence; return _fence;
} }
public bool TryGet(out Fence fence)
{
int lastValue;
do
{
lastValue = _referenceCount;
if (lastValue == 0)
{
fence = default;
return false;
}
}
while (Interlocked.CompareExchange(ref _referenceCount, lastValue + 1, lastValue) != lastValue);
fence = _fence;
return true;
}
public Fence Get() public Fence Get()
{ {
Interlocked.Increment(ref _referenceCount); Interlocked.Increment(ref _referenceCount);

View File

@ -1,6 +1,5 @@
using Silk.NET.Vulkan; using Silk.NET.Vulkan;
using System.Collections.Generic; using System;
using System.Linq;
namespace Ryujinx.Graphics.Vulkan namespace Ryujinx.Graphics.Vulkan
{ {
@ -11,7 +10,7 @@ namespace Ryujinx.Graphics.Vulkan
{ {
private static int BufferUsageTrackingGranularity = 4096; private static int BufferUsageTrackingGranularity = 4096;
private readonly Dictionary<FenceHolder, int> _fences; private readonly FenceHolder[] _fences;
private BufferUsageBitmap _bufferUsageBitmap; private BufferUsageBitmap _bufferUsageBitmap;
/// <summary> /// <summary>
@ -19,7 +18,7 @@ namespace Ryujinx.Graphics.Vulkan
/// </summary> /// </summary>
public MultiFenceHolder() public MultiFenceHolder()
{ {
_fences = new Dictionary<FenceHolder, int>(); _fences = new FenceHolder[CommandBufferPool.MaxCommandBuffers];
} }
/// <summary> /// <summary>
@ -28,7 +27,7 @@ namespace Ryujinx.Graphics.Vulkan
/// <param name="size">Size of the buffer</param> /// <param name="size">Size of the buffer</param>
public MultiFenceHolder(int size) public MultiFenceHolder(int size)
{ {
_fences = new Dictionary<FenceHolder, int>(); _fences = new FenceHolder[CommandBufferPool.MaxCommandBuffers];
_bufferUsageBitmap = new BufferUsageBitmap(size, BufferUsageTrackingGranularity); _bufferUsageBitmap = new BufferUsageBitmap(size, BufferUsageTrackingGranularity);
} }
@ -80,25 +79,37 @@ namespace Ryujinx.Graphics.Vulkan
/// </summary> /// </summary>
/// <param name="cbIndex">Command buffer index of the command buffer that owns the fence</param> /// <param name="cbIndex">Command buffer index of the command buffer that owns the fence</param>
/// <param name="fence">Fence to be added</param> /// <param name="fence">Fence to be added</param>
public void AddFence(int cbIndex, FenceHolder fence) /// <returns>True if the command buffer's previous fence value was null</returns>
public bool AddFence(int cbIndex, FenceHolder fence)
{ {
lock (_fences) ref FenceHolder fenceRef = ref _fences[cbIndex];
if (fenceRef == null)
{ {
_fences.TryAdd(fence, cbIndex); fenceRef = fence;
return true;
} }
return false;
} }
/// <summary> /// <summary>
/// Removes a fence from the holder. /// Removes a fence from the holder.
/// </summary> /// </summary>
/// <param name="cbIndex">Command buffer index of the command buffer that owns the fence</param> /// <param name="cbIndex">Command buffer index of the command buffer that owns the fence</param>
/// <param name="fence">Fence to be removed</param> public void RemoveFence(int cbIndex)
public void RemoveFence(int cbIndex, FenceHolder fence)
{ {
lock (_fences) _fences[cbIndex] = null;
{ }
_fences.Remove(fence);
} /// <summary>
/// Determines if a fence referenced on the given command buffer.
/// </summary>
/// <param name="cbIndex">Index of the command buffer to check if it's used</param>
/// <returns>True if referenced, false otherwise</returns>
public bool HasFence(int cbIndex)
{
return _fences[cbIndex] != null;
} }
/// <summary> /// <summary>
@ -147,21 +158,29 @@ namespace Ryujinx.Graphics.Vulkan
/// <returns>True if all fences were signaled before the timeout expired, false otherwise</returns> /// <returns>True if all fences were signaled before the timeout expired, false otherwise</returns>
private bool WaitForFencesImpl(Vk api, Device device, int offset, int size, bool hasTimeout, ulong timeout) private bool WaitForFencesImpl(Vk api, Device device, int offset, int size, bool hasTimeout, ulong timeout)
{ {
FenceHolder[] fenceHolders; Span<FenceHolder> fenceHolders = new FenceHolder[CommandBufferPool.MaxCommandBuffers];
Fence[] fences;
lock (_fences) int count = size != 0 ? GetOverlappingFences(fenceHolders, offset, size) : GetFences(fenceHolders);
Span<Fence> fences = stackalloc Fence[count];
int fenceCount = 0;
for (int i = 0; i < count; i++)
{ {
fenceHolders = size != 0 ? GetOverlappingFences(offset, size) : _fences.Keys.ToArray(); if (fenceHolders[i].TryGet(out Fence fence))
fences = new Fence[fenceHolders.Length];
for (int i = 0; i < fenceHolders.Length; i++)
{ {
fences[i] = fenceHolders[i].Get(); fences[fenceCount] = fence;
if (fenceCount < i)
{
fenceHolders[fenceCount] = fenceHolders[i];
}
fenceCount++;
} }
} }
if (fences.Length == 0) if (fenceCount == 0)
{ {
return true; return true;
} }
@ -170,14 +189,14 @@ namespace Ryujinx.Graphics.Vulkan
if (hasTimeout) if (hasTimeout)
{ {
signaled = FenceHelper.AllSignaled(api, device, fences, timeout); signaled = FenceHelper.AllSignaled(api, device, fences.Slice(0, fenceCount), timeout);
} }
else else
{ {
FenceHelper.WaitAllIndefinitely(api, device, fences); FenceHelper.WaitAllIndefinitely(api, device, fences.Slice(0, fenceCount));
} }
for (int i = 0; i < fenceHolders.Length; i++) for (int i = 0; i < fenceCount; i++)
{ {
fenceHolders[i].Put(); fenceHolders[i].Put();
} }
@ -186,27 +205,49 @@ namespace Ryujinx.Graphics.Vulkan
} }
/// <summary> /// <summary>
/// Gets fences to wait for use of a given buffer region. /// Gets fences to wait for.
/// </summary> /// </summary>
/// <param name="offset">Offset of the range</param> /// <param name="storage">Span to store fences in</param>
/// <param name="size">Size of the range in bytes</param> /// <returns>Number of fences placed in storage</returns>
/// <returns>Fences for the specified region</returns> private int GetFences(Span<FenceHolder> storage)
private FenceHolder[] GetOverlappingFences(int offset, int size)
{ {
List<FenceHolder> overlapping = new List<FenceHolder>(); int count = 0;
foreach (var kv in _fences) for (int i = 0; i < _fences.Length; i++)
{ {
var fence = kv.Key; var fence = _fences[i];
var ownerCbIndex = kv.Value;
if (_bufferUsageBitmap.OverlapsWith(ownerCbIndex, offset, size)) if (fence != null)
{ {
overlapping.Add(fence); storage[count++] = fence;
} }
} }
return overlapping.ToArray(); return count;
}
/// <summary>
/// Gets fences to wait for use of a given buffer region.
/// </summary>
/// <param name="storage">Span to store overlapping fences in</param>
/// <param name="offset">Offset of the range</param>
/// <param name="size">Size of the range in bytes</param>
/// <returns>Number of fences for the specified region placed in storage</returns>
private int GetOverlappingFences(Span<FenceHolder> storage, int offset, int size)
{
int count = 0;
for (int i = 0; i < _fences.Length; i++)
{
var fence = _fences[i];
if (fence != null && _bufferUsageBitmap.OverlapsWith(i, offset, size))
{
storage[count++] = fence;
}
}
return count;
} }
} }
} }

View File

@ -34,16 +34,26 @@ namespace Ryujinx.Graphics.Vulkan
public Span<byte> GetBufferData(CommandBufferPool cbp, BufferHolder buffer, int offset, int size) public Span<byte> GetBufferData(CommandBufferPool cbp, BufferHolder buffer, int offset, int size)
{ {
var flushStorage = ResizeIfNeeded(size); var flushStorage = ResizeIfNeeded(size);
Auto<DisposableBuffer> srcBuffer;
using (var cbs = cbp.Rent()) using (var cbs = cbp.Rent())
{ {
var srcBuffer = buffer.GetBuffer(cbs.CommandBuffer); srcBuffer = buffer.GetBuffer(cbs.CommandBuffer);
var dstBuffer = flushStorage.GetBuffer(cbs.CommandBuffer); var dstBuffer = flushStorage.GetBuffer(cbs.CommandBuffer);
BufferHolder.Copy(_gd, cbs, srcBuffer, dstBuffer, offset, 0, size); if (srcBuffer.TryIncrementReferenceCount())
{
BufferHolder.Copy(_gd, cbs, srcBuffer, dstBuffer, offset, 0, size, registerSrcUsage: false);
}
else
{
// Source buffer is no longer alive, don't copy anything to flush storage.
srcBuffer = null;
}
} }
flushStorage.WaitForFences(); flushStorage.WaitForFences();
srcBuffer?.DecrementReferenceCount();
return flushStorage.GetDataStorage(0, size); return flushStorage.GetDataStorage(0, size);
} }

View File

@ -66,6 +66,8 @@ namespace Ryujinx.Graphics.Vulkan
private ulong _vertexBuffersDirty; private ulong _vertexBuffersDirty;
protected Rectangle<int> ClearScissor; protected Rectangle<int> ClearScissor;
private readonly VertexBufferUpdater _vertexBufferUpdater;
public SupportBufferUpdater SupportBufferUpdater; public SupportBufferUpdater SupportBufferUpdater;
public IndexBufferPattern QuadsToTrisPattern; public IndexBufferPattern QuadsToTrisPattern;
public IndexBufferPattern TriFanToTrisPattern; public IndexBufferPattern TriFanToTrisPattern;
@ -96,6 +98,7 @@ namespace Ryujinx.Graphics.Vulkan
gd.Api.CreatePipelineCache(device, pipelineCacheCreateInfo, null, out PipelineCache).ThrowOnError(); gd.Api.CreatePipelineCache(device, pipelineCacheCreateInfo, null, out PipelineCache).ThrowOnError();
_descriptorSetUpdater = new DescriptorSetUpdater(gd, this); _descriptorSetUpdater = new DescriptorSetUpdater(gd, this);
_vertexBufferUpdater = new VertexBufferUpdater(gd);
_transformFeedbackBuffers = new BufferState[Constants.MaxTransformFeedbackBuffers]; _transformFeedbackBuffers = new BufferState[Constants.MaxTransformFeedbackBuffers];
_vertexBuffers = new VertexBufferState[Constants.MaxVertexBuffers + 1]; _vertexBuffers = new VertexBufferState[Constants.MaxVertexBuffers + 1];
@ -1185,6 +1188,9 @@ namespace Ryujinx.Graphics.Vulkan
int validCount = 1; int validCount = 1;
BufferHandle lastHandle = default;
Auto<DisposableBuffer> lastBuffer = default;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
var vertexBuffer = vertexBuffers[i]; var vertexBuffer = vertexBuffers[i];
@ -1194,7 +1200,12 @@ namespace Ryujinx.Graphics.Vulkan
if (vertexBuffer.Buffer.Handle != BufferHandle.Null) if (vertexBuffer.Buffer.Handle != BufferHandle.Null)
{ {
var vb = Gd.BufferManager.GetBuffer(CommandBuffer, vertexBuffer.Buffer.Handle, false); Auto<DisposableBuffer> vb = (vertexBuffer.Buffer.Handle == lastHandle) ? lastBuffer :
Gd.BufferManager.GetBuffer(CommandBuffer, vertexBuffer.Buffer.Handle, false);
lastHandle = vertexBuffer.Buffer.Handle;
lastBuffer = vb;
if (vb != null) if (vb != null)
{ {
int binding = i + 1; int binding = i + 1;
@ -1222,24 +1233,29 @@ namespace Ryujinx.Graphics.Vulkan
ref var buffer = ref _vertexBuffers[binding]; ref var buffer = ref _vertexBuffers[binding];
int oldScalarAlign = buffer.AttributeScalarAlignment; int oldScalarAlign = buffer.AttributeScalarAlignment;
buffer.Dispose();
if (Gd.Capabilities.VertexBufferAlignment < 2 && if (Gd.Capabilities.VertexBufferAlignment < 2 &&
(vertexBuffer.Stride % FormatExtensions.MaxBufferFormatScalarSize) == 0) (vertexBuffer.Stride % FormatExtensions.MaxBufferFormatScalarSize) == 0)
{ {
buffer = new VertexBufferState( if (!buffer.Matches(vb, descriptorIndex, vertexBuffer.Buffer.Offset, vbSize, vertexBuffer.Stride))
vb, {
descriptorIndex, buffer.Dispose();
vertexBuffer.Buffer.Offset,
vbSize,
vertexBuffer.Stride);
buffer.BindVertexBuffer(Gd, Cbs, (uint)binding, ref _newState); buffer = new VertexBufferState(
vb,
descriptorIndex,
vertexBuffer.Buffer.Offset,
vbSize,
vertexBuffer.Stride);
buffer.BindVertexBuffer(Gd, Cbs, (uint)binding, ref _newState, _vertexBufferUpdater);
}
} }
else else
{ {
// May need to be rewritten. Bind this buffer before draw. // May need to be rewritten. Bind this buffer before draw.
buffer.Dispose();
buffer = new VertexBufferState( buffer = new VertexBufferState(
vertexBuffer.Buffer.Handle, vertexBuffer.Buffer.Handle,
descriptorIndex, descriptorIndex,
@ -1255,6 +1271,8 @@ namespace Ryujinx.Graphics.Vulkan
} }
} }
_vertexBufferUpdater.Commit(Cbs);
_newState.VertexBindingDescriptionsCount = (uint)validCount; _newState.VertexBindingDescriptionsCount = (uint)validCount;
SignalStateChange(); SignalStateChange();
} }
@ -1596,10 +1614,12 @@ namespace Ryujinx.Graphics.Vulkan
{ {
int i = BitOperations.TrailingZeroCount(_vertexBuffersDirty); int i = BitOperations.TrailingZeroCount(_vertexBuffersDirty);
_vertexBuffers[i].BindVertexBuffer(Gd, Cbs, (uint)i, ref _newState); _vertexBuffers[i].BindVertexBuffer(Gd, Cbs, (uint)i, ref _newState, _vertexBufferUpdater);
_vertexBuffersDirty &= ~(1UL << i); _vertexBuffersDirty &= ~(1UL << i);
} }
_vertexBufferUpdater.Commit(Cbs);
} }
if (_stateDirty || Pbp != pbp) if (_stateDirty || Pbp != pbp)
@ -1712,6 +1732,7 @@ namespace Ryujinx.Graphics.Vulkan
_framebuffer?.Dispose(); _framebuffer?.Dispose();
_newState.Dispose(); _newState.Dispose();
_descriptorSetUpdater.Dispose(); _descriptorSetUpdater.Dispose();
_vertexBufferUpdater.Dispose();
for (int i = 0; i < _vertexBuffers.Length; i++) for (int i = 0; i < _vertexBuffers.Length; i++)
{ {

View File

@ -46,7 +46,7 @@ namespace Ryujinx.Graphics.Vulkan
AttributeScalarAlignment = 1; AttributeScalarAlignment = 1;
} }
public void BindVertexBuffer(VulkanRenderer gd, CommandBufferScoped cbs, uint binding, ref PipelineState state) public void BindVertexBuffer(VulkanRenderer gd, CommandBufferScoped cbs, uint binding, ref PipelineState state, VertexBufferUpdater updater)
{ {
var autoBuffer = _buffer; var autoBuffer = _buffer;
@ -65,21 +65,7 @@ namespace Ryujinx.Graphics.Vulkan
var buffer = autoBuffer.Get(cbs, 0, newSize).Value; var buffer = autoBuffer.Get(cbs, 0, newSize).Value;
if (gd.Capabilities.SupportsExtendedDynamicState) updater.BindVertexBuffer(cbs, binding, buffer, 0, (ulong)newSize, (ulong)stride);
{
gd.ExtendedDynamicStateApi.CmdBindVertexBuffers2(
cbs.CommandBuffer,
binding,
1,
buffer,
0,
(ulong)newSize,
(ulong)stride);
}
else
{
gd.Api.CmdBindVertexBuffers(cbs.CommandBuffer, binding, 1, buffer, 0);
}
_buffer = autoBuffer; _buffer = autoBuffer;
@ -106,21 +92,7 @@ namespace Ryujinx.Graphics.Vulkan
{ {
var buffer = autoBuffer.Get(cbs, _offset, _size).Value; var buffer = autoBuffer.Get(cbs, _offset, _size).Value;
if (gd.Capabilities.SupportsExtendedDynamicState) updater.BindVertexBuffer(cbs, binding, buffer, (ulong)_offset, (ulong)_size, (ulong)_stride);
{
gd.ExtendedDynamicStateApi.CmdBindVertexBuffers2(
cbs.CommandBuffer,
binding,
1,
buffer,
(ulong)_offset,
(ulong)_size,
(ulong)_stride);
}
else
{
gd.Api.CmdBindVertexBuffers(cbs.CommandBuffer, binding, 1, buffer, (ulong)_offset);
}
} }
} }
@ -129,6 +101,11 @@ namespace Ryujinx.Graphics.Vulkan
return _buffer == buffer; return _buffer == buffer;
} }
public bool Matches(Auto<DisposableBuffer> buffer, int descriptorIndex, int offset, int size, int stride = 0)
{
return _buffer == buffer && DescriptorIndex == descriptorIndex && _offset == offset && _size == size && _stride == stride;
}
public void Swap(Auto<DisposableBuffer> from, Auto<DisposableBuffer> to) public void Swap(Auto<DisposableBuffer> from, Auto<DisposableBuffer> to)
{ {
if (_buffer == from) if (_buffer == from)

View File

@ -0,0 +1,84 @@
using Silk.NET.Vulkan;
using System;
using VkBuffer = Silk.NET.Vulkan.Buffer;
namespace Ryujinx.Graphics.Vulkan
{
internal class VertexBufferUpdater : IDisposable
{
private VulkanRenderer _gd;
private uint _baseBinding;
private uint _count;
private NativeArray<VkBuffer> _buffers;
private NativeArray<ulong> _offsets;
private NativeArray<ulong> _sizes;
private NativeArray<ulong> _strides;
public VertexBufferUpdater(VulkanRenderer gd)
{
_gd = gd;
_buffers = new NativeArray<VkBuffer>(Constants.MaxVertexBuffers);
_offsets = new NativeArray<ulong>(Constants.MaxVertexBuffers);
_sizes = new NativeArray<ulong>(Constants.MaxVertexBuffers);
_strides = new NativeArray<ulong>(Constants.MaxVertexBuffers);
}
public void BindVertexBuffer(CommandBufferScoped cbs, uint binding, VkBuffer buffer, ulong offset, ulong size, ulong stride)
{
if (_count == 0)
{
_baseBinding = binding;
}
else if (_baseBinding + _count != binding)
{
Commit(cbs);
_baseBinding = binding;
}
int index = (int)_count;
_buffers[index] = buffer;
_offsets[index] = offset;
_sizes[index] = size;
_strides[index] = stride;
_count++;
}
public unsafe void Commit(CommandBufferScoped cbs)
{
if (_count != 0)
{
if (_gd.Capabilities.SupportsExtendedDynamicState)
{
_gd.ExtendedDynamicStateApi.CmdBindVertexBuffers2(
cbs.CommandBuffer,
_baseBinding,
_count,
_buffers.Pointer,
_offsets.Pointer,
_sizes.Pointer,
_strides.Pointer);
}
else
{
_gd.Api.CmdBindVertexBuffers(cbs.CommandBuffer, _baseBinding, _count, _buffers.Pointer, _offsets.Pointer);
}
_count = 0;
}
}
public void Dispose()
{
_buffers.Dispose();
_offsets.Dispose();
_sizes.Dispose();
_strides.Dispose();
}
}
}

View File

@ -200,9 +200,10 @@ namespace Ryujinx.HLE.HOS
LibHacHorizonManager = device.Configuration.LibHacHorizonManager; LibHacHorizonManager = device.Configuration.LibHacHorizonManager;
// We hardcode a clock source id to avoid it changing between each start.
// TODO: use set:sys (and get external clock source id from settings) // TODO: use set:sys (and get external clock source id from settings)
// TODO: use "time!standard_steady_clock_rtc_update_interval_minutes" and implement a worker thread to be accurate. // TODO: use "time!standard_steady_clock_rtc_update_interval_minutes" and implement a worker thread to be accurate.
UInt128 clockSourceId = UInt128Utils.CreateRandom(); UInt128 clockSourceId = new UInt128(0x36a0328702ce8bc1, 0x1608eaba02333284);
IRtcManager.GetExternalRtcValue(out ulong rtcValue); IRtcManager.GetExternalRtcValue(out ulong rtcValue);
// We assume the rtc is system time. // We assume the rtc is system time.
@ -222,22 +223,22 @@ namespace Ryujinx.HLE.HOS
internalOffset = internalOffset.AddSeconds(-3600L); internalOffset = internalOffset.AddSeconds(-3600L);
} }
internalOffset = new TimeSpanType(-internalOffset.NanoSeconds); systemTime = new TimeSpanType(systemTime.NanoSeconds + internalOffset.NanoSeconds);
// First init the standard steady clock // First init the standard steady clock
TimeServiceManager.Instance.SetupStandardSteadyClock(TickSource, clockSourceId, systemTime, internalOffset, TimeSpanType.Zero, false); TimeServiceManager.Instance.SetupStandardSteadyClock(TickSource, clockSourceId, TimeSpanType.Zero, TimeSpanType.Zero, TimeSpanType.Zero, false);
TimeServiceManager.Instance.SetupStandardLocalSystemClock(TickSource, new SystemClockContext(), systemTime.ToSeconds()); TimeServiceManager.Instance.SetupStandardLocalSystemClock(TickSource, new SystemClockContext(), systemTime.ToSeconds());
TimeServiceManager.Instance.StandardLocalSystemClock.GetClockContext(TickSource, out SystemClockContext localSytemClockContext);
if (NxSettings.Settings.TryGetValue("time!standard_network_clock_sufficient_accuracy_minutes", out object standardNetworkClockSufficientAccuracyMinutes)) if (NxSettings.Settings.TryGetValue("time!standard_network_clock_sufficient_accuracy_minutes", out object standardNetworkClockSufficientAccuracyMinutes))
{ {
TimeSpanType standardNetworkClockSufficientAccuracy = new TimeSpanType((int)standardNetworkClockSufficientAccuracyMinutes * 60000000000); TimeSpanType standardNetworkClockSufficientAccuracy = new TimeSpanType((int)standardNetworkClockSufficientAccuracyMinutes * 60000000000);
// The network system clock needs a valid system clock, as such we setup this system clock using the local system clock. // The network system clock needs a valid system clock, as such we setup this system clock using the local system clock.
TimeServiceManager.Instance.StandardLocalSystemClock.GetClockContext(TickSource, out SystemClockContext localSytemClockContext);
TimeServiceManager.Instance.SetupStandardNetworkSystemClock(localSytemClockContext, standardNetworkClockSufficientAccuracy); TimeServiceManager.Instance.SetupStandardNetworkSystemClock(localSytemClockContext, standardNetworkClockSufficientAccuracy);
} }
TimeServiceManager.Instance.SetupStandardUserSystemClock(TickSource, false, SteadyClockTimePoint.GetRandom()); TimeServiceManager.Instance.SetupStandardUserSystemClock(TickSource, true, localSytemClockContext.SteadyTimePoint);
// FIXME: TimeZone should be init here but it's actually done in ContentManager // FIXME: TimeZone should be init here but it's actually done in ContentManager

View File

@ -0,0 +1,13 @@
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Time.Clock.Types
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct ContinuousAdjustmentTimePoint
{
public ulong ClockOffset;
public long Multiplier;
public long DivisorLog2;
public SystemClockContext Context;
}
}

View File

@ -1,8 +1,8 @@
using Ryujinx.Cpu; using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.Kernel.Memory; using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Services.Time.Clock; using Ryujinx.HLE.HOS.Services.Time.Clock;
using Ryujinx.HLE.HOS.Services.Time.Clock.Types;
using Ryujinx.HLE.HOS.Services.Time.Types; using Ryujinx.HLE.HOS.Services.Time.Types;
using Ryujinx.HLE.Utilities;
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading; using System.Threading;
@ -16,10 +16,11 @@ namespace Ryujinx.HLE.HOS.Services.Time
private SharedMemoryStorage _timeSharedMemoryStorage; private SharedMemoryStorage _timeSharedMemoryStorage;
private int _timeSharedMemorySize; private int _timeSharedMemorySize;
private const uint SteadyClockContextOffset = 0x00; private const uint SteadyClockContextOffset = 0x00;
private const uint LocalSystemClockContextOffset = 0x38; private const uint LocalSystemClockContextOffset = 0x38;
private const uint NetworkSystemClockContextOffset = 0x80; private const uint NetworkSystemClockContextOffset = 0x80;
private const uint AutomaticCorrectionEnabledOffset = 0xC8; private const uint AutomaticCorrectionEnabledOffset = 0xC8;
private const uint ContinuousAdjustmentTimePointOffset = 0xD0;
public void Initialize(Switch device, KSharedMemory sharedMemory, SharedMemoryStorage timeSharedMemoryStorage, int timeSharedMemorySize) public void Initialize(Switch device, KSharedMemory sharedMemory, SharedMemoryStorage timeSharedMemoryStorage, int timeSharedMemorySize)
{ {
@ -39,15 +40,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
public void SetupStandardSteadyClock(ITickSource tickSource, UInt128 clockSourceId, TimeSpanType currentTimePoint) public void SetupStandardSteadyClock(ITickSource tickSource, UInt128 clockSourceId, TimeSpanType currentTimePoint)
{ {
TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(tickSource.Counter, tickSource.Frequency); UpdateSteadyClock(tickSource, clockSourceId, currentTimePoint);
SteadyClockContext context = new SteadyClockContext
{
InternalOffset = (ulong)(currentTimePoint.NanoSeconds - ticksTimeSpan.NanoSeconds),
ClockSourceId = clockSourceId
};
WriteObjectToSharedMemory(SteadyClockContextOffset, 4, context);
} }
public void SetAutomaticCorrectionEnabled(bool isAutomaticCorrectionEnabled) public void SetAutomaticCorrectionEnabled(bool isAutomaticCorrectionEnabled)
@ -58,10 +51,38 @@ namespace Ryujinx.HLE.HOS.Services.Time
public void SetSteadyClockRawTimePoint(ITickSource tickSource, TimeSpanType currentTimePoint) public void SetSteadyClockRawTimePoint(ITickSource tickSource, TimeSpanType currentTimePoint)
{ {
SteadyClockContext context = ReadObjectFromSharedMemory<SteadyClockContext>(SteadyClockContextOffset, 4); SteadyClockContext context = ReadObjectFromSharedMemory<SteadyClockContext>(SteadyClockContextOffset, 4);
TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(tickSource.Counter, tickSource.Frequency);
context.InternalOffset = (ulong)(currentTimePoint.NanoSeconds - ticksTimeSpan.NanoSeconds); UpdateSteadyClock(tickSource, context.ClockSourceId, currentTimePoint);
}
private void UpdateSteadyClock(ITickSource tickSource, UInt128 clockSourceId, TimeSpanType currentTimePoint)
{
TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(tickSource.Counter, tickSource.Frequency);
ContinuousAdjustmentTimePoint adjustmentTimePoint = new ContinuousAdjustmentTimePoint
{
ClockOffset = (ulong)ticksTimeSpan.NanoSeconds,
Multiplier = 1,
DivisorLog2 = 0,
Context = new SystemClockContext
{
Offset = 0,
SteadyTimePoint = new SteadyClockTimePoint
{
ClockSourceId = clockSourceId,
TimePoint = 0
}
}
};
WriteObjectToSharedMemory(ContinuousAdjustmentTimePointOffset, 4, adjustmentTimePoint);
SteadyClockContext context = new SteadyClockContext
{
InternalOffset = (ulong)(currentTimePoint.NanoSeconds - ticksTimeSpan.NanoSeconds),
ClockSourceId = clockSourceId
};
WriteObjectToSharedMemory(SteadyClockContextOffset, 4, context); WriteObjectToSharedMemory(SteadyClockContextOffset, 4, context);
} }

View File

@ -116,7 +116,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
device, device,
device.System.KernelContext, device.System.KernelContext,
metaLoader, metaLoader,
nacpData.Value, nacpData,
enablePtc, enablePtc,
allowCodeMemoryForJit, allowCodeMemoryForJit,
programName, programName,

View File

@ -209,7 +209,7 @@ namespace Ryujinx.HLE.Loaders.Processes
ProcessResult processResult = ProcessLoaderHelper.LoadNsos(_device, ProcessResult processResult = ProcessLoaderHelper.LoadNsos(_device,
_device.System.KernelContext, _device.System.KernelContext,
dummyExeFs.GetNpdm(), dummyExeFs.GetNpdm(),
nacpData.Value, nacpData,
diskCacheEnabled: false, diskCacheEnabled: false,
allowCodeMemoryForJit: true, allowCodeMemoryForJit: true,
programName, programName,

View File

@ -219,7 +219,7 @@ namespace Ryujinx.HLE.Loaders.Processes
Switch device, Switch device,
KernelContext context, KernelContext context,
MetaLoader metaLoader, MetaLoader metaLoader,
ApplicationControlProperty applicationControlProperties, BlitStruct<ApplicationControlProperty> applicationControlProperties,
bool diskCacheEnabled, bool diskCacheEnabled,
bool allowCodeMemoryForJit, bool allowCodeMemoryForJit,
string name, string name,
@ -355,7 +355,7 @@ namespace Ryujinx.HLE.Loaders.Processes
context.Device.System.TickSource, context.Device.System.TickSource,
context.Device.Gpu, context.Device.Gpu,
$"{programId:x16}", $"{programId:x16}",
applicationControlProperties.DisplayVersionString.ToString(), applicationControlProperties.Value.DisplayVersionString.ToString(),
diskCacheEnabled, diskCacheEnabled,
codeStart, codeStart,
codeSize); codeSize);

View File

@ -1,4 +1,5 @@
using LibHac.Loader; using LibHac.Common;
using LibHac.Loader;
using LibHac.Ns; using LibHac.Ns;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Cpu; using Ryujinx.Cpu;
@ -9,9 +10,9 @@ using System.Linq;
namespace Ryujinx.HLE.Loaders.Processes namespace Ryujinx.HLE.Loaders.Processes
{ {
public struct ProcessResult public class ProcessResult
{ {
public static ProcessResult Failed => new(null, new ApplicationControlProperty(), false, false, null, 0, 0, 0, TitleLanguage.AmericanEnglish); public static ProcessResult Failed => new(null, new BlitStruct<ApplicationControlProperty>(1), false, false, null, 0, 0, 0, TitleLanguage.AmericanEnglish);
private readonly byte _mainThreadPriority; private readonly byte _mainThreadPriority;
private readonly uint _mainThreadStackSize; private readonly uint _mainThreadStackSize;
@ -31,15 +32,15 @@ namespace Ryujinx.HLE.Loaders.Processes
public readonly bool AllowCodeMemoryForJit; public readonly bool AllowCodeMemoryForJit;
public ProcessResult( public ProcessResult(
MetaLoader metaLoader, MetaLoader metaLoader,
ApplicationControlProperty applicationControlProperties, BlitStruct<ApplicationControlProperty> applicationControlProperties,
bool diskCacheEnabled, bool diskCacheEnabled,
bool allowCodeMemoryForJit, bool allowCodeMemoryForJit,
IDiskCacheLoadState diskCacheLoadState, IDiskCacheLoadState diskCacheLoadState,
ulong pid, ulong pid,
byte mainThreadPriority, byte mainThreadPriority,
uint mainThreadStackSize, uint mainThreadStackSize,
TitleLanguage titleLanguage) TitleLanguage titleLanguage)
{ {
_mainThreadPriority = mainThreadPriority; _mainThreadPriority = mainThreadPriority;
_mainThreadStackSize = mainThreadStackSize; _mainThreadStackSize = mainThreadStackSize;
@ -48,7 +49,7 @@ namespace Ryujinx.HLE.Loaders.Processes
ProcessId = pid; ProcessId = pid;
MetaLoader = metaLoader; MetaLoader = metaLoader;
ApplicationControlProperties = applicationControlProperties; ApplicationControlProperties = applicationControlProperties.Value;
if (metaLoader is not null) if (metaLoader is not null)
{ {