03-模块和访问控制

已道心破碎,以后就挑自己觉得重要的抄吧。感觉还不一定能用到我的OpenGL项目上,唉。

本篇将看看Slang中的模块系统,比头文件#include更高效。

模块与访问控制

Slang尽管支持预处理器#include,但仍推荐使用更新的模块系统。

定义模块

Slang中的模块可由一个或多个文件组成,一个模块必须有一个能用于识别它的文件,定义如下:

// scene.slang
module scene;
// ...

如果在其他文件中实现了该模块,需要使用__include语句来引入:

// scene.slang
module scene;
__include "scene-helpers";


// scene-helpers.slang
implementing scene;
// ...

其中,__include#include不同:

  • 预处理器阶段对__include包含的文件和它本身互不可见。例如scene.slang#define的东西在scene-helpers.slang中不可见,反之亦然。
  • 不论__include多少次,一个文件只会被包含在对应模块一次。
  • 不论__include的顺序,同一模块的所有文件可访问同一模块中定义的其他实体。

__include的样式主要有两种,通过一般标识符或字符串字面量:

// `file_name` is translated to "file-name".
__include dir.file_name; 

__include "dir/file-name.slang";
__include "dir/file-name";

导入模块

可以用import关键字通过模块名导入另一个模块:

// MyShader.slang
import YourLibrary;

其中,导入的模块文件名中必须有对应的模块声明。

访问控制

Slang支持模块成员(变量、方法)的访问控制,通过三个关键字:

  • public:可以访问任何地方,不论是来自不同的类型、文件或模块。

  • private:只能由同类型的其他符号访问。

    struct MyType
    {
        private int member;
    
        int f() { member = 5; } // OK.
    
        struct ChildType
        {
            int g(MyType t)
            {
                return t.member; // OK.
            }
        }
    }
    
    void outerFunc(MyType t)
    {
        // Error, `member` is not visible here.
        t.member = 2;
    }
  • internal:只能由同模块的内容访问。

    // a.slang
    module a;
    __include b;
    public struct PS
    {
        internal int internalMember;
        public int publicMember;
    }
    internal void f() { f_b(); } // OK, f_b defined in the same module.
    
    
    // b.slang
    implementing a;
    internal void f_b(); // Defines f_b in module `a`.
    public void publicFunc();
    
    
    // m.slang
    module m;
    import a;
    void main()
    {
        f(); // Error, f is not visible here.
        publicFunc(); // OK.
        PS p; // OK.
        p.internalMember = 1; // Error, internalMember is not visible.
        p.publicMember = 1; // OK.
    }

如果没有专门设置,默认的访问权限是internal。但interface中的成员除外,它们的可见性默认是接口本身。

文件结构建议

顶层文件夹中包含一些可能被用户代码包含的模块,模块具体的实现细节则放入对应模块名的文件夹中。

Project
	main.slang
	materials.slang
	materials
		materialA.slang
		materialB.slang
	math.slang
	utils.slang
	utils
		accumulators.slang
		fill.slang
		tonemap.slang

参考资料

  • shader-slang/slang: Making it easier to work with shaders (github.com)
  • Modules and Access Control | slang