Skip to content

Commit

Permalink
Vulkan: Extend full bindless to cover cases with phi nodes (#6853)
Browse files Browse the repository at this point in the history
* Key textures using set and binding (rather than just binding)

* Extend full bindless to cover cases with phi nodes

* Log error on bindless access failure

* Shader cache version bump

* Remove constant buffer match to reduce the chances of full bindless triggering

* Re-enable it for constant buffers, paper mario does actually need it

* Format whitespace
  • Loading branch information
gdkchan committed May 26, 2024
1 parent 2ebe929 commit c41fddd
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class DiskCacheHostStorage
private const ushort FileFormatVersionMajor = 1;
private const ushort FileFormatVersionMinor = 2;
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
private const uint CodeGenVersion = 6870;
private const uint CodeGenVersion = 6852;

private const string SharedTocFileName = "shared.toc";
private const string SharedDataFileName = "shared.data";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ public static void RunPass(BasicBlock block, ResourceManager resourceManager, IG
// If we can't do bindless elimination, remove the texture operation.
// Set any destination variables to zero.

string typeName = texOp.Inst.IsImage()
? texOp.Type.ToGlslImageType(texOp.Format.GetComponentType())
: texOp.Type.ToGlslTextureType();

gpuAccessor.Log($"Failed to find handle source for bindless access of type \"{typeName}\".");

for (int destIndex = 0; destIndex < texOp.DestsCount; destIndex++)
{
block.Operations.AddBefore(node, new Operation(Instruction.Copy, texOp.GetDest(destIndex), OperandHelper.Const(0)));
Expand All @@ -62,26 +68,31 @@ public static void RunPass(BasicBlock block, ResourceManager resourceManager, IG
return false;
}

Operand nvHandle = texOp.GetSource(0);
Operand bindlessHandle = texOp.GetSource(0);

if (nvHandle.AsgOp is not Operation handleOp ||
handleOp.Inst != Instruction.Load ||
(handleOp.StorageKind != StorageKind.Input && handleOp.StorageKind != StorageKind.StorageBuffer))
if (bindlessHandle.AsgOp is PhiNode phi)
{
// Right now, we only allow bindless access when the handle comes from a shader input or storage buffer.
// This is an artificial limitation to prevent it from being used in cases where it
// would have a large performance impact of loading all textures in the pool.
// It might be removed in the future, if we can mitigate the performance impact.
for (int srcIndex = 0; srcIndex < phi.SourcesCount; srcIndex++)
{
Operand phiSource = phi.GetSource(srcIndex);

if (phiSource.AsgOp is not PhiNode && !IsBindlessAccessAllowed(phiSource))
{
return false;
}
}
}
else if (!IsBindlessAccessAllowed(bindlessHandle))
{
return false;
}

Operand textureHandle = OperandHelper.Local();
Operand samplerHandle = OperandHelper.Local();
Operand textureIndex = OperandHelper.Local();

block.Operations.AddBefore(node, new Operation(Instruction.BitwiseAnd, textureHandle, nvHandle, OperandHelper.Const(0xfffff)));
block.Operations.AddBefore(node, new Operation(Instruction.ShiftRightU32, samplerHandle, nvHandle, OperandHelper.Const(20)));
block.Operations.AddBefore(node, new Operation(Instruction.BitwiseAnd, textureHandle, bindlessHandle, OperandHelper.Const(0xfffff)));
block.Operations.AddBefore(node, new Operation(Instruction.ShiftRightU32, samplerHandle, bindlessHandle, OperandHelper.Const(20)));

int texturePoolLength = Math.Max(BindlessToArray.MinimumArrayLength, gpuAccessor.QueryTextureArrayLengthFromPool());

Expand Down Expand Up @@ -130,6 +141,30 @@ public static void RunPass(BasicBlock block, ResourceManager resourceManager, IG
return true;
}

private static bool IsBindlessAccessAllowed(Operand nvHandle)
{
if (nvHandle.Type == OperandType.ConstantBuffer)
{
// Bindless access with handles from constant buffer is allowed.

return true;
}

if (nvHandle.AsgOp is not Operation handleOp ||
handleOp.Inst != Instruction.Load ||
(handleOp.StorageKind != StorageKind.Input && handleOp.StorageKind != StorageKind.StorageBuffer))
{
// Right now, we only allow bindless access when the handle comes from a shader input or storage buffer.
// This is an artificial limitation to prevent it from being used in cases where it
// would have a large performance impact of loading all textures in the pool.
// It might be removed in the future, if we can mitigate the performance impact.

return false;
}

return true;
}

private static bool TryConvertBindless(BasicBlock block, ResourceManager resourceManager, IGpuAccessor gpuAccessor, TextureOperation texOp)
{
if (texOp.Inst == Instruction.TextureSample || texOp.Inst.IsTextureQuery())
Expand Down

0 comments on commit c41fddd

Please sign in to comment.