mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-31 23:19:44 +08:00
Performance Improvements and Optimization Tweaks (#156)
* Improve Gen5 rendering performance and compatibility * Pin .NET SDK for locked restore --------- Co-authored-by: Spooks4576 <Spooks4576@users.noreply.github.com>
This commit is contained in:
@@ -157,7 +157,7 @@ public static class AgcExports
|
||||
private static readonly HashSet<uint> _tracedSubmittedDrawOpcodes = new();
|
||||
private static readonly Dictionary<(ulong Ps, ulong State, Gen5PixelOutputKind Output), byte[]> _pixelSpirvCache = new();
|
||||
private static readonly Dictionary<
|
||||
(ulong Es, ulong EsState, ulong Ps, ulong PsState, Gen5PixelOutputKind Output),
|
||||
(ulong Es, ulong EsState, ulong Ps, ulong PsState, Gen5PixelOutputKind Output, uint Attributes),
|
||||
(byte[] Vertex, byte[] Pixel)> _graphicsSpirvCache = new();
|
||||
private static readonly Dictionary<
|
||||
(ulong Cs, ulong State, uint LocalX, uint LocalY, uint LocalZ),
|
||||
@@ -2019,8 +2019,16 @@ public static class AgcExports
|
||||
var gpuState = _submittedGpuStates.GetValue(ctx.Memory, static _ => new SubmittedGpuState());
|
||||
lock (gpuState.Gate)
|
||||
{
|
||||
ParseSubmittedDcb(ctx, gpuState, gpuState.Graphics, commandAddress, dwordCount, tracePackets);
|
||||
DrainResumableDcbs(ctx, gpuState, tracePackets);
|
||||
Gen5ShaderScalarEvaluator.BeginGlobalMemoryReadScope();
|
||||
try
|
||||
{
|
||||
ParseSubmittedDcb(ctx, gpuState, gpuState.Graphics, commandAddress, dwordCount, tracePackets);
|
||||
DrainResumableDcbs(ctx, gpuState, tracePackets);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Gen5ShaderScalarEvaluator.EndGlobalMemoryReadScope();
|
||||
}
|
||||
}
|
||||
|
||||
ctx[CpuRegister.Rax] = 0;
|
||||
@@ -2050,27 +2058,35 @@ public static class AgcExports
|
||||
var gpuState = _submittedGpuStates.GetValue(ctx.Memory, static _ => new SubmittedGpuState());
|
||||
lock (gpuState.Gate)
|
||||
{
|
||||
for (uint i = 0; i < bufferCount; i++)
|
||||
Gen5ShaderScalarEvaluator.BeginGlobalMemoryReadScope();
|
||||
try
|
||||
{
|
||||
if (!ctx.TryReadUInt64(addressArray + i * 8, out var commandAddress) ||
|
||||
commandAddress == 0 ||
|
||||
!ctx.TryReadUInt32(sizeArray + i * 4, out var dwordCount) ||
|
||||
dwordCount == 0)
|
||||
for (uint i = 0; i < bufferCount; i++)
|
||||
{
|
||||
continue;
|
||||
if (!ctx.TryReadUInt64(addressArray + i * 8, out var commandAddress) ||
|
||||
commandAddress == 0 ||
|
||||
!ctx.TryReadUInt32(sizeArray + i * 4, out var dwordCount) ||
|
||||
dwordCount == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tracePackets)
|
||||
{
|
||||
TraceAgc(
|
||||
$"agc.driver_submit_multi_dcbs index={i}/{bufferCount} " +
|
||||
$"addr=0x{commandAddress:X16} dwords={dwordCount}");
|
||||
}
|
||||
|
||||
ParseSubmittedDcb(ctx, gpuState, gpuState.Graphics, commandAddress, dwordCount, tracePackets);
|
||||
}
|
||||
|
||||
if (tracePackets)
|
||||
{
|
||||
TraceAgc(
|
||||
$"agc.driver_submit_multi_dcbs index={i}/{bufferCount} " +
|
||||
$"addr=0x{commandAddress:X16} dwords={dwordCount}");
|
||||
}
|
||||
|
||||
ParseSubmittedDcb(ctx, gpuState, gpuState.Graphics, commandAddress, dwordCount, tracePackets);
|
||||
DrainResumableDcbs(ctx, gpuState, tracePackets);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Gen5ShaderScalarEvaluator.EndGlobalMemoryReadScope();
|
||||
}
|
||||
|
||||
DrainResumableDcbs(ctx, gpuState, tracePackets);
|
||||
}
|
||||
|
||||
ctx[CpuRegister.Rax] = 0;
|
||||
@@ -2118,8 +2134,16 @@ public static class AgcExports
|
||||
gpuState.ComputeQueues.Add(ownerHandle, queueState);
|
||||
}
|
||||
|
||||
ParseSubmittedDcb(ctx, gpuState, queueState, commandAddress, dwordCount, tracePackets);
|
||||
DrainResumableDcbs(ctx, gpuState, tracePackets);
|
||||
Gen5ShaderScalarEvaluator.BeginGlobalMemoryReadScope();
|
||||
try
|
||||
{
|
||||
ParseSubmittedDcb(ctx, gpuState, queueState, commandAddress, dwordCount, tracePackets);
|
||||
DrainResumableDcbs(ctx, gpuState, tracePackets);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Gen5ShaderScalarEvaluator.EndGlobalMemoryReadScope();
|
||||
}
|
||||
}
|
||||
|
||||
ctx[CpuRegister.Rax] = 0;
|
||||
@@ -3418,7 +3442,8 @@ public static class AgcExports
|
||||
exportState,
|
||||
out var exportEvaluation,
|
||||
out error,
|
||||
resolveVertexInputs: true) ||
|
||||
resolveVertexInputs: true,
|
||||
vertexRecordLimit: indexed ? null : vertexCount) ||
|
||||
!Gen5ShaderTranslator.TryCreateState(
|
||||
ctx,
|
||||
pixelShaderAddress,
|
||||
@@ -3442,14 +3467,19 @@ public static class AgcExports
|
||||
HasPixelColorExport(pixelState, target.Slot))
|
||||
.ToArray();
|
||||
var outputKind = GetPixelOutputKind(renderTargets.FirstOrDefault().NumberType);
|
||||
var exportStateFingerprint = ComputeShaderStateFingerprint(exportEvaluation);
|
||||
var pixelStateFingerprint = ComputeShaderStateFingerprint(pixelEvaluation);
|
||||
var attributeCount = GetInterpolatedAttributeCount(pixelState);
|
||||
var exportStateFingerprint = ComputeShaderStructureFingerprint(exportEvaluation);
|
||||
var pixelStateFingerprint = ComputeShaderStructureFingerprint(pixelEvaluation);
|
||||
var shaderKey = (
|
||||
exportShaderAddress,
|
||||
exportStateFingerprint,
|
||||
pixelShaderAddress,
|
||||
pixelStateFingerprint,
|
||||
outputKind);
|
||||
outputKind,
|
||||
attributeCount);
|
||||
var totalGlobalBuffers =
|
||||
pixelEvaluation.GlobalMemoryBindings.Count +
|
||||
exportEvaluation.GlobalMemoryBindings.Count;
|
||||
(byte[] Vertex, byte[] Pixel) compiled;
|
||||
lock (_submitTraceGate)
|
||||
{
|
||||
@@ -3458,9 +3488,6 @@ public static class AgcExports
|
||||
|
||||
if (compiled.Vertex is null || compiled.Pixel is null)
|
||||
{
|
||||
var totalGlobalBuffers =
|
||||
pixelEvaluation.GlobalMemoryBindings.Count +
|
||||
exportEvaluation.GlobalMemoryBindings.Count;
|
||||
if (!Gen5SpirvTranslator.TryCompilePixelShader(
|
||||
pixelState,
|
||||
pixelEvaluation,
|
||||
@@ -3468,16 +3495,18 @@ public static class AgcExports
|
||||
out var pixelShader,
|
||||
out error,
|
||||
globalBufferBase: 0,
|
||||
totalGlobalBufferCount: totalGlobalBuffers,
|
||||
imageBindingBase: 0) ||
|
||||
totalGlobalBufferCount: totalGlobalBuffers + 2,
|
||||
imageBindingBase: 0,
|
||||
scalarRegisterBufferIndex: totalGlobalBuffers) ||
|
||||
!Gen5SpirvTranslator.TryCompileVertexShader(
|
||||
exportState,
|
||||
exportEvaluation,
|
||||
out var vertexShader,
|
||||
out error,
|
||||
globalBufferBase: pixelEvaluation.GlobalMemoryBindings.Count,
|
||||
totalGlobalBufferCount: totalGlobalBuffers,
|
||||
imageBindingBase: pixelEvaluation.ImageBindings.Count))
|
||||
totalGlobalBufferCount: totalGlobalBuffers + 2,
|
||||
imageBindingBase: pixelEvaluation.ImageBindings.Count,
|
||||
scalarRegisterBufferIndex: totalGlobalBuffers + 1))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -3529,6 +3558,8 @@ public static class AgcExports
|
||||
|
||||
var globalMemoryBindings = pixelEvaluation.GlobalMemoryBindings
|
||||
.Concat(exportEvaluation.GlobalMemoryBindings)
|
||||
.Append(CreateScalarRegisterBinding(pixelEvaluation))
|
||||
.Append(CreateScalarRegisterBinding(exportEvaluation))
|
||||
.ToArray();
|
||||
IReadOnlyList<Gen5VertexInputBinding> vertexInputs =
|
||||
exportEvaluation.VertexInputs ?? [];
|
||||
@@ -3539,7 +3570,7 @@ public static class AgcExports
|
||||
primitiveType,
|
||||
compiled.Vertex,
|
||||
compiled.Pixel,
|
||||
GetInterpolatedAttributeCount(pixelState),
|
||||
attributeCount,
|
||||
vertexCount,
|
||||
state.InstanceCount,
|
||||
indexed ? CreateVulkanIndexBuffer(ctx, state, vertexCount) : null,
|
||||
@@ -3651,6 +3682,88 @@ public static class AgcExports
|
||||
return (uint)(maxAttribute + 1);
|
||||
}
|
||||
|
||||
private const int ShaderScalarRegisterCount = 256;
|
||||
|
||||
private static Gen5GlobalMemoryBinding CreateScalarRegisterBinding(
|
||||
Gen5ShaderEvaluation evaluation)
|
||||
{
|
||||
var data = new byte[ShaderScalarRegisterCount * sizeof(uint)];
|
||||
var registers = evaluation.InitialScalarRegisters;
|
||||
var count = Math.Min(registers.Count, ShaderScalarRegisterCount);
|
||||
for (var index = 0; index < count; index++)
|
||||
{
|
||||
var value = registers[index];
|
||||
var offset = index * sizeof(uint);
|
||||
data[offset] = (byte)value;
|
||||
data[offset + 1] = (byte)(value >> 8);
|
||||
data[offset + 2] = (byte)(value >> 16);
|
||||
data[offset + 3] = (byte)(value >> 24);
|
||||
}
|
||||
|
||||
return new Gen5GlobalMemoryBinding(0, 0, [], data);
|
||||
}
|
||||
|
||||
private static ulong ComputeShaderStructureFingerprint(Gen5ShaderEvaluation evaluation)
|
||||
{
|
||||
const ulong offsetBasis = 14695981039346656037UL;
|
||||
const ulong prime = 1099511628211UL;
|
||||
var hash = offsetBasis;
|
||||
void Mix(ulong value) => hash = (hash ^ value) * prime;
|
||||
|
||||
Mix((ulong)evaluation.GlobalMemoryBindings.Count);
|
||||
foreach (var binding in evaluation.GlobalMemoryBindings)
|
||||
{
|
||||
Mix(binding.ScalarAddress);
|
||||
Mix((ulong)binding.InstructionPcs.Count);
|
||||
foreach (var pc in binding.InstructionPcs)
|
||||
{
|
||||
Mix(pc);
|
||||
}
|
||||
}
|
||||
|
||||
Mix((ulong)evaluation.ImageBindings.Count);
|
||||
foreach (var image in evaluation.ImageBindings)
|
||||
{
|
||||
Mix(image.Pc);
|
||||
Mix((ulong)(uint)image.Opcode.GetHashCode());
|
||||
foreach (var word in image.ResourceDescriptor)
|
||||
{
|
||||
Mix(word);
|
||||
}
|
||||
|
||||
foreach (var word in image.SamplerDescriptor)
|
||||
{
|
||||
Mix(word);
|
||||
}
|
||||
|
||||
Mix(image.MipLevel ?? uint.MaxValue);
|
||||
}
|
||||
|
||||
if (evaluation.VertexInputs is { } vertexInputs)
|
||||
{
|
||||
Mix((ulong)vertexInputs.Count);
|
||||
foreach (var input in vertexInputs)
|
||||
{
|
||||
Mix(input.Pc);
|
||||
Mix(input.Location);
|
||||
Mix(input.ComponentCount);
|
||||
Mix(input.DataFormat);
|
||||
Mix(input.NumberFormat);
|
||||
Mix(input.Stride);
|
||||
}
|
||||
}
|
||||
|
||||
if (evaluation.ComputeSystemRegisters is { } computeSystemRegisters)
|
||||
{
|
||||
Mix(computeSystemRegisters.WorkGroupXRegister ?? uint.MaxValue);
|
||||
Mix(computeSystemRegisters.WorkGroupYRegister ?? uint.MaxValue);
|
||||
Mix(computeSystemRegisters.WorkGroupZRegister ?? uint.MaxValue);
|
||||
Mix(computeSystemRegisters.ThreadGroupSizeRegister ?? uint.MaxValue);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
private static ulong ComputeShaderStateFingerprint(Gen5ShaderEvaluation evaluation)
|
||||
{
|
||||
const ulong offsetBasis = 14695981039346656037UL;
|
||||
|
||||
@@ -13,6 +13,24 @@ internal static class Gen5ShaderScalarEvaluator
|
||||
private const int ImageDescriptorDwords = 8;
|
||||
private const int SamplerDescriptorDwords = 4;
|
||||
private const int MaxGlobalMemoryBindingBytes = 16 * 1024 * 1024;
|
||||
private static readonly int DefaultGlobalMemoryBindingBytes =
|
||||
int.TryParse(
|
||||
Environment.GetEnvironmentVariable("SHARPEMU_GLOBAL_BINDING_BYTES"),
|
||||
out var configured) && configured >= sizeof(uint)
|
||||
? Math.Min(configured, MaxGlobalMemoryBindingBytes)
|
||||
: 1 * 1024 * 1024;
|
||||
|
||||
internal static long GlobalMemoryReadCount;
|
||||
internal static long GlobalMemoryReadBytes;
|
||||
internal static long GlobalMemoryReadCacheHits;
|
||||
internal static long GlobalMemoryReadPvmBytes;
|
||||
internal static long GlobalMemoryReadLibcBytes;
|
||||
internal static long GlobalMemoryReadReuses;
|
||||
|
||||
private const long CrossFrameReadCacheMaxBytes = 1024L * 1024 * 1024;
|
||||
private static readonly object _crossFrameReadGate = new();
|
||||
private static readonly Dictionary<(ulong BaseAddress, int SizeBytes), byte[]> _crossFrameReadCache = new();
|
||||
private static long _crossFrameReadCacheBytes;
|
||||
private const ulong RdnaWaveMask = 0xFFFF_FFFFUL;
|
||||
|
||||
private readonly record struct BufferDescriptor(
|
||||
@@ -44,7 +62,8 @@ internal static class Gen5ShaderScalarEvaluator
|
||||
Gen5ShaderState state,
|
||||
out Gen5ShaderEvaluation evaluation,
|
||||
out string error,
|
||||
bool resolveVertexInputs = false)
|
||||
bool resolveVertexInputs = false,
|
||||
uint? vertexRecordLimit = null)
|
||||
{
|
||||
evaluation = default!;
|
||||
error = string.Empty;
|
||||
@@ -255,10 +274,28 @@ internal static class Gen5ShaderScalarEvaluator
|
||||
if (resolveVertexInputs &&
|
||||
IsVertexFetchCandidate(instruction, bufferMemory, bufferDescriptor))
|
||||
{
|
||||
var vertexReadSize = bufferDescriptor.SizeBytes;
|
||||
if (vertexRecordLimit is { } recordLimit &&
|
||||
instruction.Sources.Count > 2 &&
|
||||
TryEvaluateScalarOperand(
|
||||
instruction.Sources[2],
|
||||
scalarRegisters,
|
||||
out var scalarOffset))
|
||||
{
|
||||
var bindingOffset = unchecked((uint)bufferMemory.OffsetBytes + scalarOffset);
|
||||
var requiredBytes =
|
||||
(ulong)bindingOffset +
|
||||
(ulong)(Math.Max(recordLimit, 1u) - 1u) * bufferDescriptor.Stride +
|
||||
(ulong)bufferMemory.DwordCount * sizeof(uint);
|
||||
vertexReadSize = Math.Min(
|
||||
bufferDescriptor.SizeBytes,
|
||||
Math.Max(requiredBytes, sizeof(uint)));
|
||||
}
|
||||
|
||||
if (!TryReadGlobalMemory(
|
||||
ctx,
|
||||
bufferDescriptor.BaseAddress,
|
||||
bufferDescriptor.SizeBytes,
|
||||
vertexReadSize,
|
||||
out var vertexData))
|
||||
{
|
||||
error =
|
||||
@@ -533,22 +570,29 @@ internal static class Gen5ShaderScalarEvaluator
|
||||
return false;
|
||||
}
|
||||
|
||||
[ThreadStatic]
|
||||
private static Dictionary<(ulong BaseAddress, int SizeBytes), byte[]>? _globalMemoryReadCache;
|
||||
|
||||
internal static void BeginGlobalMemoryReadScope()
|
||||
{
|
||||
_globalMemoryReadCache = new Dictionary<(ulong, int), byte[]>();
|
||||
}
|
||||
|
||||
internal static void EndGlobalMemoryReadScope()
|
||||
{
|
||||
_globalMemoryReadCache = null;
|
||||
}
|
||||
|
||||
private static bool TryReadGlobalMemory(
|
||||
CpuContext ctx,
|
||||
ulong baseAddress,
|
||||
out byte[] data)
|
||||
{
|
||||
for (var size = MaxGlobalMemoryBindingBytes; size >= 4096; size >>= 1)
|
||||
{
|
||||
data = GC.AllocateUninitializedArray<byte>(size);
|
||||
if (ctx.Memory.TryRead(baseAddress, data))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
data = [];
|
||||
return false;
|
||||
return TryReadGlobalMemory(
|
||||
ctx,
|
||||
baseAddress,
|
||||
(ulong)DefaultGlobalMemoryBindingBytes,
|
||||
out data);
|
||||
}
|
||||
|
||||
private static bool TryReadGlobalMemory(
|
||||
@@ -570,13 +614,74 @@ internal static class Gen5ShaderScalarEvaluator
|
||||
return false;
|
||||
}
|
||||
|
||||
var cache = _globalMemoryReadCache;
|
||||
var cacheKey = (baseAddress, (int)cappedSize);
|
||||
if (cache is not null && cache.TryGetValue(cacheKey, out var cached))
|
||||
{
|
||||
Interlocked.Increment(ref GlobalMemoryReadCacheHits);
|
||||
data = cached;
|
||||
return true;
|
||||
}
|
||||
|
||||
byte[]? previous;
|
||||
lock (_crossFrameReadGate)
|
||||
{
|
||||
_crossFrameReadCache.TryGetValue(cacheKey, out previous);
|
||||
}
|
||||
|
||||
if (previous is not null && ctx.Memory.TryCompare(baseAddress, previous))
|
||||
{
|
||||
Interlocked.Increment(ref GlobalMemoryReadReuses);
|
||||
if (cache is not null)
|
||||
{
|
||||
cache[cacheKey] = previous;
|
||||
}
|
||||
|
||||
data = previous;
|
||||
return true;
|
||||
}
|
||||
|
||||
var candidateSize = (int)cappedSize;
|
||||
while (candidateSize >= sizeof(uint))
|
||||
{
|
||||
data = GC.AllocateUninitializedArray<byte>(candidateSize);
|
||||
if (ctx.Memory.TryRead(baseAddress, data) ||
|
||||
var readFromPvm = ctx.Memory.TryRead(baseAddress, data);
|
||||
if (readFromPvm ||
|
||||
KernelMemoryCompatExports.TryReadTrackedLibcHeap(baseAddress, data))
|
||||
{
|
||||
Interlocked.Increment(ref GlobalMemoryReadCount);
|
||||
Interlocked.Add(ref GlobalMemoryReadBytes, data.Length);
|
||||
if (readFromPvm)
|
||||
{
|
||||
Interlocked.Add(ref GlobalMemoryReadPvmBytes, data.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
Interlocked.Add(ref GlobalMemoryReadLibcBytes, data.Length);
|
||||
}
|
||||
|
||||
if (cache is not null)
|
||||
{
|
||||
cache[cacheKey] = data;
|
||||
}
|
||||
|
||||
lock (_crossFrameReadGate)
|
||||
{
|
||||
if (_crossFrameReadCache.TryGetValue(cacheKey, out var replaced))
|
||||
{
|
||||
_crossFrameReadCacheBytes -= replaced.Length;
|
||||
}
|
||||
|
||||
if (_crossFrameReadCacheBytes + data.Length > CrossFrameReadCacheMaxBytes)
|
||||
{
|
||||
_crossFrameReadCache.Clear();
|
||||
_crossFrameReadCacheBytes = 0;
|
||||
}
|
||||
|
||||
_crossFrameReadCache[cacheKey] = data;
|
||||
_crossFrameReadCacheBytes += data.Length;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,8 @@ internal static partial class Gen5SpirvTranslator
|
||||
out string error,
|
||||
int globalBufferBase = 0,
|
||||
int totalGlobalBufferCount = -1,
|
||||
int imageBindingBase = 0)
|
||||
int imageBindingBase = 0,
|
||||
int scalarRegisterBufferIndex = -1)
|
||||
{
|
||||
var context = new CompilationContext(
|
||||
Gen5SpirvStage.Pixel,
|
||||
@@ -30,7 +31,8 @@ internal static partial class Gen5SpirvTranslator
|
||||
1,
|
||||
globalBufferBase,
|
||||
totalGlobalBufferCount,
|
||||
imageBindingBase);
|
||||
imageBindingBase,
|
||||
scalarRegisterBufferIndex);
|
||||
return context.TryCompile(out shader, out error);
|
||||
}
|
||||
|
||||
@@ -41,7 +43,8 @@ internal static partial class Gen5SpirvTranslator
|
||||
out string error,
|
||||
int globalBufferBase = 0,
|
||||
int totalGlobalBufferCount = -1,
|
||||
int imageBindingBase = 0)
|
||||
int imageBindingBase = 0,
|
||||
int scalarRegisterBufferIndex = -1)
|
||||
{
|
||||
var context = new CompilationContext(
|
||||
Gen5SpirvStage.Vertex,
|
||||
@@ -53,7 +56,8 @@ internal static partial class Gen5SpirvTranslator
|
||||
1,
|
||||
globalBufferBase,
|
||||
totalGlobalBufferCount,
|
||||
imageBindingBase);
|
||||
imageBindingBase,
|
||||
scalarRegisterBufferIndex);
|
||||
return context.TryCompile(out shader, out error);
|
||||
}
|
||||
|
||||
@@ -76,7 +80,8 @@ internal static partial class Gen5SpirvTranslator
|
||||
Math.Max(localSizeZ, 1),
|
||||
0,
|
||||
-1,
|
||||
0);
|
||||
0,
|
||||
-1);
|
||||
return context.TryCompile(out shader, out error);
|
||||
}
|
||||
|
||||
@@ -93,6 +98,7 @@ internal static partial class Gen5SpirvTranslator
|
||||
private readonly int _globalBufferBase;
|
||||
private readonly int _totalGlobalBufferCount;
|
||||
private readonly int _imageBindingBase;
|
||||
private readonly int _scalarRegisterBufferIndex;
|
||||
private readonly List<uint> _interfaces = [];
|
||||
private readonly Dictionary<uint, uint> _pixelInputs = [];
|
||||
private readonly Dictionary<uint, uint> _vertexOutputs = [];
|
||||
@@ -167,7 +173,8 @@ internal static partial class Gen5SpirvTranslator
|
||||
uint localSizeZ,
|
||||
int globalBufferBase,
|
||||
int totalGlobalBufferCount,
|
||||
int imageBindingBase)
|
||||
int imageBindingBase,
|
||||
int scalarRegisterBufferIndex)
|
||||
{
|
||||
_stage = stage;
|
||||
_state = state;
|
||||
@@ -181,6 +188,7 @@ internal static partial class Gen5SpirvTranslator
|
||||
? evaluation.GlobalMemoryBindings.Count
|
||||
: totalGlobalBufferCount;
|
||||
_imageBindingBase = imageBindingBase;
|
||||
_scalarRegisterBufferIndex = scalarRegisterBufferIndex;
|
||||
}
|
||||
|
||||
public bool TryCompile(out Gen5SpirvShader shader, out string error)
|
||||
@@ -767,15 +775,25 @@ internal static partial class Gen5SpirvTranslator
|
||||
|
||||
private void EmitInitialState()
|
||||
{
|
||||
for (uint index = 0;
|
||||
index < _evaluation.InitialScalarRegisters.Count &&
|
||||
index < ScalarRegisterCount;
|
||||
index++)
|
||||
if (_scalarRegisterBufferIndex >= 0)
|
||||
{
|
||||
var value = _evaluation.InitialScalarRegisters[(int)index];
|
||||
if (value != 0)
|
||||
for (uint index = 0; index < ScalarRegisterCount; index++)
|
||||
{
|
||||
StoreS(index, UInt(value));
|
||||
StoreS(index, LoadBufferWord(_scalarRegisterBufferIndex, UInt(index)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint index = 0;
|
||||
index < _evaluation.InitialScalarRegisters.Count &&
|
||||
index < ScalarRegisterCount;
|
||||
index++)
|
||||
{
|
||||
var value = _evaluation.InitialScalarRegisters[(int)index];
|
||||
if (value != 0)
|
||||
{
|
||||
StoreS(index, UInt(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user