[Gpu] Declare every parameter the pixel program reads in the paired vertex program
A vertex program declares outputs for the parameters it exports plus as many locations as the
pixel program has inputs. SPI_PS_INPUT_CNTL can map a pixel input to any parameter number,
though, so a pixel program with two inputs may read parameters 4 and 5. Metal requires every
fragment input to be written by the vertex stage, so the pipeline failed to link ("fragment
inputs user(locn4), user(locn5) ... not written by vertex shader"), the command stream slice
failed and Silent Hill stopped rendering at a scene change.
The required output count now covers the highest location the pixel program reads, resolved
through the same input mapping its translator uses; missing exports are zero-filled as before.
The pipeline creation error also names the vertex and pixel programs.
(cherry picked from commit 80ec9fb53cfae922e458e2dd43d4b1010dbd2701)
This commit is contained in:
parent
70d1d2f443
commit
5449fea881
|
|
@ -111,6 +111,9 @@ internal sealed partial class ShaderPipelineCache : IShaderPipelineProvider
|
|||
|
||||
pixelOutputs = ResolveBoundTargets(context, out var outputModes, out var outputMappings);
|
||||
pixelInfo = PixelStageInputResolver.Resolve(_context, pixelSource.Registered, shaderInterface, outputModes, outputMappings, inputCount);
|
||||
// SPI_PS_INPUT_CNTL can map an input to any parameter export, beyond the input count;
|
||||
// the vertex program must declare every location the pixel program reads.
|
||||
attributeCount = Math.Max(attributeCount, ReadVertexOutputCount(pixelProgram, pixelInfo));
|
||||
}
|
||||
|
||||
ShaderProgram vertexProgram;
|
||||
|
|
@ -204,6 +207,32 @@ internal sealed partial class ShaderPipelineCache : IShaderPipelineProvider
|
|||
shaderInterface.VertexOutputControl, clipSpace);
|
||||
}
|
||||
|
||||
// One past the highest parameter location the pixel program reads, resolved as its translator does.
|
||||
private static uint ReadVertexOutputCount(Gen5ShaderProgram pixelProgram, PixelInputInfo info)
|
||||
{
|
||||
var attributes = pixelProgram.Instructions
|
||||
.Select(static instruction => instruction.Control)
|
||||
.OfType<Gen5InterpolationControl>()
|
||||
.Select(static control => control.Attribute)
|
||||
.Distinct()
|
||||
.Order()
|
||||
.ToArray();
|
||||
if (attributes.Length == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var controls = new uint[32];
|
||||
for (var index = 0u; index < (uint)controls.Length; index++)
|
||||
{
|
||||
controls[index] = index < info.InputCount && index < (uint)info.InterpolatorSettings.Length
|
||||
? info.InterpolatorSettings[index]
|
||||
: index;
|
||||
}
|
||||
|
||||
return Gen5PixelInputMapping.ResolveLocations(controls, attributes).Max() + 1;
|
||||
}
|
||||
|
||||
private static uint InterpolatedAttributeCount(Gen5ShaderProgram program)
|
||||
{
|
||||
var maxAttribute = -1;
|
||||
|
|
|
|||
|
|
@ -769,7 +769,8 @@ internal static unsafe partial class VulkanVideoPresenter
|
|||
Layout = layout,
|
||||
};
|
||||
var graphicsStart = Stopwatch.GetTimestamp();
|
||||
Check(_vk.CreateGraphicsPipelines(_device, _pipelineCache, 1, &pipelineInfo, null, out var pipeline), "vkCreateGraphicsPipelines(rendering)");
|
||||
Check(_vk.CreateGraphicsPipelines(_device, _pipelineCache, 1, &pipelineInfo, null, out var pipeline),
|
||||
$"vkCreateGraphicsPipelines(rendering vs=0x{description.VertexStage.Hash:X16} ps=0x{description.PixelStage?.Hash ?? 0:X16})");
|
||||
ReportPipelineCreation(
|
||||
(long)Stopwatch.GetElapsedTime(graphicsStart).TotalMilliseconds,
|
||||
"graphics",
|
||||
|
|
|
|||
Loading…
Reference in New Issue