fixes
This commit is contained in:
275
source/viewer/dynamic_shader_program_loading.cpp
Normal file
275
source/viewer/dynamic_shader_program_loading.cpp
Normal file
@@ -0,0 +1,275 @@
|
||||
#include "../../include/viewer/dynamic_shader_program_loading.hpp"
|
||||
#include "../../include/util/string_lookup.hpp"
|
||||
#include "../../include/util/logger.hpp"
|
||||
#include <sstream>
|
||||
|
||||
std::size_t viewer::dynamic_shader_program_loading::count_shader_files(
|
||||
const std::filesystem::path& path
|
||||
) {
|
||||
using namespace std::string_view_literals;
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
auto shader_file_count = std::size_t{ 0 };
|
||||
|
||||
for (const auto& [ asset_type, folder ] : {
|
||||
std::make_pair(asset_types::mesh, "mesh"sv),
|
||||
std::make_pair(asset_types::point_cloud, "point_cloud"sv)
|
||||
}) {
|
||||
const auto folder_begin = fs::directory_iterator{ path / folder };
|
||||
const auto folder_end = fs::directory_iterator{};
|
||||
|
||||
shader_file_count += std::count_if(
|
||||
folder_begin, folder_end,
|
||||
[](auto& entry) { return entry.is_regular_file(); }
|
||||
);
|
||||
}
|
||||
|
||||
return shader_file_count;
|
||||
}
|
||||
|
||||
void viewer::dynamic_shader_program_loading::load_directory(
|
||||
asset_loader& loader,
|
||||
instance& z3d,
|
||||
std::mutex& gl_resource_lock,
|
||||
std::mutex& progress_lock,
|
||||
std::string& progress_title,
|
||||
float& progress_ratio,
|
||||
const std::filesystem::path& path
|
||||
) {
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
auto progress_builder = std::stringstream{};
|
||||
|
||||
const auto shader_file_count = static_cast<float>(count_shader_files(path));
|
||||
constexpr auto shader_loading_progress = 0.8f;
|
||||
|
||||
|
||||
auto shader_indices = ztu::string_lookup<ztu::u32>({
|
||||
{ "vertex", 0 },
|
||||
{ "geometry", 1 },
|
||||
{ "fragment", 2 }
|
||||
});
|
||||
|
||||
constexpr auto shader_types = std::array<GLenum, 3>{
|
||||
GL_VERTEX_SHADER,
|
||||
GL_GEOMETRY_SHADER,
|
||||
GL_FRAGMENT_SHADER
|
||||
};
|
||||
|
||||
auto program_capabilities = std::vector<ztu::u32>{};
|
||||
auto programs = std::vector<std::array<zgl::shader_handle, 3>>{};
|
||||
|
||||
auto capability_indices = ztu::string_lookup<ztu::u32>();
|
||||
auto capabilities = std::vector<ztu::u32>{};
|
||||
capabilities.reserve(8);
|
||||
|
||||
constexpr auto dot_char = '.';
|
||||
constexpr auto separator_char = '_';
|
||||
constexpr auto optional_char = '?';
|
||||
|
||||
auto curr_shader_count = std::size_t{ 0 };
|
||||
|
||||
for (const auto& [ asset_type, folder ] : {
|
||||
std::make_pair(asset_types::mesh, "mesh"sv),
|
||||
std::make_pair(asset_types::point_cloud, "point_cloud"sv),
|
||||
}) {
|
||||
program_capabilities.clear();
|
||||
programs.clear();
|
||||
capability_indices.clear();
|
||||
|
||||
for (const auto& file : fs::directory_iterator{ path / folder })
|
||||
{
|
||||
if (not file.is_regular_file())
|
||||
continue;
|
||||
|
||||
const auto& file_path = file.path();
|
||||
|
||||
if (file_path.extension() != ".glsl")
|
||||
continue;
|
||||
|
||||
const auto filename = file_path.filename().string();
|
||||
|
||||
progress_lock.lock();
|
||||
|
||||
progress_builder.str(std::string{});
|
||||
progress_builder << "Loading shader '" << filename << "\'...";
|
||||
progress_title = progress_builder.str();
|
||||
progress_ratio = shader_loading_progress * static_cast<float>(curr_shader_count) / shader_file_count;
|
||||
|
||||
progress_lock.unlock();
|
||||
|
||||
const auto name = std::string_view(filename.begin(), std::ranges::find(filename, dot_char));
|
||||
|
||||
const auto type_str = std::string_view(name.begin(), std::ranges::find(name, separator_char));
|
||||
|
||||
const auto shader_type_index_it = shader_indices.find(type_str);
|
||||
if (shader_type_index_it == shader_indices.end()) {
|
||||
ztu::logger::warn("Unknown shader type '%'. Skipping shader.", type_str);
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto shader_type_index = shader_type_index_it->second;
|
||||
const auto shader_type = shader_types[shader_type_index];
|
||||
|
||||
auto shader_handle = zgl::shader_handle{};
|
||||
if (const auto e = loader.load_shader(shader_type, file_path, shader_handle)) {
|
||||
ztu::logger::error(
|
||||
"Error while loading shader %: [%] %",
|
||||
file_path,
|
||||
e.category().name(),
|
||||
e.message()
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
ztu::logger::debug("% -> %", filename, shader_handle.shader_id);
|
||||
|
||||
capabilities.clear();
|
||||
capabilities.push_back(0);
|
||||
|
||||
auto specifiers_str = std::string_view(type_str.end() + 1, name.end()); // skip separator_char
|
||||
|
||||
while (not specifiers_str.empty())
|
||||
{
|
||||
const auto pos = specifiers_str.find(separator_char);
|
||||
auto specifier_str = specifiers_str.substr(0, pos);
|
||||
|
||||
if (pos == std::string_view::npos)
|
||||
{
|
||||
specifiers_str = std::string_view{};
|
||||
}
|
||||
else
|
||||
{
|
||||
specifiers_str = specifiers_str.substr(pos + 1); // skip separator_char
|
||||
}
|
||||
|
||||
if (specifier_str.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto optional = specifier_str.back() == optional_char;
|
||||
if (optional)
|
||||
{
|
||||
specifier_str = specifier_str.substr(0, specifier_str.size() - 1);
|
||||
}
|
||||
|
||||
const auto index_it = capability_indices.find(specifier_str);
|
||||
|
||||
auto capability_index = capability_indices.size();
|
||||
if (index_it == capability_indices.end())
|
||||
{
|
||||
capability_indices.emplace(specifier_str, capability_index);
|
||||
}
|
||||
else
|
||||
{
|
||||
capability_index = index_it->second;
|
||||
}
|
||||
|
||||
const auto capability_flag = ztu::u32{ 1 } << capability_index;
|
||||
|
||||
const auto capability_count = capabilities.size();
|
||||
|
||||
if (optional)
|
||||
{
|
||||
capabilities.resize(2 * capability_count);
|
||||
std::copy_n(capabilities.begin(), capability_count, capabilities.begin() + capability_count);
|
||||
}
|
||||
|
||||
for (std::size_t i{}; i != capability_count; ++i)
|
||||
{
|
||||
capabilities[i] |= capability_flag;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& capability : capabilities)
|
||||
{
|
||||
const auto program_capability_it = std::ranges::upper_bound(program_capabilities, capability);
|
||||
|
||||
auto program_index = program_capability_it - program_capabilities.begin();
|
||||
|
||||
if (
|
||||
program_capability_it == program_capabilities.begin() or
|
||||
*std::prev(program_capability_it) != capability
|
||||
) {
|
||||
program_capabilities.insert(program_capability_it, capability);
|
||||
programs.emplace(programs.begin() + program_index);
|
||||
}
|
||||
else
|
||||
{
|
||||
--program_index; // The element before the iterator matches.
|
||||
}
|
||||
|
||||
programs[program_index][shader_type_index] = shader_handle;
|
||||
}
|
||||
|
||||
++curr_shader_count;
|
||||
}
|
||||
|
||||
progress_lock.lock();
|
||||
|
||||
progress_title = "Linking programs...";
|
||||
|
||||
progress_lock.unlock();
|
||||
|
||||
// Remove any duplicates shader combinations.
|
||||
std::ranges::sort(
|
||||
programs,
|
||||
[](const auto& lhs, const auto& rhs) {
|
||||
return std::lexicographical_compare(
|
||||
lhs.begin(), lhs.end(),
|
||||
rhs.begin(), rhs.end(),
|
||||
[](const auto& a, const auto& b) {
|
||||
return a.shader_id < b.shader_id;
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
programs.erase(std::ranges::unique(programs).begin(), programs.end());
|
||||
|
||||
ztu::logger::debug("Linking % programs.", programs.size());
|
||||
|
||||
// create shader_program
|
||||
for (const auto& [vertex, geometry, fragment] : programs)
|
||||
{
|
||||
if (vertex.shader_id == 0 or fragment.shader_id == 0)
|
||||
{
|
||||
ztu::logger::warn(
|
||||
"Skipping program as the combination is unlikely to be used (vertex: % geometry: % fragment: %).",
|
||||
vertex.shader_id, geometry.shader_id, fragment.shader_id
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto program_handle = zgl::shader_program_handle{};
|
||||
if (const auto e = loader.build_shader_program(vertex, geometry, fragment, program_handle))
|
||||
{
|
||||
ztu::logger::error(
|
||||
"Error occurred while linking shader program: [%] %",
|
||||
e.category().name(),
|
||||
e.message()
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
ztu::logger::debug(
|
||||
"Linked (vertex: % geometry: % fragment: %) -> %",
|
||||
vertex.shader_id, geometry.shader_id, fragment.shader_id,
|
||||
program_handle.program_id
|
||||
);
|
||||
|
||||
|
||||
gl_resource_lock.lock();
|
||||
z3d.add_shader_program(asset_type, program_handle);
|
||||
gl_resource_lock.unlock();
|
||||
}
|
||||
|
||||
gl_resource_lock.lock();
|
||||
z3d.m_mesh_shader_program_lookup.print();
|
||||
gl_resource_lock.unlock();
|
||||
|
||||
loader.unload_shader_data();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user