Implement unbound varibility for struct types.
Now, if a struct member has an explicit 'uniform' or 'varying' qualifier, then that member has that variability, regardless of the variability of the struct's variability. Members without 'uniform' or 'varying' have unbound variability, and in turn inherit the variability of the struct. As a result of this, now structs can properly be 'varying' by default, just like all the other types, while still having sensible semantics.
This commit is contained in:
113
docs/ispc.rst
113
docs/ispc.rst
@@ -92,7 +92,8 @@ Contents:
|
||||
* `Reference Types`_
|
||||
* `Enumeration Types`_
|
||||
* `Short Vector Types`_
|
||||
* `Struct and Array Types`_
|
||||
* `Array Types`_
|
||||
* `Struct Types`_
|
||||
|
||||
+ `Declarations and Initializers`_
|
||||
+ `Expressions`_
|
||||
@@ -859,7 +860,9 @@ A variable that is declared with the ``uniform`` qualifier represents a
|
||||
single value that is shared across the entire gang. (In contrast, the
|
||||
default variability qualifier for variables in ``ispc``, ``varying``,
|
||||
represents a variable that has a distinct storage location for each program
|
||||
instance in the gang.)
|
||||
instance in the gang.) (Though see the discussion in `Struct Types`_ for
|
||||
some subtleties related to ``uniform`` and ``varying`` when used with
|
||||
structures.)
|
||||
|
||||
It is an error to try to assign a ``varying`` value to a ``uniform``
|
||||
variable, though ``uniform`` values can be assigned to ``uniform``
|
||||
@@ -1832,20 +1835,19 @@ expressions:
|
||||
int8<2> bar = ...;
|
||||
foo.yz = bar; // Error: can't assign to left-hand side of expression
|
||||
|
||||
Struct and Array Types
|
||||
----------------------
|
||||
|
||||
More complex data structures can be built using ``struct`` and arrays.
|
||||
Array Types
|
||||
-----------
|
||||
|
||||
Arrays of any type can be declared just as in C and C++:
|
||||
|
||||
::
|
||||
|
||||
struct Foo {
|
||||
float time;
|
||||
int flags[10];
|
||||
};
|
||||
float a[10];
|
||||
uniform int * varying b[20];
|
||||
|
||||
Like in C, multidimensional arrays can be specified; the following declares
|
||||
an array of 5 arrays of 15 floats.
|
||||
Multidimensional arrays can be specified as arrays of arrays; the following
|
||||
declares an array of 5 arrays of 15 floats.
|
||||
|
||||
::
|
||||
|
||||
@@ -1860,6 +1862,27 @@ that functions can be declared to take "unsized arrays" as parameters:
|
||||
|
||||
void foo(float array[], int length);
|
||||
|
||||
Finally, the name of an array will be automatically implicitly converted to
|
||||
a uniform pointer to the array type if needed:
|
||||
|
||||
::
|
||||
|
||||
int a[10];
|
||||
int * uniform ap = a;
|
||||
|
||||
|
||||
Struct Types
|
||||
------------
|
||||
|
||||
Aggregate data structures can be built using ``struct``.
|
||||
|
||||
::
|
||||
|
||||
struct Foo {
|
||||
float time;
|
||||
int flags[10];
|
||||
};
|
||||
|
||||
As in C++, after a ``struct`` is declared, an instance can be created using
|
||||
the ``struct``'s name:
|
||||
|
||||
@@ -1873,6 +1896,60 @@ Alternatively, ``struct`` can be used before the structure name:
|
||||
|
||||
struct Foo f;
|
||||
|
||||
Members in a structure declaration may each have ``uniform`` or ``varying``
|
||||
qualifiers, or may have no rate qualifier, in which case their variability
|
||||
is initially "unbound".
|
||||
|
||||
::
|
||||
|
||||
struct Bar {
|
||||
uniform int a;
|
||||
varying int b;
|
||||
int c;
|
||||
};
|
||||
|
||||
|
||||
In the declaration above, the variability of ``c`` is unbound. The
|
||||
variability of struct members that are unbound is resolved when a struct is
|
||||
defined; if the ``struct`` is ``uniform``, then unbound members are
|
||||
``uniform``, and if the ``struct`` is ``varying``, then unbound members are
|
||||
varying.
|
||||
|
||||
::
|
||||
|
||||
Bar vb;
|
||||
uniform Bar ub;
|
||||
|
||||
Here, ``b`` is a ``varying Bar`` (since ``varying`` is the default
|
||||
variability). If ``Bar`` is defined as above, then ``vb.a`` is still a
|
||||
``uniform int``, since its varaibility was bound in the original
|
||||
declaration of the ``Bar`` type. Similarly, ``vb.b`` is ``varying``. The
|
||||
variability fo ``vb.c`` is ``varying``, since ``vb`` is ``varying``.
|
||||
|
||||
(Similarly, ``ub.a`` is ``uniform``, ``ub.b`` is ``varying``, and ``ub.c``
|
||||
is ``uniform``.)
|
||||
|
||||
In most cases, it's worthwhile to declare ``struct`` members with unbound
|
||||
variability so that all have the same variability for both ``uniform`` and
|
||||
``varying`` structs. In particular, if a ``struct`` has a member with
|
||||
bound ``uniform`` type, it's not possible to index into an array of the
|
||||
struct type with a ``varying`` index. Consider the following example:
|
||||
|
||||
::
|
||||
|
||||
struct Foo { uniform int a; };
|
||||
uniform Foo f[...] = ...;
|
||||
int index = ...;
|
||||
Foo fv = f[index]; // ERROR
|
||||
|
||||
Here, the ``Foo`` type has a member with bound ``uniform`` variability.
|
||||
Because ``index`` has a different value for each program instance in the
|
||||
above code, the value of ``f[index]`` needs to be able to store a different
|
||||
value of ``Foo::a`` for each program instance. However, a ``varying Foo``
|
||||
still has only a single ``a`` member, since ``a`` was declared with
|
||||
``uniform`` variability in the declaration of ``Foo``. Therefore, the
|
||||
indexing operation in the last line results in an error.
|
||||
|
||||
|
||||
Declarations and Initializers
|
||||
-----------------------------
|
||||
@@ -3824,12 +3901,12 @@ equivalents of them.) For example, given a structure in ``ispc``:
|
||||
|
||||
// ispc code
|
||||
struct Node {
|
||||
uniform int count;
|
||||
uniform float pos[3];
|
||||
int count;
|
||||
float pos[3];
|
||||
};
|
||||
|
||||
If the ``Node`` structure is used in the parameters to an ``export`` ed
|
||||
function, then the header file generated by the ``ispc`` compiler will
|
||||
If a ``uniform Node`` structure is used in the parameters to an ``export``
|
||||
ed function, then the header file generated by the ``ispc`` compiler will
|
||||
have a declaration like:
|
||||
|
||||
::
|
||||
@@ -3970,7 +4047,7 @@ this:
|
||||
|
||||
::
|
||||
|
||||
export void length(Vector vectors[1024], uniform float len[]) {
|
||||
export void length(uniform Vector vectors[1024], uniform float len[]) {
|
||||
foreach (index = 0 ... 1024) {
|
||||
float x = vectors[index].x;
|
||||
float y = vectors[index].y;
|
||||
@@ -4038,7 +4115,7 @@ then an inner loop that peels off values from the element members:
|
||||
::
|
||||
|
||||
#define N_VEC (1024/16)
|
||||
export void length(Vector16 v[N_VEC], uniform float len[]) {
|
||||
export void length(uniform Vector16 v[N_VEC], uniform float len[]) {
|
||||
foreach (i = 0 ... N_VEC, j = 0 ... 16) {
|
||||
float x = v[i].x[j];
|
||||
float y = v[i].y[j];
|
||||
@@ -4075,7 +4152,7 @@ elements to work with and then proceeds with the computation.
|
||||
::
|
||||
|
||||
#define N_VEC (1024/4)
|
||||
export void length(Vector4 v[N_VEC], uniform float len[]) {
|
||||
export void length(uniform Vector4 v[N_VEC], uniform float len[]) {
|
||||
for (uniform int i = 0; i < N_VEC; i += programCount / 4) {
|
||||
float x, y, z;
|
||||
for (uniform int j = 0; j < programCount / 4; ++j) {
|
||||
|
||||
Reference in New Issue
Block a user