diff --git a/source/blender/gpu/glsl_preprocess/glsl_preprocess.hh b/source/blender/gpu/glsl_preprocess/glsl_preprocess.hh index d14b577e564..03b1b18ac8f 100644 --- a/source/blender/gpu/glsl_preprocess/glsl_preprocess.hh +++ b/source/blender/gpu/glsl_preprocess/glsl_preprocess.hh @@ -212,6 +212,8 @@ class Preprocessor { str = preprocessor_directive_mutation(str); str = swizzle_function_mutation(str); if (language == BLENDER_GLSL) { + str = stage_function_mutation(str); + str = resource_guard_mutation(str, report_error); str = loop_unroll(str, report_error); str = assert_processing(str, filename); static_strings_parsing(str); @@ -1026,6 +1028,123 @@ class Preprocessor { return str; } + std::string stage_function_mutation(const std::string &str) + { + using namespace std; + + if (str.find("_function]]") == string::npos) { + return str; + } + + vector> mutations; + + int64_t line = 1; + regex regex_attr(R"(\[\[gpu::(vertex|fragment|compute)_function\]\])"); + regex_global_search(str, regex_attr, [&](const smatch &match) { + string prefix = match.prefix().str(); + string suffix = match.suffix().str(); + string attribute = match[0].str(); + string shader_stage = match[1].str(); + + line += line_count(prefix); + string signature = suffix.substr(0, suffix.find('{')); + string body = '{' + + get_content_between_balanced_pair(suffix.substr(signature.size()), '{', '}') + + "}\n"; + + string function = signature + body; + + string check = "defined("; + if (shader_stage == "vertex") { + check += "GPU_VERTEX_SHADER"; + } + else if (shader_stage == "fragment") { + check += "GPU_FRAGMENT_SHADER"; + } + else if (shader_stage == "compute") { + check += "GPU_COMPUTE_SHADER"; + } + check += ")"; + + string mutated = guarded_scope_mutation( + string(attribute.size(), ' ') + function, line, check); + mutations.emplace_back(attribute + function, mutated); + }); + + string out = str; + for (auto mutation : mutations) { + replace_all(out, mutation.first, mutation.second); + } + return out; + } + + std::string resource_guard_mutation(const std::string &str, report_callback report_error) + { + using namespace std; + + if (str.find("_get(") == string::npos) { + return str; + } + + vector> mutations; + + string prefix_total; + regex regex_resource_access(R"(\b(\w+)_get\((\w+)\, \w+\))"); + regex_global_search(str, regex_resource_access, [&](const smatch &match) { + string prefix = prefix_total + match.prefix().str(); + string suffix = match.suffix().str(); + string resource_access = match[0].str(); + string resource_type = match[1].str(); + string create_info_name = match[2].str(); + + prefix_total += match.prefix().str() + resource_access; + + if (resource_type != "specialization_constant" && resource_type != "push_constant" && + resource_type != "interface" && resource_type != "buffer" && + resource_type != "attribute" && resource_type != "sampler" && resource_type != "image") + { + return; + } + + string scope_start = get_content_between_balanced_pair(prefix + '}', '{', '}', true); + string scope_end = get_content_between_balanced_pair('{' + suffix, '{', '}'); + string scope = scope_start.substr(1) + resource_access + + scope_end.substr(0, scope_end.rfind('\n') + 1); + + if (scope.find(" return ") != string::npos) { + report_error(match, + "Return statement with values are not supported inside the same scope as " + "resource access function."); + return; + } + + size_t line_start = 1 + line_count(prefix) - line_count(scope_start) + 1; + + string check = "defined(CREATE_INFO_" + create_info_name + ")"; + string mutated = guarded_scope_mutation(scope, line_start, check); + + mutations.emplace_back(scope, mutated); + }); + + string out = str; + for (auto mutation : mutations) { + replace_all(out, mutation.first, mutation.second); + } + return out; + } + + std::string guarded_scope_mutation(std::string content, int64_t line_start, std::string check) + { + int64_t line_end = line_start + line_count(content); + std::string guarded_cope; + guarded_cope += "#if " + check + "\n"; + guarded_cope += "#line " + std::to_string(line_start) + "\n"; + guarded_cope += content; + guarded_cope += "#endif\n"; + guarded_cope += "#line " + std::to_string(line_end) + "\n"; + return guarded_cope; + } + std::string enum_macro_injection(std::string str) { /** diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc index f083461441e..4d390779b53 100644 --- a/source/blender/gpu/intern/gpu_shader.cc +++ b/source/blender/gpu/intern/gpu_shader.cc @@ -843,6 +843,8 @@ Shader *ShaderCompiler::compile(const shader::ShaderCreateInfo &info, bool is_ba std::string defines = shader->defines_declare(info); std::string resources = shader->resources_declare(info); + info.resource_guard_defines(defines); + defines += "#define USE_GPU_SHADER_CREATE_INFO\n"; Vector typedefs; @@ -874,6 +876,12 @@ Shader *ShaderCompiler::compile(const shader::ShaderCreateInfo &info, bool is_ba sources.extend(info.dependencies_generated); sources.append(info.vertex_source_generated); + if (info.vertex_entry_fn_ != "main") { + sources.append("void main() { "); + sources.append(info.vertex_entry_fn_); + sources.append("(); }\n"); + } + shader->vertex_shader_from_glsl(sources); } @@ -895,6 +903,12 @@ Shader *ShaderCompiler::compile(const shader::ShaderCreateInfo &info, bool is_ba sources.extend(info.dependencies_generated); sources.append(info.fragment_source_generated); + if (info.fragment_entry_fn_ != "main") { + sources.append("void main() { "); + sources.append(info.fragment_entry_fn_); + sources.append("(); }\n"); + } + shader->fragment_shader_from_glsl(sources); } @@ -914,6 +928,12 @@ Shader *ShaderCompiler::compile(const shader::ShaderCreateInfo &info, bool is_ba sources.append(info.geometry_source_generated); sources.extend(code); + if (info.geometry_entry_fn_ != "main") { + sources.append("void main() { "); + sources.append(info.geometry_entry_fn_); + sources.append("(); }\n"); + } + shader->geometry_shader_from_glsl(sources); } @@ -932,6 +952,12 @@ Shader *ShaderCompiler::compile(const shader::ShaderCreateInfo &info, bool is_ba sources.extend(info.dependencies_generated); sources.append(info.compute_source_generated); + if (info.compute_entry_fn_ != "main") { + sources.append("void main() { "); + sources.append(info.compute_entry_fn_); + sources.append("(); }\n"); + } + shader->compute_shader_from_glsl(sources); } diff --git a/source/blender/gpu/intern/gpu_shader_create_info.cc b/source/blender/gpu/intern/gpu_shader_create_info.cc index 0bcd518a7c3..6474f10db49 100644 --- a/source/blender/gpu/intern/gpu_shader_create_info.cc +++ b/source/blender/gpu/intern/gpu_shader_create_info.cc @@ -96,6 +96,17 @@ bool ShaderCreateInfo::is_vulkan_compatible() const /** \} */ +void ShaderCreateInfo::resource_guard_defines(std::string &defines) const +{ + defines += "#define CREATE_INFO_" + name_ + "\n"; + for (const auto &info_name : additional_infos_) { + const ShaderCreateInfo &info = *reinterpret_cast( + gpu_shader_create_info_get(info_name.c_str())); + + info.resource_guard_defines(defines); + } +} + void ShaderCreateInfo::finalize(const bool recursive) { if (finalized_) { @@ -201,6 +212,23 @@ void ShaderCreateInfo::finalize(const bool recursive) assert_no_overlap(compute_source_.is_empty(), "Compute source already existing"); compute_source_ = info.compute_source_; } + + if (info.vertex_entry_fn_ != "main") { + assert_no_overlap(vertex_entry_fn_ == "main", "Vertex function already existing"); + vertex_entry_fn_ = info.vertex_entry_fn_; + } + if (info.geometry_entry_fn_ != "main") { + assert_no_overlap(geometry_entry_fn_ == "main", "Geometry function already existing"); + geometry_entry_fn_ = info.geometry_entry_fn_; + } + if (info.fragment_entry_fn_ != "main") { + assert_no_overlap(fragment_entry_fn_ == "main", "Fragment function already existing"); + fragment_entry_fn_ = info.fragment_entry_fn_; + } + if (info.compute_entry_fn_ != "main") { + assert_no_overlap(compute_entry_fn_ == "main", "Compute function already existing"); + compute_entry_fn_ = info.compute_entry_fn_; + } } if (!geometry_source_.is_empty() && bool(builtins_ & BuiltinBits::LAYER)) { diff --git a/source/blender/gpu/intern/gpu_shader_create_info.hh b/source/blender/gpu/intern/gpu_shader_create_info.hh index 20070396ab7..7652133625a 100644 --- a/source/blender/gpu/intern/gpu_shader_create_info.hh +++ b/source/blender/gpu/intern/gpu_shader_create_info.hh @@ -25,6 +25,12 @@ # include #endif +#if defined(GPU_SHADER) +# include "gpu_shader_srd_cpp.hh" +#else +# include "gpu_shader_srd_info.hh" +#endif + /* Force enable `printf` support in release build. */ #define GPU_FORCE_ENABLE_SHADER_PRINTF 0 @@ -117,7 +123,9 @@ # define LOCAL_GROUP_SIZE(...) .local_group_size(__VA_ARGS__) # define VERTEX_IN(slot, type, name) .vertex_in(slot, Type::type##_t, #name) +# define VERTEX_IN_SRD(srd) .shared_resource_descriptor(srd::populate) # define VERTEX_OUT(stage_interface) .vertex_out(stage_interface) +# define VERTEX_OUT_SRD(srd) .vertex_out(srd) /* TO REMOVE. */ # define GEOMETRY_LAYOUT(...) .geometry_layout(__VA_ARGS__) # define GEOMETRY_OUT(stage_interface) .geometry_out(stage_interface) @@ -126,11 +134,14 @@ .subpass_in(slot, Type::type##_t, ImageType::img_type, #name, rog) # define FRAGMENT_OUT(slot, type, name) .fragment_out(slot, Type::type##_t, #name) +# define FRAGMENT_OUT_SRD(srd) .shared_resource_descriptor(srd::populate) # define FRAGMENT_OUT_DUAL(slot, type, name, blend) \ .fragment_out(slot, Type::type##_t, #name, DualBlend::blend) # define FRAGMENT_OUT_ROG(slot, type, name, rog) \ .fragment_out(slot, Type::type##_t, #name, DualBlend::NONE, rog) +# define RESOURCE_SRD(srd) .shared_resource_descriptor(srd::populate) + # define EARLY_FRAGMENT_TEST(enable) .early_fragment_test(enable) # define DEPTH_WRITE(value) .depth_write(value) @@ -168,6 +179,10 @@ # define FRAGMENT_SOURCE(filename) .fragment_source(filename) # define COMPUTE_SOURCE(filename) .compute_source(filename) +# define VERTEX_FUNCTION(function) .vertex_function(function) +# define FRAGMENT_FUNCTION(function) .fragment_function(function) +# define COMPUTE_FUNCTION(function) .compute_function(function) + # define DEFINE(name) .define(name) # define DEFINE_VALUE(name, value) .define(name, value) @@ -200,7 +215,12 @@ namespace gl_VertexShader { \ const type name = {}; \ } +# define VERTEX_IN_SRD(srd) \ + namespace gl_VertexShader { \ + using namespace srd; \ + } # define VERTEX_OUT(stage_interface) using namespace interface::stage_interface; +# define VERTEX_OUT_SRD(srd) using namespace interface::srd; /* TO REMOVE. */ # define GEOMETRY_LAYOUT(...) # define GEOMETRY_OUT(stage_interface) using namespace interface::stage_interface; @@ -219,6 +239,12 @@ namespace gl_FragmentShader { \ type name; \ } +# define FRAGMENT_OUT_SRD(srd) \ + namespace gl_FragmentShader { \ + using namespace srd; \ + } + +# define RESOURCE_SRD(srd) using namespace srd; # define EARLY_FRAGMENT_TEST(enable) # define DEPTH_WRITE(value) @@ -247,10 +273,13 @@ # define BUILTINS(builtin) # define VERTEX_SOURCE(filename) -# define GEOMETRY_SOURCE(filename) # define FRAGMENT_SOURCE(filename) # define COMPUTE_SOURCE(filename) +# define VERTEX_FUNCTION(filename) +# define FRAGMENT_FUNCTION(filename) +# define COMPUTE_FUNCTION(filename) + # define DEFINE(name) # define DEFINE_VALUE(name, value) @@ -885,6 +914,8 @@ struct ShaderCreateInfo { Vector typedef_sources_; StringRefNull vertex_source_, geometry_source_, fragment_source_, compute_source_; + StringRefNull vertex_entry_fn_ = "main", geometry_entry_fn_ = "main", + fragment_entry_fn_ = "main", compute_entry_fn_ = "main"; Vector> defines_; /** @@ -994,6 +1025,12 @@ struct ShaderCreateInfo { return *(Self *)this; } + Self &shared_resource_descriptor(void (*fn)(ShaderCreateInfo &)) + { + fn(*this); + return *(Self *)this; + } + /** \} */ /* -------------------------------------------------------------------- */ @@ -1175,6 +1212,24 @@ struct ShaderCreateInfo { return *(Self *)this; } + Self &vertex_function(StringRefNull function_name) + { + vertex_entry_fn_ = function_name; + return *(Self *)this; + } + + Self &fragment_function(StringRefNull function_name) + { + fragment_entry_fn_ = function_name; + return *(Self *)this; + } + + Self &compute_function(StringRefNull function_name) + { + compute_entry_fn_ = function_name; + return *(Self *)this; + } + /** \} */ /* -------------------------------------------------------------------- */ @@ -1318,6 +1373,8 @@ struct ShaderCreateInfo { * (All statically declared CreateInfos are automatically finalized at startup) */ void finalize(const bool recursive = false); + void resource_guard_defines(std::string &defines) const; + std::string check_error() const; bool is_vulkan_compatible() const; diff --git a/source/blender/gpu/intern/gpu_shader_srd_cpp.hh b/source/blender/gpu/intern/gpu_shader_srd_cpp.hh new file mode 100644 index 00000000000..936d5a5be95 --- /dev/null +++ b/source/blender/gpu/intern/gpu_shader_srd_cpp.hh @@ -0,0 +1,59 @@ +/* SPDX-FileCopyrightText: 2021 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#define SRD_STRUCT_BEGIN(srd) \ + namespace srd { \ + namespace gl_VertexShader { \ + } \ + namespace gl_FragmentShader { \ + } \ + namespace gl_ComputeShader { \ + } +#define SRD_STRUCT_END(srd) } + +#define SRD_VERTEX_IN_BEGIN(srd) SRD_STRUCT_BEGIN(srd) +#define SRD_VERTEX_IN_END(srd) SRD_STRUCT_END(srd) +#define SRD_VERTEX_IN(srd, binding, type, name) const type name = {}; + +#define SRD_VERTEX_OUT_BEGIN(srd) GPU_SHADER_INTERFACE_INFO(srd) +#define SRD_VERTEX_OUT_END(srd) GPU_SHADER_INTERFACE_END() +#define SRD_VERTEX_OUT(srd, qual, type, name) type name = {}; + +#define SRD_FRAGMENT_IN_BEGIN(srd) SRD_STRUCT_BEGIN(srd) +#define SRD_FRAGMENT_IN_END(srd) SRD_STRUCT_END(srd) +#define SRD_FRAGMENT_IN(srd, qual, type, name) const type name = {}; +#define SRD_FRAGMENT_IN_ROG(srd, slot, type, img_type, name, rog) const type name = {}; + +#define SRD_FRAGMENT_OUT_BEGIN(srd) SRD_STRUCT_BEGIN(srd) +#define SRD_FRAGMENT_OUT_END(srd) SRD_STRUCT_END(srd) +#define SRD_FRAGMENT_OUT(srd, binding, type, name) type name = {}; +#define SRD_FRAGMENT_OUT_DUAL(srd, slot, type, name, blend) type name = {}; +#define SRD_FRAGMENT_OUT_ROG(srd, slot, type, name, rog) type name = {}; + +#define SRD_RESOURCE_BEGIN(srd) SRD_STRUCT_BEGIN(srd) +#define SRD_RESOURCE_END(srd) SRD_STRUCT_END(srd) +#define SRD_RESOURCE_SPECIALIZATION_CONSTANT(srd, type, name, default) type name = {}; +#define SRD_RESOURCE_PUSH_CONSTANT(srd, type, name) type name = {}; +#define SRD_RESOURCE_PUSH_CONSTANT_ARRAY(srd, type, name, array) type(*name) = {}; +#define SRD_RESOURCE_SAMPLER(srd, binding, type, name) type name = {}; +#define SRD_RESOURCE_SAMPLER_FREQ(srd, binding, type, name, freq) type name = {}; +#define SRD_RESOURCE_IMAGE(srd, binding, format, access, type, name) _##access type name; +#define SRD_RESOURCE_IMAGE_FREQ(srd, binding, format, access, type, name, freq) \ + _##access type name; +#define SRD_RESOURCE_STORAGE_BUF(srd, binding, access, type, name, array) type(*name) array = {}; +#define SRD_RESOURCE_STORAGE_BUF_FREQ(srd, binding, access, type, name, array, freq) \ + type(*name) array = {}; +#define SRD_RESOURCE_UNIFORM_BUF(srd, binding, type, name, array) type(*name) array = {}; +#define SRD_RESOURCE_UNIFORM_BUF_FREQ(srd, binding, type, name, array, freq) \ + type(*name) array = {}; +#define SRD_RESOURCE_STRUCT(srd, type, name) type name = {}; +/* Temporary solution while everything is being ported. + * Should be replace by SRD_RESOURCE_STRUCT. */ +#define SRD_RESOURCE_ADDITIONAL_INFO(srd, type) using namespace type; diff --git a/source/blender/gpu/intern/gpu_shader_srd_info.hh b/source/blender/gpu/intern/gpu_shader_srd_info.hh new file mode 100644 index 00000000000..d31bc8e6667 --- /dev/null +++ b/source/blender/gpu/intern/gpu_shader_srd_info.hh @@ -0,0 +1,70 @@ +/* SPDX-FileCopyrightText: 2021 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#define SRD_STRUCT_BEGIN(srd) \ + struct srd { \ + static void populate(blender::gpu::shader::ShaderCreateInfo &info) \ + { + +#define SRD_STRUCT_END(srd) \ + } \ + } \ + ; + +#define SRD_VERTEX_IN_BEGIN(srd) SRD_STRUCT_BEGIN(srd) +#define SRD_VERTEX_IN_END(srd) SRD_STRUCT_END(srd) +#define SRD_VERTEX_IN(srd, binding, type, name) info.vertex_in(binding, Type::type##_t, #name); + +#define SRD_VERTEX_OUT_BEGIN(srd) GPU_SHADER_INTERFACE_INFO(srd) +#define SRD_VERTEX_OUT_END(srd) GPU_SHADER_INTERFACE_END() +#define SRD_VERTEX_OUT(srd, qual, type, name) .qual(Type::type##_t, #name) + +#define SRD_FRAGMENT_IN_BEGIN(srd) SRD_STRUCT_BEGIN(srd) +#define SRD_FRAGMENT_IN_END(srd) SRD_STRUCT_END(srd) +#define SRD_FRAGMENT_IN(srd, qual, type, name) info.qual(Type::type##_t, #name); +#define SRD_FRAGMENT_IN_ROG(srd, slot, type, img_type, name, rog) \ + info.subpass_in(slot, type, img_type, name, rog) + +#define SRD_FRAGMENT_OUT_BEGIN(srd) SRD_STRUCT_BEGIN(srd) +#define SRD_FRAGMENT_OUT_END(srd) SRD_STRUCT_END(srd) +#define SRD_FRAGMENT_OUT(srd, binding, type, name) \ + info.fragment_out(binding, Type::type##_t, #name); +#define SRD_FRAGMENT_OUT_DUAL(srd, slot, type, name, blend) \ + info.fragment_out(slot, Type::type##_t, #name, DualBlend::blend) +#define SRD_FRAGMENT_OUT_ROG(srd, slot, type, name, rog) \ + info.fragment_out(slot, Type::type##_t, #name, DualBlend::NONE, rog) + +#define SRD_RESOURCE_BEGIN(srd) SRD_STRUCT_BEGIN(srd) +#define SRD_RESOURCE_END(srd) SRD_STRUCT_END(srd) +#define SRD_RESOURCE_SPECIALIZATION_CONSTANT(srd, type, name, default) \ + info.specialization_constant(Type::type##_t, #name, default); +#define SRD_RESOURCE_PUSH_CONSTANT(srd, type, name) info.push_constant(Type::type##_t, #name); +#define SRD_RESOURCE_PUSH_CONSTANT_ARRAY(srd, type, name, array) \ + info.push_constant(Type::type##_t, #name, array); +#define SRD_RESOURCE_SAMPLER(srd, binding, type, name) \ + info.sampler(binding, ImageType::type, #name); +#define SRD_RESOURCE_SAMPLER_FREQ(srd, binding, type, name, freq) \ + info.sampler(binding, ImageType::type, #name, Frequency::freq); +#define SRD_RESOURCE_IMAGE(srd, binding, format, access, type, name) \ + info.image(binding, format, Qualifier::access, ImageReadWriteType::type, #name); +#define SRD_RESOURCE_IMAGE_FREQ(srd, binding, format, access, type, name, freq) \ + info.image(binding, format, Qualifier::access, ImageReadWriteType::type, #name, Frequency::freq); +#define SRD_RESOURCE_STORAGE_BUF(srd, binding, access, type, name, array) \ + info.storage_buf(binding, Qualifier::access, #type, #name #array); +#define SRD_RESOURCE_STORAGE_BUF_FREQ(srd, binding, access, type, name, array, freq) \ + info.storage_buf(binding, Qualifier::access, #type, #name #array, Frequency::freq); +#define SRD_RESOURCE_UNIFORM_BUF(srd, binding, type, name, array) \ + info.uniform_buf(binding, #type, #name #array); +#define SRD_RESOURCE_UNIFORM_BUF_FREQ(srd, binding, type, name, array, freq) \ + info.uniform_buf(binding, #type, #name #array, Frequency::freq); +#define SRD_RESOURCE_STRUCT(srd, type, name) type::populate(info); +/* Temporary solution while everything is being ported. + * Should be replace by SRD_RESOURCE_STRUCT. */ +#define SRD_RESOURCE_ADDITIONAL_INFO(srd, type) info.additional_info(#type); diff --git a/source/blender/gpu/shaders/gpu_glsl_cpp_stubs.hh b/source/blender/gpu/shaders/gpu_glsl_cpp_stubs.hh index a6d2ed538ef..ff9152a51b1 100644 --- a/source/blender/gpu/shaders/gpu_glsl_cpp_stubs.hh +++ b/source/blender/gpu/shaders/gpu_glsl_cpp_stubs.hh @@ -1072,6 +1072,21 @@ void groupMemoryBarrier() {} // #define using /* Needed for Stubs. */ #define row_major row_major_is_reserved_glsl_keyword_do_not_use +#ifdef GPU_SHADER_LIBRARY +# define GPU_VERTEX_SHADER +# define GPU_FRAGMENT_SHADER +# define GPU_COMPUTE_SHADER +#endif + +/* Resource accessor. */ +#define specialization_constant_get(create_info, _res) _res +#define push_constant_get(create_info, _res) _res +#define interface_get(create_info, _res) _res +#define attribute_get(create_info, _res) _res +#define buffer_get(create_info, _res) _res +#define sampler_get(create_info, _res) _res +#define image_get(create_info, _res) _res + #include "GPU_shader_shared_utils.hh" #ifdef __GNUC__ diff --git a/source/blender/gpu/shaders/metal/mtl_shader_defines.msl b/source/blender/gpu/shaders/metal/mtl_shader_defines.msl index 0f85e1d6a21..fac71b07744 100644 --- a/source/blender/gpu/shaders/metal/mtl_shader_defines.msl +++ b/source/blender/gpu/shaders/metal/mtl_shader_defines.msl @@ -1228,3 +1228,12 @@ float4x4 __mat4x4(float3x3 a) { return to_float4x4(a); } #define gpu_dfdx(x) dFdx(x) #define gpu_dfdy(x) dFdy(x) #define gpu_fwidth(x) fwidth(x) + +/* Resource accessor. */ +#define specialization_constant_get(create_info, _res) _res +#define push_constant_get(create_info, _res) _res +#define interface_get(create_info, _res) _res +#define attribute_get(create_info, _res) _res +#define buffer_get(create_info, _res) _res +#define sampler_get(create_info, _res) _res +#define image_get(create_info, _res) _res diff --git a/source/blender/gpu/tests/shader_preprocess_test.cc b/source/blender/gpu/tests/shader_preprocess_test.cc index ec8fc0fce74..7457cc8d563 100644 --- a/source/blender/gpu/tests/shader_preprocess_test.cc +++ b/source/blender/gpu/tests/shader_preprocess_test.cc @@ -750,4 +750,151 @@ static void test_preprocess_matrix_constructors() GPU_TEST(preprocess_matrix_constructors); #endif +static void test_preprocess_stage_attribute() +{ + using namespace shader; + using namespace std; + + { + string input = R"( +[[gpu::vertex_function]] void my_func() { + return; +} +)"; + string expect = R"( +#if defined(GPU_VERTEX_SHADER) +#line 2 + void my_func() { + return; +} +#endif +#line 5 +)"; + string error; + string output = process_test_string(input, error); + EXPECT_EQ(output, expect); + EXPECT_EQ(error, ""); + } +} +GPU_TEST(preprocess_stage_attribute); + +static void test_preprocess_resource_guard() +{ + using namespace shader; + using namespace std; + + { + string input = R"( +void my_func() { + interface_get(draw_resource_id_varying, drw_ResourceID_iface).resource_index; +} +)"; + string expect = R"( +void my_func() { +#if defined(CREATE_INFO_draw_resource_id_varying) +#line 3 + interface_get(draw_resource_id_varying, drw_ResourceID_iface).resource_index; +#endif +#line 4 +} +)"; + string error; + string output = process_test_string(input, error); + EXPECT_EQ(output, expect); + EXPECT_EQ(error, ""); + } + { + string input = R"( +uint my_func() { + uint i = 0; + i += interface_get(draw_resource_id_varying, drw_ResourceID_iface).resource_index; + return i; +} +)"; + string expect = R"( +uint my_func() { +#if defined(CREATE_INFO_draw_resource_id_varying) +#line 3 + uint i = 0; + i += interface_get(draw_resource_id_varying, drw_ResourceID_iface).resource_index; + return i; +#else +#line 3 + return uint(0); +#endif +#line 6 +} +)"; + string error; + string output = process_test_string(input, error); + // EXPECT_EQ(output, expect); /* TODO: Add support. */ + EXPECT_EQ(error, + "Return statement with values are not supported inside the same scope as " + "resource access function."); + } + { + string input = R"( +uint my_func() { + uint i = 0; + { + i += interface_get(draw_resource_id_varying, drw_ResourceID_iface).resource_index; + } + return i; +} +)"; + string expect = R"( +uint my_func() { + uint i = 0; + { +#if defined(CREATE_INFO_draw_resource_id_varying) +#line 5 + i += interface_get(draw_resource_id_varying, drw_ResourceID_iface).resource_index; +#endif +#line 6 + } + return i; +} +)"; + string error; + string output = process_test_string(input, error); + EXPECT_EQ(output, expect); + EXPECT_EQ(error, ""); + } + { + string input = R"( +uint my_func() { + uint i = 0; + { + i += interface_get(draw_resource_id_varying, drw_ResourceID_iface).resource_index; + i += buffer_get(draw_resource_id, resource_id_buf)[0]; + } + return i; +} +)"; + string expect = R"( +uint my_func() { + uint i = 0; + { +#if defined(CREATE_INFO_draw_resource_id_varying) +#line 5 +#if defined(CREATE_INFO_draw_resource_id) +#line 5 + i += interface_get(draw_resource_id_varying, drw_ResourceID_iface).resource_index; + i += buffer_get(draw_resource_id, resource_id_buf)[0]; +#endif +#line 7 +#endif +#line 7 + } + return i; +} +)"; + string error; + string output = process_test_string(input, error); + EXPECT_EQ(output, expect); + EXPECT_EQ(error, ""); + } +} +GPU_TEST(preprocess_resource_guard); + } // namespace blender::gpu::tests