aboutsummaryrefslogtreecommitdiff
path: root/source/Shader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Shader.cpp')
-rw-r--r--source/Shader.cpp396
1 files changed, 238 insertions, 158 deletions
diff --git a/source/Shader.cpp b/source/Shader.cpp
index 4a576d0..61e80a1 100644
--- a/source/Shader.cpp
+++ b/source/Shader.cpp
@@ -18,114 +18,56 @@
namespace fs = std::filesystem;
using namespace std::literals;
-bool ShaderThingId::IsValid() const {
- return kind == KD_Invalid;
+void ShaderMathVariable::ShowInfo() const {
+ ImGui::BulletText("Location: %d\nName: %s\nSemantic: %s\nType: %s %dx%d",
+ location,
+ name.c_str(),
+ Tags::NameOf(semantic).data(),
+ Tags::NameOfGLType(scalarType).data(),
+ width,
+ height);
}
-ShaderVariable* ShaderInfo::FindVariable(const ShaderThingId& thing) {
- switch (thing.kind) {
- case ShaderThingId::KD_Input: return &inputs[thing.index].variable;
- case ShaderThingId::KD_Output: return &outputs[thing.index].variable;
- case ShaderThingId::KD_Uniform: return uniforms[thing.index].get();
- case ShaderThingId::KD_Invalid: break;
- }
- return nullptr;
+void ShaderSamplerVariable::ShowInfo() const {
+ ImGui::BulletText("Location: %d\nName: %s\nSemantic: %s\nType: Sampler",
+ location,
+ name.c_str(),
+ Tags::NameOf(semantic).data());
}
-bool ShaderInfo::SaveToFile(const fs::path& filePath) const {
- rapidjson::Document root(rapidjson::kObjectType);
-
- auto SaveInputOutputThings = [&](const char* name, const std::vector<InputOutputThing>& things) {
- rapidjson::Value rvThings(rapidjson::kArrayType);
- for (auto& thing : things) {
- rapidjson::Value rvThing(rapidjson::kObjectType);
- rvThing.AddMember("Name", thing.variable.name, root.GetAllocator());
- rvThing.AddMember("Semantic", rapidjson::StringRef(Tags::NameOf(thing.semantic)), root.GetAllocator());
- rvThing.AddMember("ScalarType", rapidjson::StringRef(Tags::NameOfGLType(thing.variable.scalarType)), root.GetAllocator());
- rvThing.AddMember("Width", thing.variable.width, root.GetAllocator());
- rvThing.AddMember("Height", thing.variable.height, root.GetAllocator());
- rvThing.AddMember("ArrayLength", thing.variable.arrayLength, root.GetAllocator());
- rvThing.AddMember("OpenGLLocation", thing.variable.location, root.GetAllocator());
-
- rvThings.PushBack(rvThing, root.GetAllocator());
- }
- root.AddMember(rapidjson::StringRef(name), rvThings, root.GetAllocator());
- };
- SaveInputOutputThings("Inputs", inputs);
- SaveInputOutputThings("Outputs", outputs);
-
- // TODO uniforms
-
- auto file = Utils::OpenCstdioFile(filePath, Utils::WriteTruncate);
- if (!file) return false;
- DEFER { fclose(file); };
-
- char writerBuffer[65536];
- rapidjson::FileWriteStream stream(file, writerBuffer, sizeof(writerBuffer));
- rapidjson::Writer<rapidjson::FileWriteStream> writer(stream);
- root.Accept(writer);
-
- return true;
+bool ShaderThingId::IsValid() const {
+ return kind == KD_Invalid;
}
-bool ShaderInfo::LoadFromFile(const fs::path& filePath) {
- auto file = Utils::OpenCstdioFile(filePath, Utils::Read);
- if (!file) return false;
- DEFER { fclose(file); };
-
- char readerBuffer[65536];
- rapidjson::FileReadStream stream(file, readerBuffer, sizeof(readerBuffer));
-
- rapidjson::Document root;
- root.ParseStream(stream);
-
- auto LoadInputOutputThings = [&](std::string_view name, std::vector<InputOutputThing>& things) {
- auto rvThings = rapidjson::GetProperty(root, rapidjson::kObjectType, name);
- if (!rvThings) return;
- if (!rvThings->IsArray()) return;
-
- for (auto& elm : rvThings->GetArray()) {
- if (!elm.IsObject()) continue;
- InputOutputThing thing;
-
- BRUSSEL_JSON_GET(elm, "Name", std::string, thing.variable.name, continue);
- { // Semantic
- auto value = rapidjson::GetProperty(elm, rapidjson::kStringType, "Semantic"sv);
- if (!value) {
- thing.semantic = Tags::VES_Generic;
- } else {
- thing.semantic = Tags::FindVertexElementSemantic(rapidjson::AsStringView(*value));
- }
- }
- { // Scalar type
- auto value = rapidjson::GetProperty(elm, rapidjson::kStringType, "ScalarType"sv);
- if (!value) continue;
- thing.variable.scalarType = Tags::FindGLType(rapidjson::AsStringView(*value));
- }
- BRUSSEL_JSON_GET(elm, "Width", int, thing.variable.width, continue);
- BRUSSEL_JSON_GET(elm, "Height", int, thing.variable.height, continue);
- BRUSSEL_JSON_GET(elm, "OpenGLLocation", int, thing.variable.location, continue);
- BRUSSEL_JSON_GET_DEFAULT(elm, "ArrayLength", int, thing.variable.arrayLength, 1);
-
- things.push_back(std::move(thing));
+namespace ProjectBrussel_UNITY_ID {
+GLuint FindLocation(const std::vector<ShaderMathVariable>& vars, Tags::VertexElementSemantic semantic) {
+ for (auto& var : vars) {
+ if (var.semantic == semantic) {
+ return var.location;
}
- };
- LoadInputOutputThings("Inputs"sv, inputs);
- LoadInputOutputThings("Outputs"sv, outputs);
-
- // TODO uniforms
+ }
+ return Tags::kInvalidLocation;
+}
+} // namespace ProjectBrussel_UNITY_ID
- return true;
+GLuint ShaderInfo::FindInputLocation(Tags::VertexElementSemantic semantic) {
+ using namespace ProjectBrussel_UNITY_ID;
+ return FindLocation(inputs, semantic);
}
-void ShaderInfo::LoadLocations(const Shader& ownerShader) {
- GLuint program = ownerShader.GetProgram();
+GLuint ShaderInfo::FindOutputLocation(Tags::VertexElementSemantic semantic) {
+ using namespace ProjectBrussel_UNITY_ID;
+ return FindLocation(outputs, semantic);
+}
- // TODO inputs
- // TODO outputs
- for (auto& uniform : uniforms) {
- uniform->location = glGetUniformLocation(ownerShader.GetProgram(), uniform->name.c_str());
+ShaderVariable* ShaderInfo::FindVariable(const ShaderThingId& thing) {
+ switch (thing.kind) {
+ case ShaderThingId::KD_Input: return &inputs[thing.index];
+ case ShaderThingId::KD_Output: return &outputs[thing.index];
+ case ShaderThingId::KD_Uniform: return uniforms[thing.index].get();
+ case ShaderThingId::KD_Invalid: break;
}
+ return nullptr;
}
Shader::Shader(std::string name)
@@ -133,7 +75,7 @@ Shader::Shader(std::string name)
}
Shader::~Shader() {
- glDeleteProgram(mHandle);
+ glDeleteProgram(mProgram);
}
namespace ProjectBrussel_UNITY_ID {
@@ -155,10 +97,10 @@ Shader::ErrorCode CreateShader(GLuint& out, const char* src, int beginIdx, int e
std::string log(len, '\0');
glGetShaderInfoLog(out, len, nullptr, log.data());
- return Shader ::CompilationFailed;
+ return Shader ::EC_CompilationFailed;
}
- return Shader::Success;
+ return Shader::EC_Success;
}
Shader::ErrorCode CreateShader(GLuint& out, std::string_view str, GLenum type) {
@@ -176,17 +118,17 @@ Shader::ErrorCode LinkShaderProgram(GLuint program) {
std::string log(len, '\0');
glGetProgramInfoLog(program, len, nullptr, log.data());
- return Shader::LinkingFailed;
+ return Shader::EC_LinkingFailed;
}
- return Shader::Success;
+ return Shader::EC_Success;
}
} // namespace ProjectBrussel_UNITY_ID
-#define CATCH_ERROR_IMPL(x, name) \
- auto name = x; \
- if (name != Shader::Success) { \
- return name; \
+#define CATCH_ERROR_IMPL(x, name) \
+ auto name = x; \
+ if (name != Shader::EC_Success) { \
+ return name; \
}
#define CATCH_ERROR(x) CATCH_ERROR_IMPL(x, UNIQUE_NAME(result))
@@ -194,7 +136,7 @@ Shader::ErrorCode Shader::InitFromSources(const ShaderSources& sources) {
using namespace ProjectBrussel_UNITY_ID;
if (IsValid()) {
- return ShaderAlreadyCreated;
+ return EC_AlreadyInitialized;
}
GLuint program = glCreateProgram();
@@ -238,9 +180,9 @@ Shader::ErrorCode Shader::InitFromSources(const ShaderSources& sources) {
CATCH_ERROR(LinkShaderProgram(program));
sg.Dismiss();
- mHandle = program;
+ mProgram = program;
- return Success;
+ return EC_Success;
}
Shader::ErrorCode Shader::InitFromSource(std::string_view source) {
@@ -268,7 +210,7 @@ Shader::ErrorCode Shader::InitFromSource(std::string_view source) {
auto CommitSection = [&]() -> ErrorCode {
if (prevBegin == -1 || prevEnd == -1) {
// Not actually "succeeding" here, but we just want to skip this call and continue
- return Success;
+ return EC_Success;
}
if (prevShaderVariant == "vertex" && !vertex) {
@@ -282,14 +224,14 @@ Shader::ErrorCode Shader::InitFromSource(std::string_view source) {
} else if (prevShaderVariant == "fragment" && !fragment) {
CATCH_ERROR(CreateShader(fragment, source.data(), prevBegin, prevEnd, GL_FRAGMENT_SHADER));
} else {
- return InvalidShaderVariant;
+ return EC_InvalidShaderVariant;
}
prevBegin = -1;
prevEnd = -1;
prevShaderVariant.clear();
- return Success;
+ return EC_Success;
};
constexpr const char* kMarker = "#type ";
@@ -355,9 +297,9 @@ Shader::ErrorCode Shader::InitFromSource(std::string_view source) {
CATCH_ERROR(LinkShaderProgram(program));
sg.Dismiss();
- mHandle = program;
+ mProgram = program;
- return Success;
+ return EC_Success;
}
#undef CATCH_ERROR
@@ -498,23 +440,10 @@ std::unique_ptr<ShaderVariable> CreateVariable(GLenum type, GLuint loc) {
}
} // namespace ProjectBrussel_UNITY_ID
-bool Shader::CreateEmptyInfoIfAbsent() {
- if (mInfo || !IsValid()) {
- return false;
- }
-
- mInfo = std::make_unique<ShaderInfo>();
- return true;
-}
-
-bool Shader::GatherInfoIfAbsent() {
+bool Shader::GatherInfoShaderIntrospection() {
using namespace ProjectBrussel_UNITY_ID;
- if (mInfo || !IsValid()) {
- return false;
- }
-
- mInfo = std::make_unique<ShaderInfo>();
+ mInfo = {};
// TODO handle differnt types of variables with the same name
@@ -522,45 +451,44 @@ bool Shader::GatherInfoIfAbsent() {
return true;
int inputCount;
- glGetProgramInterfaceiv(mHandle, GL_PROGRAM_INPUT, GL_ACTIVE_RESOURCES, &inputCount);
+ glGetProgramInterfaceiv(mProgram, GL_PROGRAM_INPUT, GL_ACTIVE_RESOURCES, &inputCount);
int outputCount;
- glGetProgramInterfaceiv(mHandle, GL_PROGRAM_OUTPUT, GL_ACTIVE_RESOURCES, &outputCount);
+ glGetProgramInterfaceiv(mProgram, GL_PROGRAM_OUTPUT, GL_ACTIVE_RESOURCES, &outputCount);
int uniformBlockCount;
- glGetProgramInterfaceiv(mHandle, GL_UNIFORM_BLOCK, GL_ACTIVE_RESOURCES, &uniformBlockCount);
+ glGetProgramInterfaceiv(mProgram, GL_UNIFORM_BLOCK, GL_ACTIVE_RESOURCES, &uniformBlockCount);
int uniformCount;
- glGetProgramInterfaceiv(mHandle, GL_UNIFORM, GL_ACTIVE_RESOURCES, &uniformCount);
+ glGetProgramInterfaceiv(mProgram, GL_UNIFORM, GL_ACTIVE_RESOURCES, &uniformCount);
// Gather inputs
- auto GatherMathVars = [&](int count, GLenum resourceType, ShaderThingId::Kind resourceKind, std::vector<ShaderInfo::InputOutputThing>& list) {
+ auto GatherMathVars = [&](int count, GLenum resourceType, ShaderThingId::Kind resourceKind, std::vector<ShaderMathVariable>& list) {
for (int i = 0; i < count; ++i) {
const GLenum query[] = { GL_NAME_LENGTH, GL_TYPE, GL_LOCATION, GL_TOP_LEVEL_ARRAY_SIZE };
GLint props[std::size(query)];
- glGetProgramResourceiv(mHandle, resourceType, i, std::size(query), query, std::size(props), nullptr, props);
+ glGetProgramResourceiv(mProgram, resourceType, i, std::size(query), query, std::size(props), nullptr, props);
auto& nameLength = props[0];
auto& type = props[1];
auto& loc = props[2];
auto& arrayLength = props[3];
std::string fieldName(nameLength - 1, '\0');
- glGetProgramResourceName(mHandle, GL_UNIFORM, i, nameLength, nullptr, fieldName.data());
+ glGetProgramResourceName(mProgram, GL_UNIFORM, i, nameLength, nullptr, fieldName.data());
- mInfo->things.try_emplace(fieldName, ShaderThingId{ resourceKind, i });
+ mInfo.things.try_emplace(fieldName, ShaderThingId{ resourceKind, i });
- auto& thing = list.emplace_back(ShaderInfo::InputOutputThing{});
- auto& var = thing.variable;
- var.name = std::move(fieldName);
- var.arrayLength = arrayLength;
- QueryMathInfo(type, var.scalarType, var.width, var.height);
+ auto& thing = list.emplace_back();
+ thing.name = std::move(fieldName);
+ thing.arrayLength = arrayLength;
+ QueryMathInfo(type, thing.scalarType, thing.width, thing.height);
}
};
- GatherMathVars(inputCount, GL_PROGRAM_INPUT, ShaderThingId::KD_Input, mInfo->inputs);
- GatherMathVars(outputCount, GL_PROGRAM_OUTPUT, ShaderThingId::KD_Output, mInfo->outputs);
+ GatherMathVars(inputCount, GL_PROGRAM_INPUT, ShaderThingId::KD_Input, mInfo.inputs);
+ GatherMathVars(outputCount, GL_PROGRAM_OUTPUT, ShaderThingId::KD_Output, mInfo.outputs);
// Gather uniform variables
for (int i = 0; i < uniformCount; ++i) {
const GLenum query[] = { GL_BLOCK_INDEX, GL_NAME_LENGTH, GL_TYPE, GL_LOCATION, GL_TOP_LEVEL_ARRAY_SIZE };
GLint props[std::size(query)];
- glGetProgramResourceiv(mHandle, GL_UNIFORM, i, std::size(query), query, std::size(props), nullptr, props);
+ glGetProgramResourceiv(mProgram, GL_UNIFORM, i, std::size(query), query, std::size(props), nullptr, props);
auto& blockIndex = props[0]; // Index in interface block
if (blockIndex != -1) { // If this is an interface block uniform, skip because it will be handled by our uniform blocks inspector
continue;
@@ -571,29 +499,182 @@ bool Shader::GatherInfoIfAbsent() {
auto& arrayLength = props[4];
std::string fieldName(nameLength - 1, '\0');
- glGetProgramResourceName(mHandle, GL_UNIFORM, i, nameLength, nullptr, fieldName.data());
+ glGetProgramResourceName(mProgram, GL_UNIFORM, i, nameLength, nullptr, fieldName.data());
- mInfo->things.try_emplace(fieldName, ShaderThingId{ ShaderThingId::KD_Uniform, i });
- mInfo->uniforms.push_back(CreateVariable(type, loc));
+ mInfo.things.try_emplace(fieldName, ShaderThingId{ ShaderThingId::KD_Uniform, i });
+ mInfo.uniforms.push_back(CreateVariable(type, loc));
}
return true;
}
-ShaderInfo* Shader::GetInfo() const {
- return mInfo.get();
+bool Shader::IsAnnoymous() const {
+ return mName.empty();
}
-const std::string& Shader::GetName() const {
- return mName;
+bool Shader::IsValid() const {
+ return mProgram != 0;
}
-GLuint Shader::GetProgram() const {
- return mHandle;
+namespace ProjectBrussel_UNITY_ID {
+void WriteShaderVariable(rapidjson::Value& value, rapidjson::Document& root, const ShaderVariable& var) {
+ value.AddMember("Name", var.name, root.GetAllocator());
+ value.AddMember("Semantic", rapidjson::StringRef(Tags::NameOf(var.semantic)), root.GetAllocator());
+ value.AddMember("OpenGLLocation", var.location, root.GetAllocator());
}
-bool Shader::IsValid() const {
- return mHandle != 0;
+bool ReadShaderVariable(const rapidjson::Value& value, ShaderVariable& var) {
+ BRUSSEL_JSON_GET(value, "Name", std::string, var.name, return false);
+ { // Semantic
+ auto rvSemantic = rapidjson::GetProperty(value, rapidjson::kStringType, "Semantic"sv);
+ if (!rvSemantic) {
+ var.semantic = Tags::VES_Generic;
+ } else {
+ var.semantic = Tags::FindVertexElementSemantic(rapidjson::AsStringView(*rvSemantic));
+ }
+ }
+ BRUSSEL_JSON_GET_DEFAULT(value, "OpenGLLocation", int, var.location, 0);
+ return true;
+}
+
+void WriteShaderMathVariable(rapidjson::Value& value, rapidjson::Document& root, const ShaderMathVariable& var) {
+ WriteShaderVariable(value, root, var);
+ value.AddMember("ScalarType", rapidjson::StringRef(Tags::NameOfGLType(var.scalarType)), root.GetAllocator());
+ value.AddMember("Width", var.width, root.GetAllocator());
+ value.AddMember("Height", var.height, root.GetAllocator());
+ value.AddMember("ArrayLength", var.arrayLength, root.GetAllocator());
+}
+
+bool ReadShaderMathVariable(const rapidjson::Value& value, ShaderMathVariable& var) {
+ if (!ReadShaderVariable(value, var)) return false;
+ {
+ auto rvScalar = rapidjson::GetProperty(value, rapidjson::kStringType, "ScalarType"sv);
+ if (!rvScalar) return false;
+ var.scalarType = Tags::FindGLType(rapidjson::AsStringView(*rvScalar));
+ }
+ BRUSSEL_JSON_GET(value, "Width", int, var.width, return false);
+ BRUSSEL_JSON_GET(value, "Height", int, var.height, return false);
+ BRUSSEL_JSON_GET_DEFAULT(value, "ArrayLength", int, var.arrayLength, 1);
+ return true;
+}
+
+void WriteShaderSamplerVariable(rapidjson::Value& value, rapidjson::Document& root, const ShaderSamplerVariable& var) {
+ WriteShaderVariable(value, root, var);
+ // TODO
+}
+
+bool ReadShaderSamplerVariable(const rapidjson::Value& value, ShaderSamplerVariable& var) {
+ if (!ReadShaderVariable(value, var)) return false;
+ BRUSSEL_JSON_GET_DEFAULT(value, "ArrayLength", int, var.arrayLength, 1);
+ return true;
+}
+} // namespace ProjectBrussel_UNITY_ID
+
+bool Shader::SaveMetadataToFile(const fs::path& filePath) const {
+ using namespace ProjectBrussel_UNITY_ID;
+
+ rapidjson::Document root(rapidjson::kObjectType);
+
+ auto SaveMathVars = [&](const char* name, const std::vector<ShaderMathVariable>& vars) {
+ rapidjson::Value rvThings(rapidjson::kArrayType);
+ for (auto& thing : vars) {
+ rapidjson::Value rvThing(rapidjson::kObjectType);
+ WriteShaderMathVariable(rvThing, root, thing);
+
+ rvThings.PushBack(rvThing, root.GetAllocator());
+ }
+ root.AddMember(rapidjson::StringRef(name), rvThings, root.GetAllocator());
+ };
+ SaveMathVars("Inputs", mInfo.inputs);
+ SaveMathVars("Outputs", mInfo.outputs);
+
+ // TODO uniforms
+
+ auto file = Utils::OpenCstdioFile(filePath, Utils::WriteTruncate);
+ if (!file) return false;
+ DEFER { fclose(file); };
+
+ char writerBuffer[65536];
+ rapidjson::FileWriteStream stream(file, writerBuffer, sizeof(writerBuffer));
+ rapidjson::Writer<rapidjson::FileWriteStream> writer(stream);
+ root.Accept(writer);
+
+ return true;
+}
+
+bool Shader::LoadMetadataFromFile(const fs::path& filePath) {
+ using namespace ProjectBrussel_UNITY_ID;
+
+ mInfo = {};
+
+ auto file = Utils::OpenCstdioFile(filePath, Utils::Read);
+ if (!file) return false;
+ DEFER { fclose(file); };
+
+ char readerBuffer[65536];
+ rapidjson::FileReadStream stream(file, readerBuffer, sizeof(readerBuffer));
+
+ rapidjson::Document root;
+ root.ParseStream(stream);
+
+ auto LoadMathVars = [&](std::string_view name, ShaderThingId::Kind kind, std::vector<ShaderMathVariable>& vars) {
+ auto rvThings = rapidjson::GetProperty(root, rapidjson::kArrayType, name);
+ if (!rvThings) return;
+
+ for (auto& rv : rvThings->GetArray()) {
+ if (!rv.IsObject()) continue;
+ ShaderMathVariable thing;
+ ReadShaderMathVariable(rv, thing);
+
+ mInfo.things.try_emplace(thing.name, ShaderThingId{ kind, (int)vars.size() });
+ vars.push_back(std::move(thing));
+ }
+ };
+ LoadMathVars("Inputs"sv, ShaderThingId::KD_Input, mInfo.inputs);
+ LoadMathVars("Outputs"sv, ShaderThingId::KD_Output, mInfo.outputs);
+
+ auto rvUniforms = rapidjson::GetProperty(root, rapidjson::kArrayType, "Uniforms"sv);
+ if (!rvUniforms) return false;
+ for (auto& rvUniform : rvUniforms->GetArray()) {
+ if (!rvUniform.IsObject()) continue;
+
+ auto rvType = rapidjson::GetProperty(rvUniform, rapidjson::kStringType, "Type"sv);
+ if (!rvType) continue;
+ auto type = rapidjson::AsStringView(*rvType);
+
+ auto rvValue = rapidjson::GetProperty(rvUniform, rapidjson::kObjectType, "Value"sv);
+ if (!rvValue) continue;
+
+ bool autoFill; // TODO store autofill uniforms somewhere else
+ BRUSSEL_JSON_GET_DEFAULT(rvUniform, "AutoFill", bool, autoFill, false);
+ if (autoFill) continue;
+
+ auto uniform = [&]() -> std::unique_ptr<ShaderVariable> {
+ if (type == "Math"sv) {
+ auto uniform = std::make_unique<ShaderMathVariable>();
+ ReadShaderMathVariable(*rvValue, *uniform);
+
+ return uniform;
+ } else if (type == "Sampler"sv) {
+ auto uniform = std::make_unique<ShaderSamplerVariable>();
+ ReadShaderSamplerVariable(*rvValue, *uniform);
+
+ return uniform;
+ }
+
+ return nullptr;
+ }();
+ if (uniform) {
+ mInfo.things.try_emplace(uniform->name, ShaderThingId{ ShaderThingId::KD_Uniform, (int)mInfo.uniforms.size() });
+ mInfo.uniforms.emplace_back(std::move(uniform));
+ }
+ }
+
+ for (auto& uniform : mInfo.uniforms) {
+ uniform->location = glGetUniformLocation(mProgram, uniform->name.c_str());
+ }
+
+ return true;
}
void ShaderManager::DiscoverShaders() {
@@ -625,7 +706,7 @@ void ShaderManager::DiscoverShaders() {
// Load shader
auto err = shader->InitFromSource(source);
- if (err != Shader::Success) {
+ if (err != Shader::EC_Success) {
continue;
}
@@ -633,8 +714,7 @@ void ShaderManager::DiscoverShaders() {
fs::path infoPath(item.path());
infoPath.replace_extension(".json");
if (fs::exists(infoPath)) {
- shader->CreateEmptyInfoIfAbsent();
- shader->GetInfo()->LoadFromFile(infoPath);
+ shader->LoadMetadataFromFile(infoPath);
}
mShaders.try_emplace(shaderName, std::move(shader));