blob: 425ec4e3910288b71eacaff808e045db488ca2e3 [file] [log] [blame] [edit]
///////////////////////////////////////////////////////////////////////////////
// //
// DxilFunctionProps.h //
// Copyright (C) Microsoft Corporation. All rights reserved. //
// This file is distributed under the University of Illinois Open Source //
// License. See LICENSE.TXT for details. //
// //
// Function properties for a dxil shader function. //
// //
///////////////////////////////////////////////////////////////////////////////
#pragma once
// for memset dependency:
#include <cstring>
#include <vector>
#include "dxc/DXIL/DxilConstants.h"
#include "dxc/DXIL/DxilNodeProps.h"
#include "llvm/ADT/StringRef.h"
namespace llvm {
class Function;
class Constant;
} // namespace llvm
namespace hlsl {
// SM 6.6 allows WaveSize specification for only a single required size.
// SM 6.8+ allows specification of WaveSize as a min, max and preferred value.
struct DxilWaveSize {
unsigned Min = 0;
unsigned Max = 0;
unsigned Preferred = 0;
DxilWaveSize() = default;
DxilWaveSize(unsigned min, unsigned max = 0, unsigned preferred = 0)
: Min(min), Max(max), Preferred(preferred) {}
DxilWaveSize(const DxilWaveSize &other) = default;
DxilWaveSize &operator=(const DxilWaveSize &other) = default;
bool operator==(const DxilWaveSize &other) const {
return Min == other.Min && Max == other.Max && Preferred == other.Preferred;
}
// Create DxilWaveSize, translating potential degenerate cases.
static DxilWaveSize Translate(unsigned min, unsigned max = 0,
unsigned preferred = 0) {
if (max == min)
max = 0;
if (max == 0 && preferred == min)
preferred = 0;
return DxilWaveSize(min, max, preferred);
}
// Valid non-zero values are powers of 2 between 4 and 128, inclusive.
static bool IsValidValue(unsigned Value) {
return (Value >= 4 && Value <= 128 && ((Value & (Value - 1)) == 0));
}
// Valid representations:
// (not to be confused with encodings in metadata, PSV0, or RDAT)
// 0, 0, 0: Not defined
// Min, 0, 0: single WaveSize (SM 6.6/6.7)
// (single WaveSize is represented in metadata with the single Min value)
// Min, Max (> Min), 0 or Preferred (>= Min and <= Max): Range (SM 6.8+)
// (WaveSizeRange represenation in metadata is the same)
enum class ValidationResult {
Success,
InvalidMin,
InvalidMax,
InvalidPreferred,
MaxOrPreferredWhenUndefined,
PreferredWhenNoRange,
MaxEqualsMin,
MaxLessThanMin,
PreferredOutOfRange,
NoRangeOrMin,
};
ValidationResult Validate() const {
if (Min == 0) { // Not defined
if (Max != 0 || Preferred != 0)
return ValidationResult::MaxOrPreferredWhenUndefined;
else
// all 3 parameters are 0
return ValidationResult::NoRangeOrMin;
} else if (!IsValidValue(Min)) {
return ValidationResult::InvalidMin;
} else if (Max == 0) { // single WaveSize (SM 6.6/6.7)
if (Preferred != 0)
return ValidationResult::PreferredWhenNoRange;
} else if (!IsValidValue(Max)) {
return ValidationResult::InvalidMax;
} else if (Min == Max) {
return ValidationResult::MaxEqualsMin;
} else if (Max < Min) {
return ValidationResult::MaxLessThanMin;
} else if (Preferred != 0) {
if (!IsValidValue(Preferred))
return ValidationResult::InvalidPreferred;
if (Preferred < Min || Preferred > Max)
return ValidationResult::PreferredOutOfRange;
}
return ValidationResult::Success;
}
bool IsValid() const { return Validate() == ValidationResult::Success; }
bool IsDefined() const { return Min != 0; }
bool IsRange() const { return Max != 0; }
bool HasPreferred() const { return Preferred != 0; }
};
struct DxilFunctionProps {
DxilFunctionProps() {
memset(&ShaderProps, 0, sizeof(ShaderProps));
shaderKind = DXIL::ShaderKind::Invalid;
NodeShaderID = {};
NodeShaderSharedInput = {};
memset(&Node, 0, sizeof(Node));
Node.LaunchType = DXIL::NodeLaunchType::Invalid;
Node.LocalRootArgumentsTableIndex = -1;
}
union {
// Geometry shader.
struct {
DXIL::InputPrimitive inputPrimitive;
unsigned maxVertexCount;
unsigned instanceCount;
DXIL::PrimitiveTopology
streamPrimitiveTopologies[DXIL::kNumOutputStreams];
} GS;
// Hull shader.
struct {
llvm::Function *patchConstantFunc;
DXIL::TessellatorDomain domain;
DXIL::TessellatorPartitioning partition;
DXIL::TessellatorOutputPrimitive outputPrimitive;
unsigned inputControlPoints;
unsigned outputControlPoints;
float maxTessFactor;
} HS;
// Domain shader.
struct {
DXIL::TessellatorDomain domain;
unsigned inputControlPoints;
} DS;
// Vertex shader.
struct {
llvm::Constant *clipPlanes[DXIL::kNumClipPlanes];
} VS;
// Pixel shader.
struct {
bool EarlyDepthStencil;
} PS;
// Ray Tracing shaders
struct {
union {
unsigned payloadSizeInBytes;
unsigned paramSizeInBytes;
};
unsigned attributeSizeInBytes;
} Ray;
// Mesh shader.
struct {
unsigned maxVertexCount;
unsigned maxPrimitiveCount;
DXIL::MeshOutputTopology outputTopology;
unsigned payloadSizeInBytes;
} MS;
// Amplification shader.
struct {
unsigned payloadSizeInBytes;
} AS;
} ShaderProps;
// numThreads shared between multiple shader types and node shaders.
unsigned numThreads[3];
struct NodeProps {
DXIL::NodeLaunchType LaunchType = DXIL::NodeLaunchType::Invalid;
bool IsProgramEntry;
int LocalRootArgumentsTableIndex;
unsigned DispatchGrid[3];
unsigned MaxDispatchGrid[3];
unsigned MaxRecursionDepth;
} Node;
DXIL::ShaderKind shaderKind;
NodeID NodeShaderID;
NodeID NodeShaderSharedInput;
std::vector<NodeIOProperties> InputNodes;
std::vector<NodeIOProperties> OutputNodes;
DxilWaveSize WaveSize;
// Save root signature for lib profile entry.
std::vector<uint8_t> serializedRootSignature;
void SetSerializedRootSignature(const uint8_t *pData, unsigned size) {
serializedRootSignature.assign(pData, pData + size);
}
// TODO: Should we have an unmangled name here for ray tracing shaders?
bool IsPS() const { return shaderKind == DXIL::ShaderKind::Pixel; }
bool IsVS() const { return shaderKind == DXIL::ShaderKind::Vertex; }
bool IsGS() const { return shaderKind == DXIL::ShaderKind::Geometry; }
bool IsHS() const { return shaderKind == DXIL::ShaderKind::Hull; }
bool IsDS() const { return shaderKind == DXIL::ShaderKind::Domain; }
bool IsCS() const { return shaderKind == DXIL::ShaderKind::Compute; }
bool IsGraphics() const {
return (shaderKind >= DXIL::ShaderKind::Pixel &&
shaderKind <= DXIL::ShaderKind::Domain) ||
shaderKind == DXIL::ShaderKind::Mesh ||
shaderKind == DXIL::ShaderKind::Amplification;
}
bool IsRayGeneration() const {
return shaderKind == DXIL::ShaderKind::RayGeneration;
}
bool IsIntersection() const {
return shaderKind == DXIL::ShaderKind::Intersection;
}
bool IsAnyHit() const { return shaderKind == DXIL::ShaderKind::AnyHit; }
bool IsClosestHit() const {
return shaderKind == DXIL::ShaderKind::ClosestHit;
}
bool IsMiss() const { return shaderKind == DXIL::ShaderKind::Miss; }
bool IsCallable() const { return shaderKind == DXIL::ShaderKind::Callable; }
bool IsRay() const {
return (shaderKind >= DXIL::ShaderKind::RayGeneration &&
shaderKind <= DXIL::ShaderKind::Callable);
}
bool IsMS() const { return shaderKind == DXIL::ShaderKind::Mesh; }
bool IsAS() const { return shaderKind == DXIL::ShaderKind::Amplification; }
bool IsNode() const {
return shaderKind == DXIL::ShaderKind::Node ||
Node.LaunchType != DXIL::NodeLaunchType::Invalid;
};
};
} // namespace hlsl