2

我正在使用以下预处理器黑客

// shader_descriptor.hpp

#ifdef __cplusplus
    #include "./shader_source.hpp"
    #include "engine/utils/vec_t.hpp"
    #include <tuple>
    #include <span>

    #define BEGIN_SHADER_DESCRIPTOR(namespace_name, name)                                     \
        namespace namespace_name                                                                   \
        {                                                                                          \
            struct name                                                                            \
            {                                                                                      \
                using port_types = std::tuple <

    #define SHADER_INPUT(type, name) ::type##f_t,

    #define END_SHADER_DESCRIPTOR()                                                           \
        nullptr_t > ;                                                                              \
        static ::shaders::vertex_shader_source<std::span<uint32_t const>> vertex_shader();   \
        static ::shaders::fragment_shader_source<std::span<uint32_t const>>                  \
        fragment_shader();                                                                         \
                                                                                                   \
        static constexpr auto num_inputs = std::tuple_size_v<port_types> - 1;                      \
        }                                                                                          \
        ;                                                                                          \
        }

#else
const int port_counter_base = __COUNTER__;
    #define BEGIN_SHADER_DESCRIPTOR(namespace_name, name)
    #define SHADER_INPUT(type, name)                                                          \
        layout(location = __COUNTER__ - port_counter_base - 1) in type name;
    #define IDIS_END_SHADER_DESCRIPTOR()
#endif

所以我可以从源代码中提取正确的输入。输入定义如下:

// tsetprog.hpp

#include "./shader_descriptor.hpp"

BEGIN_SHADER_DESCRIPTOR(idis::shaders, testprog)
SHADER_INPUT(vec2, loc)
SHADER_INPUT(vec4, vert_color)
END_SHADER_DESCRIPTOR()

还有一个着色器模块(这里是顶点着色器):

#include "./testprog_def.hpp"

layout(location = 0) out vec4 frag_color;

void main()
{
    gl_Position = vec4(loc, 0.0, 1.0);
    frag_color = vert_color;
}

然后分两步编译着色器:

targets = args['targets']
source_file = args['source_file']
with tempfile.TemporaryDirectory(suffix = None, prefix = 'maike_' + args['build_info']['build_id']) as tmpdir:
    new_source_file = tmpdir + '/' + os.path.basename(source_file)
    with open(new_source_file, 'wb') as tmpfile:
        tmpfile.write('#version 450\n'.encode())
        cpp = subprocess.run(['cpp', '-P', source_file], stdout=subprocess.PIPE)
        tmpfile.write(cpp.stdout)

    result = subprocess.run(['glslangValidator', '-V', '-Os', '-o', targets[0], new_source_file]);

虽然这种方法有效,但它有一些局限性:

  1. 不可能对所有输入使用单个顶点缓冲区(无法生成正确的结构以从 c++ 端使用)

  2. 由于与 (1) 类似的原因,可能不适用于统一缓冲区。

是否有任何其他选项可以保证在编译时正确绑定(即:绑定应该具有正确的类型,并且必须连接所有输入)。目前,我使用以下函数来绑定缓冲区:

        template<class ShaderDescriptor, class... Buffers>
        render_pass_section& bind(VkCommandBuffer cmdbuff,
                                  std::reference_wrapper<pipeline<ShaderDescriptor> const> pipeline,
                                  std::reference_wrapper<Buffers const>... buffers)
        {
            static_assert(((Buffers::buffer_usage & VK_BUFFER_USAGE_VERTEX_BUFFER_BIT) && ...));
            static_assert(sizeof...(Buffers) == ShaderDescriptor::num_inputs);
            static_assert(std::is_same_v<std::tuple<typename Buffers::value_type..., nullptr_t>,
                                         typename ShaderDescriptor::port_types>);
            std::array<VkBuffer, sizeof...(Buffers)> handles{buffers.get().handle()...};
            std::array<VkDeviceSize, sizeof...(Buffers)> offsets{};
            vkCmdBindVertexBuffers(
                cmdbuff, 0, std::size(handles), std::data(handles), std::data(offsets));
            vkCmdBindPipeline(cmdbuff, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get().handle());
            return *this;
        }

ShaderDescriptor由预处理器生成。

4

0 回答 0