Compare commits

...

4 commits

Author SHA1 Message Date
KeatonTheBot
fd6c680aca 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!5
2025-04-14 16:46:22 -05:00
WilliamWsyHK
e0181d3410 Update translations of zh-tw
See merge request ryubing/ryujinx!9
2025-04-14 15:33:07 -05:00
Isaac Marovitz
d75cfc5028 Fix >16 primitives 2025-04-06 15:26:15 -05:00
Isaac Marovitz
ab8d4fcae1 Use compute shader for non indirect index buffer conversion 2025-04-06 15:26:15 -05:00
3 changed files with 38 additions and 72 deletions

View file

@ -3844,7 +3844,7 @@
"tr_TR": "", "tr_TR": "",
"uk_UA": "Показати оригінальний UI (Потрібен перезапуск)", "uk_UA": "Показати оригінальний UI (Потрібен перезапуск)",
"zh_CN": "显示原始 UI 样式 (需要重启)", "zh_CN": "显示原始 UI 样式 (需要重启)",
"zh_TW": "" "zh_TW": "顯示原始 UI 樣式 (需要重新啟動 Ryujinx)"
} }
}, },
{ {
@ -3869,7 +3869,7 @@
"tr_TR": "", "tr_TR": "",
"uk_UA": "Показати старий інтерфейс Avalonia Ryujinx, який був у Ryujinx 1.1.1403. Ця опція активна за замовчуванням на всіх інших, окрім Windows платформах.\nПовернеться класична панель заголовка, а всі суттєві зміни інтерфейсу будуть скасовані, зокрема горизонтальне розміщення навігації в налаштуваннях.", "uk_UA": "Показати старий інтерфейс Avalonia Ryujinx, який був у Ryujinx 1.1.1403. Ця опція активна за замовчуванням на всіх інших, окрім Windows платформах.\nПовернеться класична панель заголовка, а всі суттєві зміни інтерфейсу будуть скасовані, зокрема горизонтальне розміщення навігації в налаштуваннях.",
"zh_CN": "显示旧的类似 Ryujinx 1.1.1403 的 Avalonia Ryujinx UI。在非 Windows 平台上默认启用此选项。\n经典样式的标题栏已回归并且恢复了对窗口布局的重大重构;例如在工具提示上方放置设置导航。", "zh_CN": "显示旧的类似 Ryujinx 1.1.1403 的 Avalonia Ryujinx UI。在非 Windows 平台上默认启用此选项。\n经典样式的标题栏已回归并且恢复了对窗口布局的重大重构;例如在工具提示上方放置设置导航。",
"zh_TW": "" "zh_TW": "顯示舊版 Ryujinx 1.1.1403 的 Avalonia UI 樣式。在非 Windows 平台預設啟用。\n經典樣式的標題欄已回歸並且還原了對設定視窗佈局的大型重構例如在工具提示上方設置導覽列。"
} }
}, },
{ {
@ -4944,7 +4944,7 @@
"tr_TR": "", "tr_TR": "",
"uk_UA": "Множник Турборежиму:", "uk_UA": "Множник Турборежиму:",
"zh_CN": "涡轮模式倍数:", "zh_CN": "涡轮模式倍数:",
"zh_TW": "" "zh_TW": "加速模式倍數:"
} }
}, },
{ {
@ -4969,7 +4969,7 @@
"tr_TR": "", "tr_TR": "",
"uk_UA": "Цільове значення коефіцієнта Турборежиму.\n\nЗалиште 200, якщо не впевнені", "uk_UA": "Цільове значення коефіцієнта Турборежиму.\n\nЗалиште 200, якщо не впевнені",
"zh_CN": "涡轮模式倍数的目标值。\n\n如果不确定请保留为 200。", "zh_CN": "涡轮模式倍数的目标值。\n\n如果不确定请保留为 200。",
"zh_TW": "" "zh_TW": "加速模式倍數的數值。\n\n如果不確定請保持數值為 200。"
} }
}, },
{ {
@ -4994,7 +4994,7 @@
"tr_TR": "", "tr_TR": "",
"uk_UA": "Турборежим це функція емулятора, яка ефективно прискорює або сповільнює гру, якщо та не чутлива до частоти кадрів. Цю функцію можна ввімкнути/вимкнути безпосередньо під час гри за допомогою гарячої клавіші, яку можна налаштувати в меню Гарячі клавіші в налаштуваннях.", "uk_UA": "Турборежим це функція емулятора, яка ефективно прискорює або сповільнює гру, якщо та не чутлива до частоти кадрів. Цю функцію можна ввімкнути/вимкнути безпосередньо під час гри за допомогою гарячої клавіші, яку можна налаштувати в меню Гарячі клавіші в налаштуваннях.",
"zh_CN": "涡轮模式是一种模拟器功能当游戏对帧率不敏感时它可以有效地导致加速或降速。\n您可以在游戏中使用热键切换此功能,它可以在 Ryujinx 的键盘热键设置进行设置。\n\n如果不确定则保留为 200。", "zh_CN": "涡轮模式是一种模拟器功能当游戏对帧率不敏感时它可以有效地导致加速或降速。\n您可以在游戏中使用热键切换此功能,它可以在 Ryujinx 的键盘热键设置进行设置。\n\n如果不确定则保留为 200。",
"zh_TW": "" "zh_TW": "加速模式是一種模擬器功能,其目的為加速或減速對不是以影格速率為速度 (frame-rate sensitive) 的遊戲。\n你可以在遊戲中以快捷鍵切換此功能而快捷鍵可於 Ryujinx 鍵盤快捷鍵中設置。\n\n如果不確定請保持數值為 200。"
} }
}, },
{ {
@ -18269,7 +18269,7 @@
"tr_TR": "", "tr_TR": "",
"uk_UA": "{0} FPS ({1}ms), Турбо ({2}%)", "uk_UA": "{0} FPS ({1}ms), Турбо ({2}%)",
"zh_CN": "{0} FPS ({1}ms), 涡轮 ({2}%)", "zh_CN": "{0} FPS ({1}ms), 涡轮 ({2}%)",
"zh_TW": "" "zh_TW": "{0} FPS ({1}ms), 加速 ({2}%)"
} }
}, },
{ {
@ -24019,7 +24019,7 @@
"tr_TR": "", "tr_TR": "",
"uk_UA": "Турбомод:", "uk_UA": "Турбомод:",
"zh_CN": "涡轮模式: ", "zh_CN": "涡轮模式: ",
"zh_TW": "" "zh_TW": "加速模式:"
} }
}, },
{ {
@ -24044,7 +24044,7 @@
"tr_TR": "", "tr_TR": "",
"uk_UA": "Гаряча клавіша Турборежиму.\nКонфігурація поведінки турборежиму в налаштуваннях Процесору Ryujinx.\n\nНе прив'язуйте, якщо не впевнені.", "uk_UA": "Гаряча клавіша Турборежиму.\nКонфігурація поведінки турборежиму в налаштуваннях Процесору Ryujinx.\n\nНе прив'язуйте, якщо не впевнені.",
"zh_CN": "涡轮模式热键。\n可以在 Ryujinx CPU 设置中配置涡轮模式的行为。\n\n如果不确定请保留为未绑定。", "zh_CN": "涡轮模式热键。\n可以在 Ryujinx CPU 设置中配置涡轮模式的行为。\n\n如果不确定请保留为未绑定。",
"zh_TW": "" "zh_TW": "加速模式快捷鍵。\n可以在 Ryujinx CPU 設定中設定加速模式的倍數。\n\n如果不確定請保持為「未分配」。"
} }
}, },
{ {
@ -24069,7 +24069,7 @@
"tr_TR": "", "tr_TR": "",
"uk_UA": "Тільки під час натискання", "uk_UA": "Тільки під час натискання",
"zh_CN": "仅在按下时", "zh_CN": "仅在按下时",
"zh_TW": "" "zh_TW": "只在按下時"
} }
}, },
{ {
@ -24119,7 +24119,7 @@
"tr_TR": "", "tr_TR": "",
"uk_UA": "Список сумісності — {0} ігор", "uk_UA": "Список сумісності — {0} ігор",
"zh_CN": "兼容性列表 - {0} 条", "zh_CN": "兼容性列表 - {0} 条",
"zh_TW": "" "zh_TW": "相容性列表 - {0} 則紀錄"
} }
}, },
{ {
@ -24194,7 +24194,7 @@
"tr_TR": "", "tr_TR": "",
"uk_UA": "Шукати серед {0} перевірених ігор...", "uk_UA": "Шукати серед {0} перевірених ігор...",
"zh_CN": "搜索 {0} 兼容性条目...", "zh_CN": "搜索 {0} 兼容性条目...",
"zh_TW": "" "zh_TW": "從相容性列表的 {0} 則紀錄中搜尋..."
} }
}, },
{ {

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 srcBuffer = src.GetBuffer().Get(cbs, srcOffset, indexCount * indexSize).Value; Buffer dstBuffer = dstIndexBuffer.GetBuffer().Get(cbs, 0, convertedCount * outputIndexSize).Value;
Buffer dstBuffer = dst.GetBuffer().Get(cbs, 0, convertedCount * outputIndexSize).Value;
gd.Api.CmdFillBuffer(cbs.CommandBuffer, dstBuffer, 0, Vk.WholeSize, 0); const int ParamsBufferSize = 16 * sizeof(int);
List<BufferCopy> bufferCopy = []; Span<int> shaderParams = stackalloc int[ParamsBufferSize / sizeof(int)];
int outputOffset = 0;
// Try to merge copies of adjacent indices to reduce copy count. shaderParams[8] = pattern.PrimitiveVertices;
int sequenceStart = 0; shaderParams[9] = pattern.PrimitiveVerticesOut;
int sequenceLength = 0; shaderParams[10] = indexSize;
shaderParams[11] = outputIndexSize;
shaderParams[12] = pattern.BaseIndex;
shaderParams[13] = pattern.IndexStride;
shaderParams[14] = srcOffset;
shaderParams[15] = primitiveCount;
foreach (int index in pattern.GetIndexMapping(indexCount)) pattern.OffsetIndex.CopyTo(shaderParams[..pattern.OffsetIndex.Length]);
{
if (sequenceLength > 0)
{
if (index == sequenceStart + sequenceLength && indexSize == outputIndexSize)
{
sequenceLength++;
continue;
}
// Commit the copy so far. using var patternScoped = gd.BufferManager.ReserveOrCreate(gd, cbs, ParamsBufferSize);
bufferCopy.Add(new BufferCopy((ulong)(srcOffset + sequenceStart * indexSize), (ulong)outputOffset, (ulong)(indexSize * sequenceLength))); var patternBuffer = patternScoped.Holder;
outputOffset += outputIndexSize * sequenceLength;
}
sequenceStart = index; patternBuffer.SetDataUnchecked<int>(patternScoped.Offset, shaderParams);
sequenceLength = 1;
}
if (sequenceLength > 0) _pipeline.SetCommandBuffer(cbs);
{
// 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);