Add ShaderReflector
- Used to look at the shader files and find set/binding automatically
This commit is contained in:
@@ -16,6 +16,21 @@ namespace Copium
|
||||
return buffer;
|
||||
}
|
||||
|
||||
std::vector<uint32_t> FileSystem::ReadFile32(const std::string& filename)
|
||||
{
|
||||
std::ifstream file(filename, std::ios::ate | std::ios::binary);
|
||||
CP_ASSERT(file.is_open(), "ReadFile32 : Failed to open file");
|
||||
|
||||
size_t fileSize = (size_t)file.tellg();
|
||||
CP_ASSERT(fileSize % 4 == 0, "ReadFile32 : byte size is not divisible by 4");
|
||||
std::vector<uint32_t> buffer(fileSize / 4);
|
||||
|
||||
file.seekg(0);
|
||||
file.read((char*)buffer.data(), fileSize);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
std::string FileSystem::ReadFileStr(const std::string& filename)
|
||||
{
|
||||
std::ifstream file(filename, std::ios::ate | std::ios::binary);
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Copium
|
||||
CP_STATIC_CLASS(FileSystem);
|
||||
public:
|
||||
static std::vector<char> ReadFile(const std::string& filename);
|
||||
static std::vector<uint32_t> ReadFile32(const std::string& filename);
|
||||
static std::string ReadFileStr(const std::string& filename);
|
||||
static void WriteFile(const std::string& filename, const std::string& data);
|
||||
static void WriteFile(const std::string& filename, const char* data, size_t size);
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
#include "copium/util/ShaderReflector.h"
|
||||
|
||||
#include "copium/util/FileSystem.h"
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace Copium
|
||||
{
|
||||
|
||||
ShaderReflector::ShaderReflector(const std::string& vertexGlslFile, const std::string& fragmentGlslFile)
|
||||
{
|
||||
ParseGlslFile(vertexGlslFile, ShaderType::Vertex);
|
||||
ParseGlslFile(fragmentGlslFile, ShaderType::Fragment);
|
||||
}
|
||||
|
||||
void ShaderReflector::ParseGlslFile(const std::string& glslFile, ShaderType shaderType)
|
||||
{
|
||||
std::string str = FileSystem::ReadFileStr(glslFile);
|
||||
int index = 0;
|
||||
while (index < str.size())
|
||||
{
|
||||
ParseWhitespace(str, index);
|
||||
if (str[index] == '#')
|
||||
{
|
||||
ParseLine(str, index);
|
||||
continue;
|
||||
}
|
||||
if (std::string_view(&str[index], sizeof("layout") - 1) == "layout")
|
||||
{
|
||||
ParseLayout(str, index, shaderType);
|
||||
continue;
|
||||
}
|
||||
ParseLine(str, index);
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderReflector::ParseLine(const std::string& str, int& index)
|
||||
{
|
||||
while(str[index] != '\n' && index < str.size()) index++;
|
||||
}
|
||||
|
||||
void ShaderReflector::ParseWhitespace(const std::string& str, int& index)
|
||||
{
|
||||
while ((str[index] == '\n' || str[index] == ' ' || str[index] == '\t' || str[index] == '\r') && index < str.size()) index++;
|
||||
}
|
||||
|
||||
void ShaderReflector::ParseLayout(const std::string& str, int& index, ShaderType shaderType)
|
||||
{
|
||||
// TODO: Make more robust, currently we might get a crash on the string if the glsl file is invalid
|
||||
index += sizeof("layout") - 1;
|
||||
ParseWhitespace(str, index);
|
||||
index++; // "("
|
||||
ParseWhitespace(str, index);
|
||||
if (std::string_view(&str[index], sizeof("set") - 1) != "set")
|
||||
{
|
||||
ParseLine(str, index);
|
||||
return;
|
||||
}
|
||||
ShaderBinding shaderBinding;
|
||||
shaderBinding.shaderType = shaderType;
|
||||
index += sizeof("set") - 1;
|
||||
ParseWhitespace(str, index);
|
||||
index++; // "="
|
||||
ParseWhitespace(str, index);
|
||||
char* end;
|
||||
shaderBinding.set = std::strtol(&str[index], &end, 10);
|
||||
index = end - str.c_str();
|
||||
ParseWhitespace(str, index);
|
||||
index++; // ","
|
||||
ParseWhitespace(str, index);
|
||||
index += sizeof("binding") - 1;
|
||||
ParseWhitespace(str, index);
|
||||
index++; // "="
|
||||
ParseWhitespace(str, index);
|
||||
shaderBinding.binding = std::strtol(&str[index], &end, 10);
|
||||
index = end - str.c_str();
|
||||
ParseWhitespace(str, index);
|
||||
index++; // ")
|
||||
ParseWhitespace(str, index);
|
||||
index += sizeof("uniform") - 1;
|
||||
ParseWhitespace(str, index);
|
||||
|
||||
std::string_view type = ParseWord(str, index);
|
||||
ParseWhitespace(str, index);
|
||||
if (str[index] == '{') ParseUniformBuffer(str, index);
|
||||
ParseWhitespace(str, index);
|
||||
std::string_view name = ParseWord(str, index);
|
||||
shaderBinding.name = name;
|
||||
ParseWhitespace(str, index);
|
||||
|
||||
if (str[index] == '[')
|
||||
{
|
||||
index++;
|
||||
shaderBinding.arraySize = std::strtol(&str[index], &end, 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
shaderBinding.arraySize = 1;
|
||||
}
|
||||
|
||||
ParseLine(str, index);
|
||||
if (type == "sampler2D")
|
||||
shaderBinding.bindingType = BindingType::Sampler2D;
|
||||
else
|
||||
shaderBinding.bindingType = BindingType::UniformBuffer;
|
||||
CP_ASSERT(bindings.emplace(shaderBinding).second, "ParseLayout : multiple layouts with the same binding");
|
||||
}
|
||||
|
||||
std::string_view ShaderReflector::ParseWord(const std::string& str, int& index)
|
||||
{
|
||||
int start = index;
|
||||
while (((str[index] >= 'a' && str[index] < 'z') ||
|
||||
(str[index] >= 'A' && str[index] < 'Z') ||
|
||||
(str[index] >= '0' && str[index] <= '9')) ||
|
||||
str[index] == '_' &&
|
||||
index < str.size()) index++;
|
||||
return std::string_view(&str[start], index - start);
|
||||
}
|
||||
|
||||
void ShaderReflector::ParseUniformBuffer(const std::string& str, int& index)
|
||||
{
|
||||
while (str[index] != '}' && index < str.size()) index++;
|
||||
if (index < str.size()) index++; // go past "}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
namespace Copium
|
||||
{
|
||||
enum class BindingType
|
||||
{
|
||||
Sampler2D, UniformBuffer
|
||||
};
|
||||
|
||||
enum class ShaderType
|
||||
{
|
||||
Vertex, Fragment
|
||||
};
|
||||
|
||||
struct ShaderBinding
|
||||
{
|
||||
std::string name;
|
||||
uint32_t set;
|
||||
uint32_t binding;
|
||||
uint32_t arraySize;
|
||||
BindingType bindingType;
|
||||
ShaderType shaderType;
|
||||
|
||||
bool operator<(const ShaderBinding& rhs) const
|
||||
{
|
||||
if (set != rhs.set)
|
||||
return set < rhs.set;
|
||||
if (binding != rhs.binding)
|
||||
return binding < rhs.binding;
|
||||
}
|
||||
};
|
||||
|
||||
class ShaderReflector
|
||||
{
|
||||
public:
|
||||
std::set<ShaderBinding> bindings;
|
||||
public:
|
||||
ShaderReflector(const std::string& vertexGlslFile, const std::string& fragmentGlslFile);
|
||||
|
||||
private:
|
||||
void ParseGlslFile(const std::string& glslFile, ShaderType type);
|
||||
void ParseLine(const std::string& str, int& index);
|
||||
void ParseWhitespace(const std::string& str, int& index);
|
||||
void ParseLayout(const std::string& str, int& index, ShaderType type);
|
||||
std::string_view ParseWord(const std::string& str, int& index);
|
||||
void ParseUniformBuffer(const std::string& str, int& index);
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user