跳到主要内容

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, samplersbuffers)的句柄是不透明的,DescriptorHandle<T>会将其翻译为一个uint2类型,以便能被定义在任何内存中。该uint2值被视为访问全局描述符堆/数组的索引。

DescriptorHandle<T>的定义如下:

struct DescriptorHandle<T> where T:IOpaqueDescriptor {}

其中IOpaqueDescriptor是大部分资源类型,例如:texturesConstancBufferRaytracingAccelerationStructureSamplerStateSamplerComparisonState和所有类型的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;
}
}

参考资料