Skip to content

Commit e02b887

Browse files
committed
Added support for for early fragment tests.
Set early_fragment_tests render state to enable early fragment tests for targets that support explicitly setting it. Added support for Metal simulator. Internally this now uses an enum rather than a bool for the target platform.
1 parent 039ca5e commit e02b887

File tree

17 files changed

+315
-96
lines changed

17 files changed

+315
-96
lines changed

Compile/include/MSL/Compile/Target.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,13 +108,14 @@ class MSL_COMPILE_EXPORT Target
108108
SubpassInputs, ///< Subpass inputs for reading directly from framebuffers.
109109
ClipDistance, ///< Support for gl_ClipDistance array.
110110
CullDistance, ///< Support for gl_CullDistance array.
111+
EarlyFragmentTests, ///< Support for explicitly enabling early fragment tests.
111112
};
112113

113114
/**
114115
* @brief The number of feature enum elements.
115116
*/
116117
static const unsigned int featureCount =
117-
static_cast<unsigned int>(Feature::CullDistance) + 1;
118+
static_cast<unsigned int>(Feature::EarlyFragmentTests) + 1;
118119

119120
/**
120121
* @brief Information about a feature.

Compile/include/MSL/Compile/TargetMetal.h

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,23 +48,32 @@ namespace msl
4848
class MSL_COMPILE_EXPORT TargetMetal : public Target
4949
{
5050
public:
51+
/**
52+
* @brief Enum for the platform to target.
53+
*/
54+
enum class Platform
55+
{
56+
MacOS, ///< Target macOS.
57+
iOS, ///< Target iOS.
58+
iOSSimulator ///< Target iOS simulator.
59+
};
5160

5261
/**
5362
* @brief Constructs this with the version number.
5463
* @param version The Metal version number.
55-
* @param isIos True if this is Metal for iOS.
64+
* @param platform The platform to target.
5665
*/
57-
TargetMetal(std::uint32_t version, bool isIos);
66+
TargetMetal(std::uint32_t version, Platform platform);
5867

5968
~TargetMetal();
6069
TargetMetal(const TargetMetal&) = delete;
6170
TargetMetal& operator=(const TargetMetal&) = delete;
6271

6372
/**
64-
* @brief Returns whether or not this is for iOS.
65-
* @return True if for iOS.
73+
* @brief Gets the platform that's targetd.
74+
* @return The targeted platform.
6675
*/
67-
bool isIos() const;
76+
Platform getPlatform() const;
6877

6978
std::uint32_t getId() const override;
7079
std::uint32_t getVersion() const override;
@@ -84,7 +93,7 @@ class MSL_COMPILE_EXPORT TargetMetal : public Target
8493
std::string getSDK() const;
8594

8695
std::uint32_t m_version;
87-
bool m_ios;
96+
Platform m_platform;
8897
};
8998

9099
} // namespace msl

Compile/include/MSL/Compile/Types.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,11 @@ struct RenderState
742742
* @brief The number of cull distances.
743743
*/
744744
std::uint32_t cullDistanceCount = 0;
745+
746+
/**
747+
* @brief Whether or not to enable early fragment tests.
748+
*/
749+
Bool earlyFragmentTests = Bool::Unset;
745750
};
746751

747752
/**

Compile/src/Parser.cpp

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1268,13 +1268,19 @@ static ParseResult readRenderState(Output& output, Parser::Pipeline& pipeline, c
12681268
}
12691269
return ParseResult::Success;
12701270
}
1271-
// Patch control points
1272-
else if (isAttachment(attachmentIndex, key.value, "patch_control_points"))
1271+
// Other states
1272+
else if (key.value == "patch_control_points")
12731273
{
12741274
if (!getInt(output, pipeline.renderState.patchControlPoints, value))
12751275
return ParseResult::Error;
12761276
return ParseResult::Success;
12771277
}
1278+
else if (key.value == "early_fragment_tests")
1279+
{
1280+
if (!getBool(output, pipeline.renderState.earlyFragmentTests, value))
1281+
return ParseResult::Error;
1282+
return ParseResult::Success;
1283+
}
12781284
else
12791285
return ParseResult::NotThisType;
12801286
}
@@ -1540,7 +1546,8 @@ bool Parser::parse(Output& output, int options)
15401546
}
15411547

15421548
std::string Parser::createShaderString(std::vector<LineMapping>& lineMappings, Output& output,
1543-
const Pipeline& pipeline, Stage stage, bool ignoreEntryPoint) const
1549+
const Pipeline& pipeline, Stage stage, bool ignoreEntryPoint,
1550+
bool earlyFragmentTests) const
15441551
{
15451552
lineMappings.clear();
15461553
std::string shaderString;
@@ -1555,6 +1562,15 @@ std::string Parser::createShaderString(std::vector<LineMapping>& lineMappings, O
15551562
!m_elements[static_cast<unsigned int>(Element::UniformBlock)][stageIndex].empty();
15561563
}
15571564

1565+
// Add line for early fragment tests if enabled.
1566+
if (stage == Stage::Fragment && earlyFragmentTests)
1567+
{
1568+
shaderString += "layout(early_fragment_tests) in;\n";
1569+
lineMappings.emplace_back();
1570+
lineMappings.back().fileName = "<internal>";
1571+
lineMappings.back().line = 0;
1572+
}
1573+
15581574
// Add precision and struct elements first. This ensures that any type declarations are present
15591575
// before generating the push constant.
15601576
for (const TokenRange& tokenRange :
@@ -2155,6 +2171,7 @@ bool Parser::removeUniformBlock(std::string& str, std::vector<LineMapping>& line
21552171
if (!(m_options & RemoveUniformBlocks))
21562172
return false;
21572173

2174+
// Add the contents of the uniform block, stripping the block itself.
21582175
bool newline = true;
21592176
bool processed = false;
21602177
unsigned int braceCount = 0;

Compile/src/Parser.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ class MSL_COMPILE_EXPORT Parser
8282

8383
bool parse(Output& output, int options = 0);
8484
std::string createShaderString(std::vector<LineMapping>& lineMappings, Output& output,
85-
const Pipeline& pipeline, Stage stage, bool ignoreEntryPoint = false) const;
85+
const Pipeline& pipeline, Stage stage, bool ignoreEntryPoint,
86+
bool earlyFragmentTests) const;
8687

8788
private:
8889
enum class Element

Compile/src/Target.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ static Target::FeatureInfo featureInfos[] =
100100
"Subpass inputs for reading directly from framebuffers."},
101101
{"ClipDistance", "HAS_CLIP_DISTANCE", "Support for gl_ClipDistance array."},
102102
{"CullDistance", "HAS_CULL_DISTANCE", "Support for gl_CullDistance array."},
103+
{"EarlyFragmentTests", "HAS_EARLY_FRAGMENT_TESTS",
104+
"Support for explicitly enabling early fragment tests."},
103105
};
104106

105107
static_assert(sizeof(featureInfos)/sizeof(*featureInfos) == Target::featureCount,
@@ -685,6 +687,7 @@ bool Target::compileImpl(CompiledResult& result, Output& output, Parser& parser,
685687
int options = 0;
686688
if (!featureEnabled(Feature::UniformBlocks))
687689
options |= Parser::RemoveUniformBlocks;
690+
bool hasEarlyFragmentTests = featureEnabled(Feature::EarlyFragmentTests);
688691

689692
if (!parser.parse(output, options))
690693
return false;
@@ -770,7 +773,9 @@ bool Target::compileImpl(CompiledResult& result, Output& output, Parser& parser,
770773
if (pipeline.entryPoints[i].value.empty())
771774
continue;
772775

773-
std::string glsl = parser.createShaderString(lineMappings, output, pipeline, stage);
776+
std::string glsl = parser.createShaderString(lineMappings, output, pipeline, stage,
777+
false, hasEarlyFragmentTests &&
778+
pipeline.renderState.earlyFragmentTests == Bool::True);
774779
if (glsl.empty())
775780
return false;
776781
if (!Compiler::compile(stages, output, fileName, glsl, lineMappings, stage, resources))

Compile/src/TargetGlsl.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,11 @@ bool TargetGlsl::featureSupported(Feature feature) const
313313
return !m_es && m_version >= 130;
314314
case Feature::CullDistance:
315315
return !m_es && m_version >= 450;
316+
case Feature::EarlyFragmentTests:
317+
if (m_es)
318+
return m_version >= 310;
319+
else
320+
return m_version >= 420;
316321
}
317322

318323
return false;

Compile/src/TargetMetal.cpp

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -128,27 +128,27 @@ static std::vector<std::uint32_t> setBindingIndices(const std::vector<std::uint3
128128
return adjustedSpirv;
129129
}
130130

131-
TargetMetal::TargetMetal(std::uint32_t version, bool isIos)
131+
TargetMetal::TargetMetal(std::uint32_t version, Platform platform)
132132
: m_version(version)
133-
, m_ios(isIos)
133+
, m_platform(platform)
134134
{
135135
}
136136

137137
TargetMetal::~TargetMetal()
138138
{
139139
}
140140

141-
bool TargetMetal::isIos() const
141+
TargetMetal::Platform TargetMetal::getPlatform() const
142142
{
143-
return m_ios;
143+
return m_platform;
144144
}
145145

146146
std::uint32_t TargetMetal::getId() const
147147
{
148-
if (m_ios)
149-
return MSL_CREATE_ID('M', 'T', 'L', 'I');
150-
else
148+
if (m_platform == Platform::MacOS)
151149
return MSL_CREATE_ID('M', 'T', 'L', 'X');
150+
else
151+
return MSL_CREATE_ID('M', 'T', 'L', 'I');
152152
}
153153

154154
std::uint32_t TargetMetal::getVersion() const
@@ -170,6 +170,8 @@ bool TargetMetal::featureSupported(Feature feature) const
170170
return false;
171171
case Feature::TessellationStages:
172172
return m_version >= 102;
173+
case Feature::EarlyFragmentTests:
174+
return m_version >= 102;
173175
default:
174176
return true;
175177
}
@@ -180,10 +182,10 @@ std::vector<std::pair<std::string, std::string>> TargetMetal::getExtraDefines()
180182
std::stringstream stream;
181183
stream << getVersion();
182184
std::vector<std::pair<std::string, std::string>> defines = {{"METAL_VERSION", stream.str()}};
183-
if (m_ios)
184-
defines.emplace_back("METAL_IOS_VERSION", stream.str());
185-
else
185+
if (m_platform == Platform::MacOS)
186186
defines.emplace_back("METAL_OSX_VERSION", stream.str());
187+
else
188+
defines.emplace_back("METAL_IOS_VERSION", stream.str());
187189
return defines;
188190
}
189191

@@ -208,7 +210,8 @@ bool TargetMetal::crossCompile(std::vector<std::uint8_t>& data, Output& output,
208210
std::vector<std::uint32_t> adjustedSpirv = setBindingIndices(spirv, uniforms, uniformIds,
209211
hasPushConstant, bufferCount, textureCount);
210212

211-
std::string metal = MetalOutput::disassemble(output, adjustedSpirv, stage, m_version, m_ios,
213+
bool ios = m_platform != Platform::MacOS;
214+
std::string metal = MetalOutput::disassemble(output, adjustedSpirv, stage, m_version, ios,
212215
outputToBuffer, hasPushConstant, bufferCount, textureCount, fileName, line, column);
213216
if (metal.empty())
214217
return false;
@@ -218,7 +221,7 @@ bool TargetMetal::crossCompile(std::vector<std::uint8_t>& data, Output& output,
218221

219222
// Compile this entry point.
220223
std::stringstream versionStr;
221-
if (m_ios)
224+
if (ios)
222225
versionStr << "-std=ios-metal";
223226
else
224227
versionStr << "-std=osx-metal";
@@ -253,10 +256,16 @@ bool TargetMetal::crossCompile(std::vector<std::uint8_t>& data, Output& output,
253256

254257
std::string TargetMetal::getSDK() const
255258
{
256-
if (m_ios)
257-
return "iphoneos";
258-
else
259-
return "macosx";
259+
switch (m_platform)
260+
{
261+
case Platform::MacOS:
262+
return "macosx";
263+
case Platform::iOS:
264+
return "iphoneos";
265+
case Platform::iOSSimulator:
266+
return "iphonesimulator";
267+
}
268+
return "";
260269
}
261270

262271
} // namespace msl

Compile/test/CompilerTest.cpp

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ TEST_F(CompilerTest, CompleteShader)
6161

6262
auto stage = static_cast<Stage>(i);
6363
std::vector<Parser::LineMapping> lineMappings;
64-
std::string glsl = parser.createShaderString(lineMappings, output, pipeline, stage);
64+
std::string glsl =
65+
parser.createShaderString(lineMappings, output, pipeline, stage, false, false);
6566
EXPECT_TRUE(Compiler::compile(stages, output, shaderName, glsl, lineMappings, stage,
6667
Compiler::getDefaultResources()));
6768
compiledStage = true;
@@ -102,7 +103,40 @@ TEST_F(CompilerTest, CompileError)
102103

103104
auto stage = Stage::Fragment;
104105
std::vector<Parser::LineMapping> lineMappings;
105-
std::string glsl = parser.createShaderString(lineMappings, output, pipeline, stage);
106+
std::string glsl =
107+
parser.createShaderString(lineMappings, output, pipeline, stage, false, false);
108+
EXPECT_FALSE(Compiler::compile(stages, output, shaderName, glsl, lineMappings, stage,
109+
Compiler::getDefaultResources()));
110+
111+
const std::vector<Output::Message>& messages = output.getMessages();
112+
ASSERT_LE(1U, messages.size());
113+
EXPECT_EQ(Output::Level::Error, messages[0].level);
114+
EXPECT_TRUE(boost::algorithm::ends_with(pathStr(messages[0].file),
115+
pathStr(inputDir/"CompileError.mslh")));
116+
EXPECT_EQ(15U, messages[0].line);
117+
EXPECT_EQ("'inputss' : undeclared identifier", messages[0].message);
118+
}
119+
120+
TEST_F(CompilerTest, CompileErrorWithEarlyFragmentTests)
121+
{
122+
boost::filesystem::path inputDir = exeDir/"inputs";
123+
std::string shaderName = pathStr(inputDir/"CompileError.msl");
124+
125+
Parser parser;
126+
Preprocessor preprocessor;
127+
Output output;
128+
preprocessor.addIncludePath(pathStr(inputDir));
129+
EXPECT_TRUE(preprocessor.preprocess(parser.getTokens(), output, shaderName));
130+
EXPECT_TRUE(parser.parse(output));
131+
132+
ASSERT_EQ(1U, parser.getPipelines().size());
133+
const Parser::Pipeline& pipeline = parser.getPipelines()[0];
134+
Compiler::Stages stages;
135+
136+
auto stage = Stage::Fragment;
137+
std::vector<Parser::LineMapping> lineMappings;
138+
std::string glsl =
139+
parser.createShaderString(lineMappings, output, pipeline, stage, false, true);
106140
EXPECT_FALSE(Compiler::compile(stages, output, shaderName, glsl, lineMappings, stage,
107141
Compiler::getDefaultResources()));
108142

@@ -133,7 +167,8 @@ TEST_F(CompilerTest, CompileWarning)
133167

134168
auto stage = Stage::Fragment;
135169
std::vector<Parser::LineMapping> lineMappings;
136-
std::string glsl = parser.createShaderString(lineMappings, output, pipeline, stage);
170+
std::string glsl =
171+
parser.createShaderString(lineMappings, output, pipeline, stage, false, false);
137172
EXPECT_TRUE(Compiler::compile(stages, output, shaderName, glsl, lineMappings, stage,
138173
Compiler::getDefaultResources()));
139174

@@ -169,7 +204,8 @@ TEST_F(CompilerTest, MissingEntryPoint)
169204

170205
auto stage = static_cast<Stage>(i);
171206
std::vector<Parser::LineMapping> lineMappings;
172-
std::string glsl = parser.createShaderString(lineMappings, output, pipeline, stage);
207+
std::string glsl =
208+
parser.createShaderString(lineMappings, output, pipeline, stage, false, false);
173209
if (stage == Stage::Fragment)
174210
EXPECT_TRUE(glsl.empty());
175211
else
@@ -210,7 +246,8 @@ TEST_F(CompilerTest, DuplicateEntryPoint)
210246

211247
auto stage = static_cast<Stage>(i);
212248
std::vector<Parser::LineMapping> lineMappings;
213-
std::string glsl = parser.createShaderString(lineMappings, output, pipeline, stage);
249+
std::string glsl =
250+
parser.createShaderString(lineMappings, output, pipeline, stage, false, false);
214251
if (stage == Stage::Fragment)
215252
EXPECT_TRUE(glsl.empty());
216253
else

0 commit comments

Comments
 (0)