144 lines
4.6 KiB
C++
144 lines
4.6 KiB
C++
//===- HLSLRootSignatureValidations.cpp - HLSL Root Signature helpers -----===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
///
|
|
/// \file This file contains helpers for working with HLSL Root Signatures.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/Frontend/HLSL/RootSignatureValidations.h"
|
|
|
|
#include <cmath>
|
|
|
|
namespace llvm {
|
|
namespace hlsl {
|
|
namespace rootsig {
|
|
|
|
bool verifyRootFlag(uint32_t Flags) { return (Flags & ~0xfff) == 0; }
|
|
|
|
bool verifyVersion(uint32_t Version) { return (Version == 1 || Version == 2); }
|
|
|
|
bool verifyRegisterValue(uint32_t RegisterValue) {
|
|
return RegisterValue != ~0U;
|
|
}
|
|
|
|
// This Range is reserverved, therefore invalid, according to the spec
|
|
// https://github.com/llvm/wg-hlsl/blob/main/proposals/0002-root-signature-in-clang.md#all-the-values-should-be-legal
|
|
bool verifyRegisterSpace(uint32_t RegisterSpace) {
|
|
return !(RegisterSpace >= 0xFFFFFFF0);
|
|
}
|
|
|
|
bool verifyRootDescriptorFlag(uint32_t Version, uint32_t FlagsVal) {
|
|
using FlagT = dxbc::RootDescriptorFlags;
|
|
FlagT Flags = FlagT(FlagsVal);
|
|
if (Version == 1)
|
|
return Flags == FlagT::DataVolatile;
|
|
|
|
assert(Version == 2 && "Provided invalid root signature version");
|
|
|
|
// The data-specific flags are mutually exclusive.
|
|
FlagT DataFlags = FlagT::DataVolatile | FlagT::DataStatic |
|
|
FlagT::DataStaticWhileSetAtExecute;
|
|
|
|
if (popcount(llvm::to_underlying(Flags & DataFlags)) > 1)
|
|
return false;
|
|
|
|
// Only a data flag or no flags is valid
|
|
return (Flags | DataFlags) == DataFlags;
|
|
}
|
|
|
|
bool verifyRangeType(uint32_t Type) {
|
|
switch (Type) {
|
|
case llvm::to_underlying(dxbc::DescriptorRangeType::CBV):
|
|
case llvm::to_underlying(dxbc::DescriptorRangeType::SRV):
|
|
case llvm::to_underlying(dxbc::DescriptorRangeType::UAV):
|
|
case llvm::to_underlying(dxbc::DescriptorRangeType::Sampler):
|
|
return true;
|
|
};
|
|
|
|
return false;
|
|
}
|
|
|
|
bool verifyDescriptorRangeFlag(uint32_t Version, dxbc::DescriptorRangeType Type,
|
|
uint32_t FlagsVal) {
|
|
using FlagT = dxbc::DescriptorRangeFlags;
|
|
FlagT Flags = FlagT(FlagsVal);
|
|
|
|
const bool IsSampler = (Type == dxbc::DescriptorRangeType::Sampler);
|
|
|
|
if (Version == 1) {
|
|
// Since the metadata is unversioned, we expect to explicitly see the values
|
|
// that map to the version 1 behaviour here.
|
|
if (IsSampler)
|
|
return Flags == FlagT::DescriptorsVolatile;
|
|
return Flags == (FlagT::DataVolatile | FlagT::DescriptorsVolatile);
|
|
}
|
|
|
|
// The data-specific flags are mutually exclusive.
|
|
FlagT DataFlags = FlagT::DataVolatile | FlagT::DataStatic |
|
|
FlagT::DataStaticWhileSetAtExecute;
|
|
|
|
if (popcount(llvm::to_underlying(Flags & DataFlags)) > 1)
|
|
return false;
|
|
|
|
// The descriptor-specific flags are mutually exclusive.
|
|
FlagT DescriptorFlags = FlagT::DescriptorsStaticKeepingBufferBoundsChecks |
|
|
FlagT::DescriptorsVolatile;
|
|
if (popcount(llvm::to_underlying(Flags & DescriptorFlags)) > 1)
|
|
return false;
|
|
|
|
// For volatile descriptors, DATA_is never valid.
|
|
if ((Flags & FlagT::DescriptorsVolatile) == FlagT::DescriptorsVolatile) {
|
|
FlagT Mask = FlagT::DescriptorsVolatile;
|
|
if (!IsSampler) {
|
|
Mask |= FlagT::DataVolatile;
|
|
Mask |= FlagT::DataStaticWhileSetAtExecute;
|
|
}
|
|
return (Flags & ~Mask) == FlagT::None;
|
|
}
|
|
|
|
// For "KEEPING_BUFFER_BOUNDS_CHECKS" descriptors,
|
|
// the other data-specific flags may all be set.
|
|
if ((Flags & FlagT::DescriptorsStaticKeepingBufferBoundsChecks) ==
|
|
FlagT::DescriptorsStaticKeepingBufferBoundsChecks) {
|
|
FlagT Mask = FlagT::DescriptorsStaticKeepingBufferBoundsChecks;
|
|
if (!IsSampler) {
|
|
Mask |= FlagT::DataVolatile;
|
|
Mask |= FlagT::DataStatic;
|
|
Mask |= FlagT::DataStaticWhileSetAtExecute;
|
|
}
|
|
return (Flags & ~Mask) == FlagT::None;
|
|
}
|
|
|
|
// When no descriptor flag is set, any data flag is allowed.
|
|
FlagT Mask = FlagT::None;
|
|
if (!IsSampler) {
|
|
Mask |= FlagT::DataVolatile;
|
|
Mask |= FlagT::DataStaticWhileSetAtExecute;
|
|
Mask |= FlagT::DataStatic;
|
|
}
|
|
return (Flags & ~Mask) == FlagT::None;
|
|
}
|
|
|
|
bool verifyNumDescriptors(uint32_t NumDescriptors) {
|
|
return NumDescriptors > 0;
|
|
}
|
|
|
|
bool verifyMipLODBias(float MipLODBias) {
|
|
return MipLODBias >= -16.f && MipLODBias <= 15.99f;
|
|
}
|
|
|
|
bool verifyMaxAnisotropy(uint32_t MaxAnisotropy) {
|
|
return MaxAnisotropy <= 16u;
|
|
}
|
|
|
|
bool verifyLOD(float LOD) { return !std::isnan(LOD); }
|
|
|
|
} // namespace rootsig
|
|
} // namespace hlsl
|
|
} // namespace llvm
|