Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable optimizations for ESSL 1.0 code #7358

Merged
merged 1 commit into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ set(FILAMENT_METAL_HANDLE_ARENA_SIZE_IN_MB "8" CACHE STRING
"Size of the Metal handle arena, default 8."
)

# Enable exceptions by default in spirv-cross.
set(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS OFF)

# ==================================================================================================
# CMake policies
# ==================================================================================================
Expand Down Expand Up @@ -339,6 +342,7 @@ endif()

if (CYGWIN)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions -fno-rtti")
set(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS ON)
endif()

if (MSVC)
Expand Down Expand Up @@ -375,6 +379,7 @@ endif()
# saved by -fno-exception and 10 KiB saved by -fno-rtti).
if (ANDROID OR IOS OR WEBGL)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fno-exceptions -fno-rtti")
set(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS ON)

if (ANDROID OR WEBGL)
# Omitting unwind info prevents the generation of readable stack traces in crash reports on iOS
Expand All @@ -386,6 +391,7 @@ endif()
# std::visit, which is not supported on iOS 11.0 when exceptions are enabled.
if (IOS)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-exceptions")
set(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS ON)
endif()

# With WebGL, we disable RTTI even for debug builds because we pass emscripten::val back and forth
Expand Down
2 changes: 1 addition & 1 deletion NEW_RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
## Release notes for next branch cut

- matc: New option `-1` to disable generation of ESSL 1.0 code in Feature Level 0 materials
- matc: Enable preprocessor optimization of ESSL 1.0 shader code [⚠️ **Recompile materials**]
- matc: Support optimizations for ESSL 1.0 code [⚠️ **Recompile materials**]
21 changes: 14 additions & 7 deletions libs/filamat/src/GLSLPostProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

#include "MetalArgumentBuffer.h"
#include "SpirvFixup.h"
#include "utils/ostream.h"

#include <filament/MaterialEnums.h>

Expand Down Expand Up @@ -396,12 +397,8 @@ bool GLSLPostProcessor::process(const std::string& inputShader, Config const& co
break;
case MaterialBuilder::Optimization::SIZE:
case MaterialBuilder::Optimization::PERFORMANCE:
if (config.featureLevel == filament::backend::FeatureLevel::FEATURE_LEVEL_0) {
// Full optimization blocked by upstream issue:
// https://github.com/KhronosGroup/SPIRV-Cross/issues/2223
preprocessOptimization(tShader, config, internalConfig);
} else {
fullOptimization(tShader, config, internalConfig);
if (!fullOptimization(tShader, config, internalConfig)) {
return false;
}
break;
}
Expand Down Expand Up @@ -485,7 +482,7 @@ void GLSLPostProcessor::preprocessOptimization(glslang::TShader& tShader,
}
}

void GLSLPostProcessor::fullOptimization(const TShader& tShader,
bool GLSLPostProcessor::fullOptimization(const TShader& tShader,
GLSLPostProcessor::Config const& config, InternalConfig& internalConfig) const {
SpirvBlob spirv;

Expand Down Expand Up @@ -553,7 +550,16 @@ void GLSLPostProcessor::fullOptimization(const TShader& tShader,
}
}

#ifdef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
*internalConfig.glslOutput = glslCompiler.compile();
#else
try {
*internalConfig.glslOutput = glslCompiler.compile();
} catch (spirv_cross::CompilerError e) {
slog.e << "ERROR: " << e.what() << io::endl;
return false;
}
#endif

// spirv-cross automatically redeclares gl_ClipDistance if it's used. Some drivers don't
// like this, so we simply remove it.
Expand All @@ -566,6 +572,7 @@ void GLSLPostProcessor::fullOptimization(const TShader& tShader,
str.replace(found, clipDistanceDefinition.length(), "");
}
}
return true;
}

std::shared_ptr<spvtools::Optimizer> GLSLPostProcessor::createOptimizer(
Expand Down
2 changes: 1 addition & 1 deletion libs/filamat/src/GLSLPostProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class GLSLPostProcessor {
ShaderMinifier minifier;
};

void fullOptimization(const glslang::TShader& tShader,
bool fullOptimization(const glslang::TShader& tShader,
GLSLPostProcessor::Config const& config, InternalConfig& internalConfig) const;

void preprocessOptimization(glslang::TShader& tShader,
Expand Down
9 changes: 4 additions & 5 deletions libs/filamat/src/MaterialBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,10 @@ void MaterialBuilderBase::prepare(bool vulkanSemantics,
if (mIncludeEssl1
&& featureLevel == filament::backend::FeatureLevel::FEATURE_LEVEL_0
&& shaderModel == ShaderModel::MOBILE) {
// ESSL1 code may never be compiled to SPIR-V.
mCodeGenPermutations.push_back({
shaderModel,
TargetApi::OPENGL,
TargetLanguage::GLSL,
glTargetLanguage,
filament::backend::FeatureLevel::FEATURE_LEVEL_0
});
}
Expand Down Expand Up @@ -1422,15 +1421,15 @@ void MaterialBuilder::writeCommonChunks(ChunkContainer& container, MaterialInfo&
uniforms.push_back({
"objectUniforms.data[0].morphTargetCount",
offsetof(PerRenderableUib, data[0].morphTargetCount), 1,
UniformType::UINT });
UniformType::INT });
uniforms.push_back({
"objectUniforms.data[0].flagsChannels",
offsetof(PerRenderableUib, data[0].flagsChannels), 1,
UniformType::UINT });
UniformType::INT });
uniforms.push_back({
"objectUniforms.data[0].objectId",
offsetof(PerRenderableUib, data[0].objectId), 1,
UniformType::UINT });
UniformType::INT });
uniforms.push_back({
"objectUniforms.data[0].userData",
offsetof(PerRenderableUib, data[0].userData), 1,
Expand Down
16 changes: 10 additions & 6 deletions libs/filamat/src/shaders/CodeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,8 +301,9 @@ utils::io::sstream& CodeGenerator::generateProlog(utils::io::sstream& out, Shade
out << '\n';
out << SHADERS_COMMON_DEFINES_GLSL_DATA;

if (mFeatureLevel > FeatureLevel::FEATURE_LEVEL_0 &&
material.featureLevel == FeatureLevel::FEATURE_LEVEL_0) {
if (material.featureLevel == FeatureLevel::FEATURE_LEVEL_0 &&
(mFeatureLevel > FeatureLevel::FEATURE_LEVEL_0
|| mTargetLanguage == TargetLanguage::SPIRV)) {
// Insert compatibility definitions for ESSL 1.0 functions which were removed in ESSL 3.0.

// This is the minimum required value according to the OpenGL ES Shading Language Version
Expand Down Expand Up @@ -490,19 +491,22 @@ io::sstream& CodeGenerator::generateOutput(io::sstream& out, ShaderStage type,
const char* materialTypeString = getOutputTypeName(materialOutputType);
const char* typeString = getOutputTypeName(outputType);

bool generate_essl3_code = mTargetLanguage == TargetLanguage::SPIRV
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why can't we generate essl1 with target lang spirv?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I described it a bit above in a comment elsewhere in this file:

// During compilation and optimization, __VERSION__ reflects the shader language version of the
// intermediate code, not the version of the final code. spirv-cross automatically adapts
// certain language features (e.g. fragment output) but leaves others untouched (e.g. sampler
// functions, bit shift operations). Client code may have to make decisions based on this
// information, so define a FILAMENT_EFFECTIVE_VERSION constant.

Since the intermediate code is always ESSL 3.0 even if it eventually becomes ESSL 1.0, we have to sometimes generate ESSL 3.0 stuff like this.

|| mFeatureLevel >= FeatureLevel::FEATURE_LEVEL_1;

out << "\n#define FRAG_OUTPUT" << index << " " << name.c_str();
if (mFeatureLevel == FeatureLevel::FEATURE_LEVEL_0) {
out << "\n#define FRAG_OUTPUT_AT" << index << " gl_FragColor";
} else {
if (generate_essl3_code) {
out << "\n#define FRAG_OUTPUT_AT" << index << " output_" << name.c_str();
} else {
out << "\n#define FRAG_OUTPUT_AT" << index << " gl_FragColor";
}
out << "\n#define FRAG_OUTPUT_MATERIAL_TYPE" << index << " " << materialTypeString;
out << "\n#define FRAG_OUTPUT_PRECISION" << index << " " << precisionString;
out << "\n#define FRAG_OUTPUT_TYPE" << index << " " << typeString;
out << "\n#define FRAG_OUTPUT_SWIZZLE" << index << " " << swizzleString;
out << "\n";

if (mFeatureLevel >= FeatureLevel::FEATURE_LEVEL_1) {
if (generate_essl3_code) {
out << "\nlayout(location=" << index << ") out " << precisionString << " "
<< typeString << " output_" << name.c_str() << ";\n";
}
Expand Down
13 changes: 11 additions & 2 deletions third_party/spirv-cross/spirv_glsl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14977,7 +14977,12 @@ string CompilerGLSL::flags_to_qualifiers_glsl(const SPIRType &type, const Bitset
{
auto &execution = get_entry_point();

if (flags.get(DecorationRelaxedPrecision))
if (type.basetype == SPIRType::UInt && is_legacy_es())
{
// HACK: This is a bool. See comment in type_to_glsl().
qual += "lowp ";
}
else if (flags.get(DecorationRelaxedPrecision))
{
bool implied_fmediump = type.basetype == SPIRType::Float &&
options.fragment.default_float_precision == Options::Mediump &&
Expand Down Expand Up @@ -15503,7 +15508,11 @@ string CompilerGLSL::type_to_glsl(const SPIRType &type, uint32_t id)
if (type.basetype == SPIRType::UInt && is_legacy())
{
if (options.es)
SPIRV_CROSS_THROW("Unsigned integers are not supported on legacy ESSL.");
// HACK: spirv-cross changes bools into uints and generates code which compares them to
// zero. Input code will have already been validated as not to have contained any uints,
// so any remaining uints must in fact be bools. However, simply returning "bool" here
// will result in invalid code. Instead, return an int.
return backend.basic_int_type;
else
require_extension_internal("GL_EXT_gpu_shader4");
}
Expand Down
Loading