Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/gpu/intern/gpu_shader_dependency.cc')
-rw-r--r--source/blender/gpu/intern/gpu_shader_dependency.cc325
1 files changed, 278 insertions, 47 deletions
diff --git a/source/blender/gpu/intern/gpu_shader_dependency.cc b/source/blender/gpu/intern/gpu_shader_dependency.cc
index 2c6845334d3..7ee64d7e80f 100644
--- a/source/blender/gpu/intern/gpu_shader_dependency.cc
+++ b/source/blender/gpu/intern/gpu_shader_dependency.cc
@@ -10,11 +10,14 @@
#include <iomanip>
#include <iostream>
+#include <sstream>
+#include "BLI_ghash.h"
#include "BLI_map.hh"
#include "BLI_set.hh"
#include "BLI_string_ref.hh"
+#include "gpu_material_library.h"
#include "gpu_shader_create_info.hh"
#include "gpu_shader_dependency_private.h"
@@ -31,6 +34,7 @@ extern "C" {
namespace blender::gpu {
using GPUSourceDictionnary = Map<StringRef, struct GPUSource *>;
+using GPUFunctionDictionnary = Map<StringRef, struct GPUFunction *>;
struct GPUSource {
StringRefNull fullpath;
@@ -41,7 +45,10 @@ struct GPUSource {
shader::BuiltinBits builtins = (shader::BuiltinBits)0;
std::string processed_source;
- GPUSource(const char *path, const char *file, const char *datatoc)
+ GPUSource(const char *path,
+ const char *file,
+ const char *datatoc,
+ GPUFunctionDictionnary *g_functions)
: fullpath(path), filename(file), source(datatoc)
{
/* Scan for builtins. */
@@ -92,16 +99,20 @@ struct GPUSource {
if (filename.endswith(".h") || filename.endswith(".hh")) {
enum_preprocess();
}
+
+ if (is_from_material_library()) {
+ material_functions_parse(g_functions);
+ }
};
- bool is_in_comment(const StringRef &input, int64_t offset)
+ static bool is_in_comment(const StringRef &input, int64_t offset)
{
return (input.rfind("/*", offset) > input.rfind("*/", offset)) ||
(input.rfind("//", offset) > input.rfind("\n", offset));
}
template<bool check_whole_word = true, bool reversed = false, typename T>
- int64_t find_str(const StringRef &input, const T keyword, int64_t offset = 0)
+ static int64_t find_str(const StringRef &input, const T keyword, int64_t offset = 0)
{
while (true) {
if constexpr (reversed) {
@@ -114,7 +125,7 @@ struct GPUSource {
if constexpr (check_whole_word) {
/* Fix false positive if something has "enum" as suffix. */
char previous_char = input[offset - 1];
- if (!(ELEM(previous_char, '\n', '\t', ' ', ':'))) {
+ if (!(ELEM(previous_char, '\n', '\t', ' ', ':', '(', ','))) {
offset += (reversed) ? -1 : 1;
continue;
}
@@ -129,9 +140,13 @@ struct GPUSource {
}
}
+#define find_keyword find_str<true, false>
+#define rfind_keyword find_str<true, true>
+#define find_token find_str<false, false>
+#define rfind_token find_str<false, true>
+
void print_error(const StringRef &input, int64_t offset, const StringRef message)
{
- std::cout << " error: " << message << "\n";
StringRef sub = input.substr(0, offset);
int64_t line_number = std::count(sub.begin(), sub.end(), '\n') + 1;
int64_t line_end = input.find("\n", offset);
@@ -152,6 +167,12 @@ struct GPUSource {
std::cout << "^\n";
}
+#define CHECK(test_value, str, ofs, msg) \
+ if ((test_value) == -1) { \
+ print_error(str, ofs, msg); \
+ continue; \
+ }
+
/**
* Transform C,C++ enum declaration into GLSL compatible defines and constants:
*
@@ -193,16 +214,6 @@ struct GPUSource {
int64_t last_pos = 0;
const bool is_cpp = filename.endswith(".hh");
-#define find_keyword find_str<true, false>
-#define find_token find_str<false, false>
-#define rfind_token find_str<false, true>
-#define CHECK(test_value, str, ofs, msg) \
- if ((test_value) == -1) { \
- print_error(str, ofs, msg); \
- cursor++; \
- continue; \
- }
-
while (true) {
cursor = find_keyword(input, "enum ", cursor + 1);
if (cursor == -1) {
@@ -268,10 +279,6 @@ struct GPUSource {
return;
}
-#undef find_keyword
-#undef find_token
-#undef rfind_token
-
if (last_pos != 0) {
output += input.substr(last_pos);
}
@@ -279,37 +286,241 @@ struct GPUSource {
source = processed_source.c_str();
};
+ void material_functions_parse(GPUFunctionDictionnary *g_functions)
+ {
+ const StringRefNull input = source;
+
+ const char whitespace_chars[] = " \n\t";
+
+ auto function_parse = [&](const StringRef &input,
+ int64_t &cursor,
+ StringRef &out_return_type,
+ StringRef &out_name,
+ StringRef &out_args) -> bool {
+ cursor = find_keyword(input, "void ", cursor + 1);
+ if (cursor == -1) {
+ return false;
+ }
+ int64_t arg_start = find_token(input, '(', cursor);
+ if (arg_start == -1) {
+ return false;
+ }
+ int64_t arg_end = find_token(input, ')', arg_start);
+ if (arg_end == -1) {
+ return false;
+ }
+ int64_t body_start = find_token(input, '{', arg_end);
+ int64_t next_semicolon = find_token(input, ';', arg_end);
+ if (body_start != -1 && next_semicolon != -1 && body_start > next_semicolon) {
+ /* Assert no prototypes but could also just skip them. */
+ BLI_assert_msg(false, "No prototypes allowed in node GLSL libraries.");
+ }
+ int64_t name_start = input.find_first_not_of(whitespace_chars, input.find(' ', cursor));
+ if (name_start == -1) {
+ return false;
+ }
+ int64_t name_end = input.find_last_not_of(whitespace_chars, arg_start);
+ if (name_end == -1) {
+ return false;
+ }
+ /* Only support void type for now. */
+ out_return_type = "void";
+ out_name = input.substr(name_start, name_end - name_start);
+ out_args = input.substr(arg_start + 1, arg_end - (arg_start + 1));
+ return true;
+ };
+
+ auto keyword_parse = [&](const StringRef &str, int64_t &cursor) -> const StringRef {
+ int64_t keyword_start = str.find_first_not_of(whitespace_chars, cursor);
+ if (keyword_start == -1) {
+ /* No keyword found. */
+ return str.substr(0, 0);
+ }
+ int64_t keyword_end = str.find_first_of(whitespace_chars, keyword_start);
+ if (keyword_end == -1) {
+ /* Last keyword. */
+ keyword_end = str.size();
+ }
+ cursor = keyword_end + 1;
+ return str.substr(keyword_start, keyword_end - keyword_start);
+ };
+
+ auto arg_parse = [&](const StringRef &str,
+ int64_t &cursor,
+ StringRef &out_qualifier,
+ StringRef &out_type,
+ StringRef &out_name) -> bool {
+ int64_t arg_start = cursor + 1;
+ if (arg_start >= str.size()) {
+ return false;
+ }
+ cursor = find_token(str, ',', arg_start);
+ if (cursor == -1) {
+ /* Last argument. */
+ cursor = str.size();
+ }
+ const StringRef arg = str.substr(arg_start, cursor - arg_start);
+
+ int64_t keyword_cursor = 0;
+ out_qualifier = keyword_parse(arg, keyword_cursor);
+ out_type = keyword_parse(arg, keyword_cursor);
+ out_name = keyword_parse(arg, keyword_cursor);
+ if (out_name.is_empty()) {
+ /* No qualifier case. */
+ out_name = out_type;
+ out_type = out_qualifier;
+ out_qualifier = arg.substr(0, 0);
+ }
+ return true;
+ };
+
+ int64_t cursor = -1;
+ StringRef func_return_type, func_name, func_args;
+ while (function_parse(input, cursor, func_return_type, func_name, func_args)) {
+ GPUFunction *func = MEM_new<GPUFunction>(__func__);
+ func_name.copy(func->name, sizeof(func->name));
+ func->source = reinterpret_cast<void *>(this);
+
+ bool insert = g_functions->add(func->name, func);
+
+ /* NOTE: We allow overloading non void function, but only if the function comes from the
+ * same file. Otherwise the dependency system breaks. */
+ if (!insert) {
+ GPUSource *other_source = reinterpret_cast<GPUSource *>(
+ g_functions->lookup(func_name)->source);
+ if (other_source != this) {
+ print_error(input,
+ source.find(func_name),
+ "Function redefinition or overload in two different files ...");
+ print_error(
+ input, other_source->source.find(func_name), "... previous definition was here");
+ }
+ else {
+ /* Non-void function overload. */
+ MEM_delete(func);
+ }
+ continue;
+ }
+
+ if (func_return_type != "void") {
+ continue;
+ }
+
+ func->totparam = 0;
+ int64_t args_cursor = -1;
+ StringRef arg_qualifier, arg_type, arg_name;
+ while (arg_parse(func_args, args_cursor, arg_qualifier, arg_type, arg_name)) {
+
+ if (func->totparam >= ARRAY_SIZE(func->paramtype)) {
+ print_error(input, source.find(func_name), "Too much parameter in function");
+ break;
+ }
+
+ auto parse_qualifier = [](StringRef &qualifier) -> GPUFunctionQual {
+ if (qualifier == "out") {
+ return FUNCTION_QUAL_OUT;
+ }
+ else if (qualifier == "inout") {
+ return FUNCTION_QUAL_INOUT;
+ }
+ else {
+ return FUNCTION_QUAL_IN;
+ }
+ };
+
+ auto parse_type = [](StringRef &type) -> eGPUType {
+ if (type == "float") {
+ return GPU_FLOAT;
+ }
+ else if (type == "vec2") {
+ return GPU_VEC2;
+ }
+ else if (type == "vec3") {
+ return GPU_VEC3;
+ }
+ else if (type == "vec4") {
+ return GPU_VEC4;
+ }
+ else if (type == "mat3") {
+ return GPU_MAT3;
+ }
+ else if (type == "mat4") {
+ return GPU_MAT4;
+ }
+ else if (type == "sampler1DArray") {
+ return GPU_TEX1D_ARRAY;
+ }
+ else if (type == "sampler2DArray") {
+ return GPU_TEX2D_ARRAY;
+ }
+ else if (type == "sampler2D") {
+ return GPU_TEX2D;
+ }
+ else if (type == "sampler3D") {
+ return GPU_TEX3D;
+ }
+ else if (type == "Closure") {
+ return GPU_CLOSURE;
+ }
+ else {
+ return GPU_NONE;
+ }
+ };
+
+ func->paramqual[func->totparam] = parse_qualifier(arg_qualifier);
+ func->paramtype[func->totparam] = parse_type(arg_type);
+
+ if (func->paramtype[func->totparam] == GPU_NONE) {
+ std::string err = "Unknown parameter type \"" + arg_type + "\"";
+ int64_t err_ofs = source.find(func_name);
+ err_ofs = find_keyword(source, arg_name, err_ofs);
+ err_ofs = rfind_keyword(source, arg_type, err_ofs);
+ print_error(input, err_ofs, err);
+ }
+
+ func->totparam++;
+ }
+ }
+ }
+
+#undef find_keyword
+#undef rfind_keyword
+#undef find_token
+#undef rfind_token
+
/* Return 1 one error. */
- int init_dependencies(const GPUSourceDictionnary &dict)
+ int init_dependencies(const GPUSourceDictionnary &dict,
+ const GPUFunctionDictionnary &g_functions)
{
- if (dependencies_init) {
+ if (this->dependencies_init) {
return 0;
}
- dependencies_init = true;
- int64_t pos = 0;
+ this->dependencies_init = true;
+ int64_t pos = -1;
+
while (true) {
- pos = source.find("pragma BLENDER_REQUIRE(", pos);
- if (pos == -1) {
- return 0;
- }
- int64_t start = source.find('(', pos) + 1;
- int64_t end = source.find(')', pos);
- if (end == -1) {
- /* TODO Use clog. */
- std::cout << "Error: " << filename << " : Malformed BLENDER_REQUIRE: Missing \")\"."
- << std::endl;
- return 1;
- }
- StringRef dependency_name = source.substr(start, end - start);
- GPUSource *dependency_source = dict.lookup_default(dependency_name, nullptr);
- if (dependency_source == nullptr) {
- /* TODO Use clog. */
- std::cout << "Error: " << filename << " : Dependency not found \"" << dependency_name
- << "\"." << std::endl;
- return 1;
+ GPUSource *dependency_source = nullptr;
+
+ {
+ pos = source.find("pragma BLENDER_REQUIRE(", pos + 1);
+ if (pos == -1) {
+ return 0;
+ }
+ int64_t start = source.find('(', pos) + 1;
+ int64_t end = source.find(')', pos);
+ if (end == -1) {
+ print_error(source, start, "Malformed BLENDER_REQUIRE: Missing \")\" token");
+ return 1;
+ }
+ StringRef dependency_name = source.substr(start, end - start);
+ dependency_source = dict.lookup_default(dependency_name, nullptr);
+ if (dependency_source == nullptr) {
+ print_error(source, start, "Dependency not found");
+ return 1;
+ }
}
/* Recursive. */
- int result = dependency_source->init_dependencies(dict);
+ int result = dependency_source->init_dependencies(dict, g_functions);
if (result != 0) {
return 1;
}
@@ -318,8 +529,8 @@ struct GPUSource {
dependencies.append_non_duplicates(dep);
}
dependencies.append_non_duplicates(dependency_source);
- pos++;
- };
+ }
+ return 0;
}
/* Returns the final string with all includes done. */
@@ -339,6 +550,11 @@ struct GPUSource {
}
return out_builtins;
}
+
+ bool is_from_material_library() const
+ {
+ return filename.startswith("gpu_shader_material_") && filename.endswith(".glsl");
+ }
};
} // namespace blender::gpu
@@ -346,13 +562,15 @@ struct GPUSource {
using namespace blender::gpu;
static GPUSourceDictionnary *g_sources = nullptr;
+static GPUFunctionDictionnary *g_functions = nullptr;
void gpu_shader_dependency_init()
{
g_sources = new GPUSourceDictionnary();
+ g_functions = new GPUFunctionDictionnary();
#define SHADER_SOURCE(datatoc, filename, filepath) \
- g_sources->add_new(filename, new GPUSource(filepath, filename, datatoc));
+ g_sources->add_new(filename, new GPUSource(filepath, filename, datatoc, g_functions));
#include "glsl_draw_source_list.h"
#include "glsl_gpu_source_list.h"
#ifdef WITH_OCIO
@@ -362,7 +580,7 @@ void gpu_shader_dependency_init()
int errors = 0;
for (auto *value : g_sources->values()) {
- errors += value->init_dependencies(*g_sources);
+ errors += value->init_dependencies(*g_sources, *g_functions);
}
BLI_assert_msg(errors == 0, "Dependency errors detected: Aborting");
UNUSED_VARS_NDEBUG(errors);
@@ -373,7 +591,20 @@ void gpu_shader_dependency_exit()
for (auto *value : g_sources->values()) {
delete value;
}
+ for (auto *value : g_functions->values()) {
+ MEM_delete(value);
+ }
delete g_sources;
+ delete g_functions;
+}
+
+GPUFunction *gpu_material_library_use_function(GSet *used_libraries, const char *name)
+{
+ GPUFunction *function = g_functions->lookup_default(name, nullptr);
+ BLI_assert_msg(function != nullptr, "Requested function not in the function library");
+ GPUSource *source = reinterpret_cast<GPUSource *>(function->source);
+ BLI_gset_add(used_libraries, const_cast<char *>(source->filename.c_str()));
+ return function;
}
namespace blender::gpu::shader {