mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 06:08:30 +09:00
[Fix] (MG_Util/Program): program linking
This commit is contained in:
@@ -18,19 +18,19 @@ TEST_F(ProgramTest, Sanity) {
|
|||||||
const char* vs = R"(#version 150
|
const char* vs = R"(#version 150
|
||||||
|
|
||||||
in vec3 Position;
|
in vec3 Position;
|
||||||
in vec2 UV;
|
in vec2 UV0;
|
||||||
in vec4 Color;
|
in vec4 Color;
|
||||||
|
|
||||||
uniform mat4 ModelViewMat;
|
uniform mat4 ModelViewMat;
|
||||||
uniform mat4 ProjMat;
|
uniform mat4 ProjMat;
|
||||||
|
|
||||||
out vec2 texCoord;
|
out vec2 texCoord0;
|
||||||
out vec4 vertexColor;
|
out vec4 vertexColor;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
gl_Position = ProjMat * ModelViewMat * vec4(Position, 1.0);
|
gl_Position = ProjMat * ModelViewMat * vec4(Position, 1.0);
|
||||||
|
|
||||||
texCoord = UV;
|
texCoord0 = UV0;
|
||||||
vertexColor = Color;
|
vertexColor = Color;
|
||||||
})";
|
})";
|
||||||
|
|
||||||
@@ -49,19 +49,20 @@ TEST_F(ProgramTest, CompileSimpleVertexShader) {
|
|||||||
|
|
||||||
const char* fs = R"(#version 150
|
const char* fs = R"(#version 150
|
||||||
|
|
||||||
uniform sampler2D DiffuseSampler;
|
uniform sampler2D Sampler0;
|
||||||
|
|
||||||
uniform vec4 ColorModulator;
|
uniform vec4 ColorModulator;
|
||||||
|
|
||||||
in vec2 texCoord;
|
in vec2 texCoord0;
|
||||||
in vec4 vertexColor;
|
in vec4 vertexColor;
|
||||||
|
|
||||||
out vec4 fragColor;
|
out vec4 fragColor;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec4 color = texture(DiffuseSampler, texCoord) * vertexColor;
|
vec4 color = texture(Sampler0, texCoord0) * vertexColor;
|
||||||
|
if (color.a == 0.0) {
|
||||||
// blit final output of compositor into displayed back buffer
|
discard;
|
||||||
|
}
|
||||||
fragColor = color * ColorModulator;
|
fragColor = color * ColorModulator;
|
||||||
})";
|
})";
|
||||||
|
|
||||||
@@ -78,116 +79,36 @@ TEST_F(ProgramTest, CompileSimpleFragmentShader) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* vs_uniform = R"(#version 150
|
TEST_F(ProgramTest, CompileAndLinkProgram) {
|
||||||
|
|
||||||
in vec3 Position;
|
|
||||||
in vec2 UV;
|
|
||||||
in vec4 Color;
|
|
||||||
|
|
||||||
uniform mat4 ModelViewMat;
|
|
||||||
uniform mat4 ProjMat;
|
|
||||||
|
|
||||||
out vec2 texCoord;
|
|
||||||
out vec4 vertexColor;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
mat4 mat = ProjMat * ModelViewMat;
|
|
||||||
gl_Position = ProjMat * ModelViewMat * vec4(Position, 1.0);
|
|
||||||
|
|
||||||
texCoord = UV;
|
|
||||||
vertexColor = Color;
|
|
||||||
})";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
TEST_F(ProgramTest, ExtractPlainUniform) {
|
|
||||||
using namespace MG_Util::ShaderTranspiler;
|
using namespace MG_Util::ShaderTranspiler;
|
||||||
ShaderAttrib attrib {
|
ShaderAttrib vs_attrib {
|
||||||
.shaderType = GL_VERTEX_SHADER,
|
.shaderType = GL_VERTEX_SHADER,
|
||||||
.sourceStr = vs_uniform
|
.sourceStr = vs
|
||||||
|
};
|
||||||
|
auto vs_res = ShaderCompiler::CompileShader(vs_attrib);
|
||||||
|
if (!vs_res) {
|
||||||
|
ASSERT_NE(vs_res.error().errc, 0);
|
||||||
|
FAIL() << "errc: " << vs_res.error().errc << "\nlog: " << vs_res.error().log;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderAttrib fs_attrib {
|
||||||
|
.shaderType = GL_FRAGMENT_SHADER,
|
||||||
|
.sourceStr = fs
|
||||||
|
};
|
||||||
|
auto fs_res = ShaderCompiler::CompileShader(fs_attrib);
|
||||||
|
if (!fs_res) {
|
||||||
|
ASSERT_NE(fs_res.error().errc, 0);
|
||||||
|
FAIL() << "errc: " << fs_res.error().errc << "\nlog: " << fs_res.error().log;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProgramAttrib programAttrib {
|
||||||
|
.shaderTypes = { GL_VERTEX_SHADER, GL_FRAGMENT_SHADER },
|
||||||
|
.shaders = { vs_res.value(), fs_res.value() }
|
||||||
};
|
};
|
||||||
|
|
||||||
Vector<TUniform<TUniformType::Uniform>> uniforms;
|
auto program_res = ShaderCompiler::LinkProgram(programAttrib);
|
||||||
Vector<TUniform<TUniformType::Sampler>> samplers;
|
if (!program_res) {
|
||||||
|
ASSERT_NE(program_res.error().errc, 0);
|
||||||
auto res = ShaderCompiler::CompileShader(attrib);
|
FAIL() << "errc: " << program_res.error().errc << "\nlog: " << program_res.error().log;
|
||||||
if (res) {
|
|
||||||
UniformTraverser traverser(uniforms, samplers);
|
|
||||||
auto root = res->TShader->getIntermediate()->getTreeRoot();
|
|
||||||
root->traverse(&traverser);
|
|
||||||
|
|
||||||
ASSERT_EQ(uniforms.size(), 2);
|
|
||||||
ASSERT_EQ(samplers.size(), 0);
|
|
||||||
|
|
||||||
auto ProjMat_uniform_it = std::find_if(uniforms.begin(), uniforms.end(), [] (TUniform<TUniformType::Uniform>& uniform) {
|
|
||||||
return uniform.name == "ProjMat";
|
|
||||||
});
|
|
||||||
ASSERT_TRUE(ProjMat_uniform_it != uniforms.end());
|
|
||||||
ASSERT_EQ(ProjMat_uniform_it->storageQualifier, glslang::EvqUniform);
|
|
||||||
|
|
||||||
auto ModelViewMat_uniform_it = std::find_if(uniforms.begin(), uniforms.end(), [] (TUniform<TUniformType::Uniform>& uniform) {
|
|
||||||
return uniform.name == "ModelViewMat";
|
|
||||||
});
|
|
||||||
ASSERT_TRUE(ModelViewMat_uniform_it != uniforms.end());
|
|
||||||
ASSERT_EQ(ModelViewMat_uniform_it->storageQualifier, glslang::EvqUniform);
|
|
||||||
} else {
|
|
||||||
ASSERT_NE(res.error().errc, 0);
|
|
||||||
FAIL() << "errc: " << res.error().errc << "\nlog: " << res.error().log;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* fs_uniform = R"(#version 150
|
|
||||||
|
|
||||||
uniform sampler2D DiffuseSampler;
|
|
||||||
|
|
||||||
uniform vec4 ColorModulator;
|
|
||||||
|
|
||||||
in vec2 texCoord;
|
|
||||||
in vec4 vertexColor;
|
|
||||||
|
|
||||||
out vec4 fragColor;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
vec4 color = texture(DiffuseSampler, texCoord) * vertexColor;
|
|
||||||
|
|
||||||
// blit final output of compositor into displayed back buffer
|
|
||||||
fragColor = color * ColorModulator;
|
|
||||||
})";
|
|
||||||
|
|
||||||
TEST_F(ProgramTest, ExtractSampler) {
|
|
||||||
using namespace MG_Util::ShaderTranspiler;
|
|
||||||
ShaderAttrib attrib {
|
|
||||||
.shaderType = GL_FRAGMENT_SHADER,
|
|
||||||
.sourceStr = fs_uniform
|
|
||||||
};
|
|
||||||
|
|
||||||
Vector<TUniform<TUniformType::Uniform>> uniforms;
|
|
||||||
Vector<TUniform<TUniformType::Sampler>> samplers;
|
|
||||||
|
|
||||||
auto res = ShaderCompiler::CompileShader(attrib);
|
|
||||||
if (res) {
|
|
||||||
UniformTraverser traverser(uniforms, samplers);
|
|
||||||
auto root = res->TShader->getIntermediate()->getTreeRoot();
|
|
||||||
root->traverse(&traverser);
|
|
||||||
|
|
||||||
ASSERT_EQ(uniforms.size(), 1);
|
|
||||||
ASSERT_EQ(samplers.size(), 1);
|
|
||||||
|
|
||||||
auto ColorModulator_uniform_it = std::find_if(uniforms.begin(), uniforms.end(), [] (TUniform<TUniformType::Uniform>& uniform) {
|
|
||||||
return uniform.name == "ColorModulator";
|
|
||||||
});
|
|
||||||
ASSERT_TRUE(ColorModulator_uniform_it != uniforms.end());
|
|
||||||
ASSERT_EQ(ColorModulator_uniform_it->storageQualifier, glslang::EvqUniform);
|
|
||||||
|
|
||||||
auto DiffuseSampler_uniform_it = std::find_if(samplers.begin(), samplers.end(), [] (TUniform<TUniformType::Sampler>& uniform) {
|
|
||||||
return uniform.name == "DiffuseSampler";
|
|
||||||
});
|
|
||||||
ASSERT_TRUE(DiffuseSampler_uniform_it != samplers.end());
|
|
||||||
auto& sampler = DiffuseSampler_uniform_it->sampler;
|
|
||||||
ASSERT_EQ(sampler.type, glslang::EbtFloat);
|
|
||||||
ASSERT_EQ(sampler.dim, glslang::Esd2D);
|
|
||||||
} else {
|
|
||||||
ASSERT_NE(res.error().errc, 0);
|
|
||||||
FAIL() << "errc: " << res.error().errc << "\nlog: " << res.error().log;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -116,22 +116,22 @@ namespace MobileGL {
|
|||||||
return Resources;
|
return Resources;
|
||||||
}
|
}
|
||||||
|
|
||||||
CompilerResult ShaderCompiler::CompileShader(const ShaderAttrib& attrib) {
|
Result<SharedPtr<glslang::TShader>> ShaderCompiler::CompileShader(const ShaderAttrib& attrib) {
|
||||||
auto shaderType = attrib.shaderType;
|
auto shaderType = attrib.shaderType;
|
||||||
auto sourceStr = attrib.sourceStr;
|
auto sourceStr = attrib.sourceStr;
|
||||||
|
|
||||||
auto lang = GetEShLanguageByShaderType(shaderType);
|
auto lang = GetEShLanguageByShaderType(shaderType);
|
||||||
if (lang == EShLanguage::EShLangCount) {
|
if (lang == EShLanguage::EShLangCount) {
|
||||||
ShaderCompileResult<false> r;
|
ResultInfo r;
|
||||||
r.log += "Error: [Preprocess] Unsupported shader type: " +
|
r.log += "Error: [Preprocess] Unsupported shader type: " +
|
||||||
ConvertGLEnumToString(shaderType);
|
ConvertGLEnumToString(shaderType);
|
||||||
r.errc = -1;
|
r.errc = -1;
|
||||||
return std::unexpected(r);
|
return std::unexpected(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderCompileResult<true> res;
|
SharedPtr<glslang::TShader> res;
|
||||||
auto& tshader = res.TShader;
|
auto& tshader = res;
|
||||||
tshader = MakeUnique<glslang::TShader>(lang);
|
tshader = MakeShared<glslang::TShader>(lang);
|
||||||
const char* src[] = { sourceStr.c_str() };
|
const char* src[] = { sourceStr.c_str() };
|
||||||
tshader->setStrings(src, 1);
|
tshader->setStrings(src, 1);
|
||||||
tshader->setInvertY(true);
|
tshader->setInvertY(true);
|
||||||
@@ -144,7 +144,7 @@ namespace MobileGL {
|
|||||||
if (!tshader->parse(&GetTBuiltInResourceInstance(), 150, ECompatibilityProfile,
|
if (!tshader->parse(&GetTBuiltInResourceInstance(), 150, ECompatibilityProfile,
|
||||||
/*forceDefaultVersionAndProfile: */false,
|
/*forceDefaultVersionAndProfile: */false,
|
||||||
/*forwardCompatible: */true, EShMsgDefault)) {
|
/*forwardCompatible: */true, EShMsgDefault)) {
|
||||||
ShaderCompileResult<false> r;
|
ResultInfo r;
|
||||||
r.log += "Error: [glslang] Cannot compile " + ConvertGLEnumToString(shaderType) + ":\n"
|
r.log += "Error: [glslang] Cannot compile " + ConvertGLEnumToString(shaderType) + ":\n"
|
||||||
+ std::string(tshader->getInfoLog());
|
+ std::string(tshader->getInfoLog());
|
||||||
r.errc = -2;
|
r.errc = -2;
|
||||||
@@ -153,6 +153,49 @@ namespace MobileGL {
|
|||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<Vector<Vector<unsigned>>> ShaderCompiler::LinkProgram(const ProgramAttrib& attrib) {
|
||||||
|
glslang::TProgram program;
|
||||||
|
for (auto& s : attrib.shaders) {
|
||||||
|
program.addShader(s.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!program.link(EShMsgDefault)) {
|
||||||
|
ResultInfo r;
|
||||||
|
r.log = "Error: [glslang] Cannot link the program:\n" + std::string(program.getInfoLog());
|
||||||
|
r.errc = -3;
|
||||||
|
return std::unexpected(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
UniquePtr<glslang::TIoMapResolver> resolver;
|
||||||
|
for (unsigned stage = 0; stage < EShLangCount; stage++) {
|
||||||
|
auto* pResolver = program.getGlslIoResolver((EShLanguage)stage);
|
||||||
|
if (pResolver) {
|
||||||
|
resolver = UniquePtr<glslang::TIoMapResolver>(pResolver);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto ioMapper = UniquePtr<glslang::TIoMapper>(glslang::GetGlslIoMapper());
|
||||||
|
|
||||||
|
if (!program.mapIO(resolver.get(), ioMapper.get())) {
|
||||||
|
ResultInfo r;
|
||||||
|
r.log = "Error: [glslang] Cannot mapIO:\n" + std::string(program.getInfoLog());
|
||||||
|
r.errc = -4;
|
||||||
|
return std::unexpected(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
glslang::SpvOptions spvOptions;
|
||||||
|
spvOptions.disableOptimizer = false;
|
||||||
|
|
||||||
|
Vector<Vector<unsigned>> allSpirv;
|
||||||
|
for (auto type : attrib.shaderTypes) {
|
||||||
|
Vector<unsigned> spirv;
|
||||||
|
GlslangToSpv(*program.getIntermediate(ConvertGLEnumToEShLanguage(type)), spirv, &spvOptions);
|
||||||
|
allSpirv.push_back(spirv);
|
||||||
|
}
|
||||||
|
|
||||||
|
return allSpirv;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ namespace MG_Util {
|
|||||||
namespace ShaderTranspiler {
|
namespace ShaderTranspiler {
|
||||||
class ShaderCompiler {
|
class ShaderCompiler {
|
||||||
public:
|
public:
|
||||||
static CompilerResult CompileShader(const ShaderAttrib& attrib);
|
static Result<SharedPtr<glslang::TShader>> CompileShader(const ShaderAttrib& attrib);
|
||||||
|
static Result<Vector<Vector<unsigned>>> LinkProgram(const ProgramAttrib& attrib);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace MobileGL {
|
|||||||
struct TUniform<TUniformType::Uniform> {
|
struct TUniform<TUniformType::Uniform> {
|
||||||
String name;
|
String name;
|
||||||
|
|
||||||
glslang::TStorageQualifier storageQualifier;
|
// glslang::TType type;
|
||||||
Uint layoutLocation = 0;
|
Uint layoutLocation = 0;
|
||||||
Uint layoutBinding = 0;
|
Uint layoutBinding = 0;
|
||||||
glslang::TLayoutPacking layoutPacking;
|
glslang::TLayoutPacking layoutPacking;
|
||||||
@@ -42,20 +42,18 @@ namespace MobileGL {
|
|||||||
String sourceStr;
|
String sourceStr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CompiledTShader {
|
struct ProgramAttrib {
|
||||||
UniquePtr<glslang::TShader> TShader;
|
Vector<GLenum> shaderTypes;
|
||||||
Vector<TUniform<TUniformType::Uniform>> uniforms;
|
Vector<SharedPtr<glslang::TShader>> shaders;
|
||||||
Vector<TUniform<TUniformType::Sampler>> samplers;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <bool Succeeded>
|
struct ResultInfo {
|
||||||
struct ShaderCompileResult:
|
|
||||||
public std::conditional_t<Succeeded, CompiledTShader, EmptyType> {
|
|
||||||
Int errc = 0;
|
Int errc = 0;
|
||||||
String log;
|
String log;
|
||||||
};
|
};
|
||||||
|
|
||||||
using CompilerResult = std::expected<ShaderCompileResult<true>, ShaderCompileResult<false>>;
|
template <typename T>
|
||||||
|
using Result = std::expected<T, ResultInfo>;
|
||||||
|
|
||||||
struct ShaderPayload {
|
struct ShaderPayload {
|
||||||
// In
|
// In
|
||||||
|
|||||||
Reference in New Issue
Block a user