Compare commits

...

4 commits

Author SHA1 Message Date
Keaton
7095259731 Merge branch 'feature/vulkan-index-buff-compute' into 'master'
Vulkan: Use compute shader for non-indirect unsupported topology index buffer conversions

See merge request ryubing/ryujinx!15
2025-03-30 02:45:39 -05:00
GreemDev
2ea9e945ab Move locales.json to repository root under "assets" folder
See merge request ryubing/ryujinx!20
2025-03-30 02:06:04 -05:00
Isaac Marovitz
6b51cd01a9 Fix >16 primitives 2025-03-27 18:23:15 -05:00
Isaac Marovitz
c32e8e1a57 Use compute shader for non indirect index buffer conversion 2025-03-27 18:23:15 -05:00
7 changed files with 34 additions and 66 deletions

View file

@ -15,7 +15,7 @@ namespace Ryujinx.BuildValidationTasks
{ {
Console.WriteLine("Running Locale Validation Task..."); Console.WriteLine("Running Locale Validation Task...");
string path = projectPath + "src/Ryujinx/Assets/locales.json"; string path = projectPath + "assets/locales.json";
string data; string data;
using (StreamReader sr = new(path)) using (StreamReader sr = new(path))

View file

@ -874,57 +874,42 @@ namespace Ryujinx.Graphics.Vulkan
public unsafe void ConvertIndexBuffer(VulkanRenderer gd, public unsafe void ConvertIndexBuffer(VulkanRenderer gd,
CommandBufferScoped cbs, CommandBufferScoped cbs,
BufferHolder src, BufferHolder srcIndexBuffer,
BufferHolder dst, BufferHolder dstIndexBuffer,
IndexBufferPattern pattern, IndexBufferPattern pattern,
int indexSize, int indexSize,
int srcOffset, int srcOffset,
int indexCount) int indexCount)
{ {
// TODO: Support conversion with primitive restart enabled. // TODO: Support conversion with primitive restart enabled.
// TODO: Convert with a compute shader?
int primitiveCount = pattern.GetPrimitiveCount(indexCount);
int convertedCount = pattern.GetConvertedCount(indexCount); int convertedCount = pattern.GetConvertedCount(indexCount);
int outputIndexSize = 4; int outputIndexSize = 4;
Buffer dstBuffer = dstIndexBuffer.GetBuffer().Get(cbs, 0, convertedCount * outputIndexSize).Value;
Buffer srcBuffer = src.GetBuffer().Get(cbs, srcOffset, indexCount * indexSize).Value; const int ParamsBufferSize = 16 * sizeof(int);
Buffer dstBuffer = dst.GetBuffer().Get(cbs, 0, convertedCount * outputIndexSize).Value;
gd.Api.CmdFillBuffer(cbs.CommandBuffer, dstBuffer, 0, Vk.WholeSize, 0); Span<int> shaderParams = stackalloc int[ParamsBufferSize / sizeof(int)];
List<BufferCopy> bufferCopy = []; shaderParams[8] = pattern.PrimitiveVertices;
int outputOffset = 0; shaderParams[9] = pattern.PrimitiveVerticesOut;
shaderParams[10] = indexSize;
shaderParams[11] = outputIndexSize;
shaderParams[12] = pattern.BaseIndex;
shaderParams[13] = pattern.IndexStride;
shaderParams[14] = srcOffset;
shaderParams[15] = primitiveCount;
// Try to merge copies of adjacent indices to reduce copy count. pattern.OffsetIndex.CopyTo(shaderParams[..pattern.OffsetIndex.Length]);
int sequenceStart = 0;
int sequenceLength = 0;
foreach (int index in pattern.GetIndexMapping(indexCount)) using var patternScoped = gd.BufferManager.ReserveOrCreate(gd, cbs, ParamsBufferSize);
{ var patternBuffer = patternScoped.Holder;
if (sequenceLength > 0)
{
if (index == sequenceStart + sequenceLength && indexSize == outputIndexSize)
{
sequenceLength++;
continue;
}
// Commit the copy so far. patternBuffer.SetDataUnchecked<int>(patternScoped.Offset, shaderParams);
bufferCopy.Add(new BufferCopy((ulong)(srcOffset + sequenceStart * indexSize), (ulong)outputOffset, (ulong)(indexSize * sequenceLength)));
outputOffset += outputIndexSize * sequenceLength;
}
sequenceStart = index; _pipeline.SetCommandBuffer(cbs);
sequenceLength = 1;
}
if (sequenceLength > 0)
{
// Commit final pending copy.
bufferCopy.Add(new BufferCopy((ulong)(srcOffset + sequenceStart * indexSize), (ulong)outputOffset, (ulong)(indexSize * sequenceLength)));
}
BufferCopy[] bufferCopyArray = bufferCopy.ToArray();
BufferHolder.InsertBufferBarrier( BufferHolder.InsertBufferBarrier(
gd, gd,
@ -937,10 +922,11 @@ namespace Ryujinx.Graphics.Vulkan
0, 0,
convertedCount * outputIndexSize); convertedCount * outputIndexSize);
fixed (BufferCopy* pBufferCopy = bufferCopyArray) _pipeline.SetUniformBuffers([new BufferAssignment(0, new BufferRange(patternScoped.Handle, patternScoped.Offset, ParamsBufferSize))]);
{ _pipeline.SetStorageBuffers(1, new[] { srcIndexBuffer.GetBuffer(), dstIndexBuffer.GetBuffer() });
gd.Api.CmdCopyBuffer(cbs.CommandBuffer, srcBuffer, dstBuffer, (uint)bufferCopyArray.Length, pBufferCopy);
} _pipeline.SetProgram(_programConvertIndexBuffer);
_pipeline.DispatchCompute(BitUtils.DivRoundUp(primitiveCount, 16), 1, 1);
BufferHolder.InsertBufferBarrier( BufferHolder.InsertBufferBarrier(
gd, gd,
@ -952,6 +938,8 @@ namespace Ryujinx.Graphics.Vulkan
PipelineStageFlags.AllCommandsBit, PipelineStageFlags.AllCommandsBit,
0, 0,
convertedCount * outputIndexSize); convertedCount * outputIndexSize);
_pipeline.Finish(gd, cbs);
} }
public void CopyIncompatibleFormats( public void CopyIncompatibleFormats(

View file

@ -47,28 +47,6 @@ namespace Ryujinx.Graphics.Vulkan
return primitiveCount * OffsetIndex.Length; return primitiveCount * OffsetIndex.Length;
} }
public IEnumerable<int> GetIndexMapping(int indexCount)
{
int primitiveCount = GetPrimitiveCount(indexCount);
int index = BaseIndex;
for (int i = 0; i < primitiveCount; i++)
{
if (RepeatStart)
{
// Used for triangle fan
yield return 0;
}
for (int j = RepeatStart ? 1 : 0; j < OffsetIndex.Length; j++)
{
yield return index + OffsetIndex[j];
}
index += IndexStride;
}
}
public BufferHandle GetRepeatingBuffer(int vertexCount, out int indexCount) public BufferHandle GetRepeatingBuffer(int vertexCount, out int indexCount)
{ {
int primitiveCount = GetPrimitiveCount(vertexCount); int primitiveCount = GetPrimitiveCount(vertexCount);

View file

@ -154,7 +154,7 @@ namespace Ryujinx.Ava.Common.Locale
{ {
Dictionary<LocaleKeys, string> localeStrings = new(); Dictionary<LocaleKeys, string> localeStrings = new();
_localeData ??= EmbeddedResources.ReadAllText("Ryujinx/Assets/locales.json") _localeData ??= EmbeddedResources.ReadAllText("Ryujinx/Assets/Locale.json")
.Into(it => JsonHelper.Deserialize(it, LocalesJsonContext.Default.LocalesJson)); .Into(it => JsonHelper.Deserialize(it, LocalesJsonContext.Default.LocalesJson));
foreach (LocalesEntry locale in _localeData.Value.Locales) foreach (LocalesEntry locale in _localeData.Value.Locales)

View file

@ -154,7 +154,9 @@
<EmbeddedResource Include="..\..\docs\compatibility.csv" LogicalName="RyujinxGameCompatibilityList"> <EmbeddedResource Include="..\..\docs\compatibility.csv" LogicalName="RyujinxGameCompatibilityList">
<Link>Assets\RyujinxGameCompatibility.csv</Link> <Link>Assets\RyujinxGameCompatibility.csv</Link>
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Include="Assets\locales.json" /> <EmbeddedResource Include="..\..\assets\locales.json">
<Link>Assets\Locale.json</Link>
</EmbeddedResource>
<EmbeddedResource Include="Assets\Styles\Styles.xaml" /> <EmbeddedResource Include="Assets\Styles\Styles.xaml" />
<EmbeddedResource Include="Assets\Icons\Controller_JoyConLeft.svg" /> <EmbeddedResource Include="Assets\Icons\Controller_JoyConLeft.svg" />
<EmbeddedResource Include="Assets\Icons\Controller_JoyConPair.svg" /> <EmbeddedResource Include="Assets\Icons\Controller_JoyConPair.svg" />
@ -173,6 +175,6 @@
<EmbeddedResource Include="Assets\UIImages\Logo_Ryujinx_AntiAlias.png" /> <EmbeddedResource Include="Assets\UIImages\Logo_Ryujinx_AntiAlias.png" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<AdditionalFiles Include="Assets\locales.json" /> <AdditionalFiles Include="..\..\assets\locales.json" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -76,7 +76,7 @@ namespace Ryujinx.Ava.UI.Views.Main
private static IEnumerable<MenuItem> GenerateLanguageMenuItems() private static IEnumerable<MenuItem> GenerateLanguageMenuItems()
{ {
const string LocalePath = "Ryujinx/Assets/locales.json"; const string LocalePath = "Ryujinx/Assets/Locale.json";
string languageJson = EmbeddedResources.ReadAllText(LocalePath); string languageJson = EmbeddedResources.ReadAllText(LocalePath);