02-方便的特性
已道心破碎,以后就挑自己觉得重要的抄吧。感觉还不一定能用到我的OpenGL项目上,唉。
命名空间
Slang支持命名空间,且支持三种嵌套方式:
namespace ns1.ns2
{
int f();
}
// equivalent to:
namespace ns1::ns2
{
int f();
}
// equivalent to:
namespace ns1
{
namespace ns2
{
int f();
}
}
和C++一样,能用using
来使用命名空间:
using ns1.ns2;
// or:
using namespace ns1.ns2; // alternative syntax.
结构体
成员函数
Slang支持在结构体中定义(静态)成员函数:
struct Foo
{
int compute(int a, int b)
{
return a + b;
}
}
// ...
Foo foo;
int rs = foo.compute(1,2);
考虑到gpu性能优先,成员函数中的this
是不可修改的,如果执意要修改,需要用[mutating]
属性修饰该成员函数,否则会报错。
getter&setter
可以用property
关键字定义成员变量的getter和setter函数:
struct MyType
{
uint flag;
property highBits : uint
{
get() { return flag >> 16; }
set(uint x) { flag = (flag & 0xFF) + (x << 16); }
}
};
[mutating]
为了GPU性能考虑,成员函数是无法改变结构体内变量的。如果真要这么做,需要[mutating]
注解:
struct Foo
{
int count;
[mutating]
void setCount(int x) { count = x; }
// This would fail to compile.
// void setCount2(int x) { count = x; }
}
运算符重载
Slang也支持运算符重载:
struct MyType
{
int val;
__init(int x) { val = x; }
}
MyType operator+(MyType a, MyType b)
{
return MyType(a.val + b.val);
}
特殊类型
Tuple类型
Tuple类型可以收集不同种类的类型:
Tuple<int, float, bool> t0 = Tuple<int, float, bool>(5, 2.0f, false);
Tuple<int, float, bool> t1 = makeTuple(3, 1.0f, true);
要想访问对应位置的成员变量,需要使用_X
:
int i = t0._0; // 5
bool b = t1._2; // true
t0._0_0_1 // evaluates to (5, 5, 2.0f)
可以用concat()
拼接两个Tuple:
concat(t0, t1) // evaluates to (5, 2.0f, false, 3, 1.0f, true)
可以用countof()
获取Tuple内元素个数:
int n = countof(Tuple<int, float>); // 2
int n1 = countof(makeTuple(1,2,3)); // 3
Optional<T>
类型
Slang支持Optional<T>
类型,代表可能不存在的值:
struct MyType
{
int val;
}
int useVal(Optional<MyType> p)
{
// Equivalent to `!p.hasValue`
if (p == none)
return 0;
return p.value.val;
}
int caller()
{
MyType v;
v.val = 0;
// OK to pass `MyType` to `Optional<MyType>`.
useVal(v);
// OK to pass `none` to `Optional<MyType>`.
useVal(none);
return 0;
}
可以用if let
样式获取该类型的值:
Optional<int> getOptInt() { ... }
void test()
{
if (let x = getOptInt())
{
// if we are here, `getOptInt` returns a value `int`.
// and `x` represents the `int` value.
}
}
reinterpret<T>
类型
在Shader中很难进行类型包装,但Slang提供了相关功能:
float4 myPackedVector = reinterpret<float4>(myVal);
只要目标类型不比原类型的小,就能通过reinterpret<T>()
进行类型包装的转换。
DescriptorHandle<T>
类型
Slang提供DescriptorHandle<T>
类型, 代表一个无绑定的资源句柄. 对于像HLSL, GLSL 和 SPRIV, 资源类型(如texture
, samplers
和 buffers
)的句柄是不透明的,DescriptorHandle<T>
会将其翻译为一个uint2
类型,以便能被定义在任何内存中。该uint2
值被视为访问全局描述符堆/数组的索引。
DescriptorHandle<T>
的定义如下:
struct DescriptorHandle<T> where T:IOpaqueDescriptor {}
其中IOpaqueDescriptor
是大部分资源类型,例如:textures
,ConstancBuffer
,RaytracingAccelerationStructure
,SamplerState
,SamplerComparisonState
和所有类型的StructuredBuffer
。
使用例如下:
uniform StructuredBuffer<DescriptorHandle<Texture2D>> textures;
uniform int textureIndex;
// define a descriptor handle using builtin convenience typealias:
uniform StructuredBuffer<float4>.Handle output;
[numthreads(1,1,1)]
void main()
{
output[0] = textures[textureIndex].Load(int3(0));
// Alternatively, this syntax is also valid:
(*output)[0] = textures[textureIndex]->Load(int3(0));
}
特殊语法
多层break
Slang支持多层break
:
outer:
for (int i = 0; i < 5; i++)
{
inner:
for (int j = 0; j < 10; j++)
{
if (someCondition)
break outer;
}
}
参考资料
- shader-slang/slang: Making it easier to work with shaders (github.com)
- Basic Convenience Features | slang