1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
#include "slang-ir-entry-point-decorations.h"
#include "compiler-core/slang-diagnostic-sink.h"
#include "core/slang-signal.h"
#include "core/slang-string.h"
#include "core/slang-type-text-util.h"
#include "slang-compiler.h"
#include "slang-ir-insts.h"
#include "slang-ir.h"
#include "slang-options.h"
namespace Slang
{
class CheckEntryPointDecorationsContext
{
public:
CheckEntryPointDecorationsContext(IRModule* module, CodeGenTarget target, DiagnosticSink* sink)
: m_module(module), m_target(target), m_sink(sink)
{
}
void check()
{
for (auto inst : m_module->getGlobalInsts())
{
const auto func = as<IRFunc>(inst);
if (!func)
continue;
const auto entryPointDecoration = func->findDecoration<IREntryPointDecoration>();
if (!entryPointDecoration)
continue;
checkEntryPoint(func, entryPointDecoration->getProfile().getStage());
}
}
private:
void checkEntryPoint(IRFunc* entryPoint, Stage stage)
{
for (auto decoration : entryPoint->getDecorations())
{
if (auto outputTopologyDecoration = as<IROutputTopologyDecoration>(decoration))
{
checkOutputTopologyDecoration(outputTopologyDecoration, stage);
}
}
}
void checkOutputTopologyDecoration(IROutputTopologyDecoration* decoration, Stage stage)
{
if (stage == Stage::Mesh)
{
const auto outputTopologyType = OutputTopologyType(decoration->getTopologyType());
if (isTargetGLSL() || isTargetSPIRV() || isTargetMetal())
{
if (outputTopologyType != OutputTopologyType::Point &&
outputTopologyType != OutputTopologyType::Line &&
outputTopologyType != OutputTopologyType::Triangle)
{
diagnoseInvalidMeshStageOutputTopology(
decoration,
"'point', 'line', 'triangle'");
}
}
else if (isTargetHLSL())
{
if (outputTopologyType != OutputTopologyType::Line &&
outputTopologyType != OutputTopologyType::Triangle)
{
diagnoseInvalidMeshStageOutputTopology(decoration, "'line', 'triangle'");
}
}
else
{
SLANG_UNEXPECTED("Invalid compilation target for mesh stage");
}
}
}
void diagnoseInvalidMeshStageOutputTopology(
IROutputTopologyDecoration* decoration,
String validTopologies)
{
m_sink->diagnose(
decoration,
Diagnostics::invalidMeshStageOutputTopology,
decoration->getTopology()->getStringSlice(),
TypeTextUtil::getCompileTargetName(SlangCompileTarget(m_target)),
validTopologies);
}
bool isTargetHLSL() const { return m_target == CodeGenTarget::HLSL; }
bool isTargetGLSL() const { return m_target == CodeGenTarget::GLSL; }
bool isTargetSPIRV() const
{
return m_target == CodeGenTarget::SPIRV || m_target == CodeGenTarget::SPIRVAssembly;
}
bool isTargetMetal() const
{
return m_target == CodeGenTarget::Metal || m_target == CodeGenTarget::MetalLib ||
m_target == CodeGenTarget::MetalLibAssembly;
}
IRModule* m_module;
const CodeGenTarget m_target;
DiagnosticSink* m_sink;
};
void checkEntryPointDecorations(IRModule* module, CodeGenTarget target, DiagnosticSink* sink)
{
CheckEntryPointDecorationsContext(module, target, sink).check();
}
OutputTopologyType convertOutputTopologyStringToEnum(String rawOutputTopology)
{
auto name = rawOutputTopology.toLower();
OutputTopologyType outputTopologyType = OutputTopologyType::Unknown;
#define CASE(ID, NAME) \
if (name == String(#NAME).toLower()) \
{ \
outputTopologyType = OutputTopologyType::ID; \
} \
else
OUTPUT_TOPOLOGY_TYPES(CASE)
#undef CASE
{
outputTopologyType = OutputTopologyType::Unknown;
// no match
}
return outputTopologyType;
}
} // namespace Slang
|