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

Traversers for samplers layout binding consistency #1412

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions Apps/Playground/Scripts/config.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
{
"root": "https://cdn.babylonjs.com",
"tests": [
{
"title": "Iridescence NME",
"playgroundId": "#2FDQT5#1507",
"referenceImage": "iridescence-nme.png"
},
{
"title": "NME Multi Build",
"playgroundId": "#D8AK3Z#104",
"referenceImage": "nme-multi-build.png",
"renderCount": 50
},
{
"title": "EXR Loader",
"playgroundId": "#4RN0VF#151",
Expand Down
86 changes: 43 additions & 43 deletions Apps/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions Apps/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
"getNightly": "node scripts/getNightly.js"
},
"dependencies": {
"babylonjs": "^7.22.3",
"babylonjs-gltf2interface": "^7.22.3",
"babylonjs-gui": "^7.22.3",
"babylonjs-loaders": "^7.22.3",
"babylonjs-materials": "^7.22.3",
"babylonjs": "^7.23.0",
"babylonjs-gltf2interface": "^7.23.0",
"babylonjs-gui": "^7.23.0",
"babylonjs-loaders": "^7.23.0",
"babylonjs-materials": "^7.23.0",
"chai": "^4.3.4",
"jsc-android": "^241213.1.0",
"mocha": "^9.2.2",
Expand Down
1 change: 1 addition & 0 deletions Plugins/NativeEngine/Source/ShaderCompilerD3D.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ namespace Babylon
ShaderCompilerTraversers::AssignLocationsAndNamesToVertexVaryingsD3D(program, ids, vertexAttributeRenaming);
ShaderCompilerTraversers::SplitSamplersIntoSamplersAndTextures(program, ids);
ShaderCompilerTraversers::InvertYDerivativeOperands(program);
ShaderCompilerTraversers::ReassignBindingToSamplers(program);

// clang-format off
static const spirv_cross::HLSLVertexAttributeRemap attributes[] = {
Expand Down
3 changes: 2 additions & 1 deletion Plugins/NativeEngine/Source/ShaderCompilerMetal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ namespace Babylon
ShaderCompilerTraversers::AssignLocationsAndNamesToVertexVaryingsMetal(program, ids, vertexAttributeRenaming);
ShaderCompilerTraversers::SplitSamplersIntoSamplersAndTextures(program, ids);
ShaderCompilerTraversers::InvertYDerivativeOperands(program);

ShaderCompilerTraversers::ReassignBindingToSamplers(program);

std::string vertexGLSL(vertexSource.data(), vertexSource.size());
auto [vertexParser, vertexCompiler] = CompileShader(program, EShLangVertex, vertexGLSL);

Expand Down
77 changes: 77 additions & 0 deletions Plugins/NativeEngine/Source/ShaderCompilerTraversers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -901,6 +901,78 @@ namespace Babylon::ShaderCompilerTraversers

TIntermediate* m_intermediate{};
};

/// <summary>
/// https://github.com/BabylonJS/BabylonNative/issues/1411
/// When a same sampler is declared in VS and FS, GLSlang assign a different binding location for VS and FS.
/// Max binding location is 16 so if more than 8 samplers are declared then D3Dcompile will not compile the shader.
/// This is the case for NME shaders for example.
/// The following traverser list samplers from the VS (and their binding location) and set the same binding location
/// in FS if it's present. If a sampler is present in FS but not in VS, then a binding location id will be used and incremented.
/// potential solution replacements:
/// - do not expose samplers in generated nme shaders (this doesn't fix the issue if samplers are declared in VS and FS for genuine reasons)
/// Apart from potential regressions and more complex TS code, the problem resides in D3D world only.
/// - use spirv optimizer tool to remove unused samplers: it will not fix the issue, binary will be bigger and compilation time will be longer.
/// </summary>
class ReassignBindingToSamplersTraverser : public TIntermTraverser
{
public:
static void Traverse(TProgram& program)
{
ReassignBindingToSamplersTraverser reassignBindingToSamplersTraverser{ };
program.getIntermediate(EShLangVertex)->getTreeRoot()->traverse(&reassignBindingToSamplersTraverser);
reassignBindingToSamplersTraverser.m_fragmentPass = true;
program.getIntermediate(EShLangFragment)->getTreeRoot()->traverse(&reassignBindingToSamplersTraverser);
}

protected:
void visitSymbol(TIntermSymbol* symbol) override {
// Check if the symbol is a sampler
const TType& type = symbol->getType();
if (type.getBasicType() == EbtSampler) {
TQualifier& qualifier = symbol->getWritableType().getQualifier();
std::string name{symbol->getName().c_str()};
static const std::string suffix = "Texture";
// appends 'Texture' to the name see SamplerSplitterTraverser for differenciation
bool textureEnds = name.size() >= suffix.size() && name.compare(name.size() - suffix.size(), suffix.size(), suffix) == 0;
if (!textureEnds)
{
name += suffix;
}
if (m_fragmentPass)
{
// fragment pass
auto iter = m_samplerLayoutBinding.find(name);
if (iter == m_samplerLayoutBinding.end())
{
qualifier.layoutBinding = ++m_nextLayoutBinding;
m_samplerLayoutBinding[name] = qualifier.layoutBinding;
}
else
{
qualifier.layoutBinding = iter->second;
}
}
else
{
if (qualifier.hasBinding())
{
// vertex pass
m_samplerLayoutBinding[name] = qualifier.layoutBinding;
m_nextLayoutBinding = std::max(m_nextLayoutBinding, qualifier.layoutBinding);
}
}
}
}

private:
ReassignBindingToSamplersTraverser()
{
}
std::map<std::string, int> m_samplerLayoutBinding;
bool m_fragmentPass{};
unsigned int m_nextLayoutBinding{0};
};
}

ScopeT MoveNonSamplerUniformsIntoStruct(TProgram& program, IdGenerator& ids)
Expand Down Expand Up @@ -937,4 +1009,9 @@ namespace Babylon::ShaderCompilerTraversers
{
InvertYDerivativeOperandsTraverser::Traverse(program);
}

void ReassignBindingToSamplers(glslang::TProgram& program)
{
ReassignBindingToSamplersTraverser::Traverse(program);
}
}
2 changes: 2 additions & 0 deletions Plugins/NativeEngine/Source/ShaderCompilerTraversers.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,6 @@ namespace Babylon::ShaderCompilerTraversers
/// https://github.com/bkaradzic/bgfx/blob/7be225bf490bb1cd231cfb4abf7e617bf35b59cb/src/bgfx_shader.sh#L44-L45
/// https://github.com/bkaradzic/bgfx/blob/7be225bf490bb1cd231cfb4abf7e617bf35b59cb/src/bgfx_shader.sh#L62-L65
void InvertYDerivativeOperands(glslang::TProgram& program);

void ReassignBindingToSamplers(glslang::TProgram& program);
}