diff options
| author | Tim Foley <tfoley@nvidia.com> | 2017-06-21 10:43:25 -0700 |
|---|---|---|
| committer | Tim Foley <tfoley@nvidia.com> | 2017-06-21 11:59:51 -0700 |
| commit | 7f7864e80e8b5631ba5ec1aa9657fdaf1b4adb06 (patch) | |
| tree | a9d0bc921e9ead73e5ec9491c4f3925c041cdbf5 /source/slang/slang-stdlib.cpp | |
| parent | 5148c594c19da9466b151ab3b6b11441f265823e (diff) | |
Support texture `Gather*()` operations
The catch with these operations is that they return a vector based on the scalar of the element type of the texture.
That is, given `Texture2D<float> t` the operation `t.GatherRed(...)` should return a `float4`.
The ideal way to solve this would use associated types, but we aren't there yet, so I am using extension declarations.
An extension can "capture" the identity of the element type, like so:
__generic<T, let N : int> __extension Texture2D<vector<T,N> > { ... }
That extension will match `Texture2D<float3>` and correctly capture `T == float`, so that we can use it in other operations.
Getting this working required a bunch of changes:
- Actually emit the relevant extension declarations in the stdlib
- Fix the parser to be able to parse `Texture2D<vector<T,N> >` (that is, a nested generic app).
- I actually went ahead and significantly overhauled the expression parser while I was there, because I just couldn't deal with the existing code any longer.
- Added support for general-case lookup to look through `__extension` declarations. I had logic in place to special-case this for looking up "constructors" but hadn't done anything for general member lookup yet.
- This required some annoying holes to be punched through the layers, because lookup might need to invoke semantic analysis to ensure that an extension has been checked.
- There is some first-pass code trying to support looking up a `typedef` nested inside the `vector` type. This is a nice idea in principle, but the problem is that the `Texture2D<T>` definition would be looking up `T.Element` and not `float4.Element`, and that means we'd need machinery for doing lookup *through* interface conformances for a type parameter like `T`
The big gotcha here is that none of this logic applies to `Texture2D<float>` (the original case I mentioned) because I am matching vector types and not scalars.
Matching scalars *should* be as easy as:
__generic<T : __BuitlinScalarType> __extension Texture2D<T> { ... }
But I'd need to confirm that interface constraints like that actually work, or else that extension would *also* apply to `Texture2D<float4>` and break everything.
Diffstat (limited to 'source/slang/slang-stdlib.cpp')
| -rw-r--r-- | source/slang/slang-stdlib.cpp | 101 |
1 files changed, 95 insertions, 6 deletions
diff --git a/source/slang/slang-stdlib.cpp b/source/slang/slang-stdlib.cpp index 387b6fbb2..3a3f6d13f 100644 --- a/source/slang/slang-stdlib.cpp +++ b/source/slang/slang-stdlib.cpp @@ -1150,6 +1150,7 @@ namespace Slang // Declare vector and matrix types sb << "__generic<T = float, let N : int = 4> __magic_type(Vector) struct vector\n{\n"; + sb << " typedef T Element;\n"; sb << " __init(T value);\n"; // initialize from single scalar sb << "};\n"; sb << "__generic<T = float, let R : int = 4, let C : int = 4> __magic_type(Matrix) struct matrix {};\n"; @@ -1343,13 +1344,9 @@ namespace Slang sb << "float CalculateLevelOfDetailUnclamped(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount << " location);\n"; - - // TODO: `Gather` operation - // (tricky because it returns a 4-vector of the element type - // of the texture components...) } - // TODO: `GetDimensions` operations + // `GetDimensions` for(int isFloat = 0; isFloat < 2; ++isFloat) for(int includeMipInfo = 0; includeMipInfo < 2; ++includeMipInfo) @@ -1532,12 +1529,104 @@ namespace Slang } sb << "\n};\n"; + + // `Gather*()` operations are handled via an `extension` declaration, + // because this lets us capture the element type of the texture. + // + // TODO: longer-term there should be something like a `TextureElementType` + // interface, that both scalars and vectors implement, that then exposes + // a `Scalar` associated type, and `Gather` can return `vector<T.Scalar, 4>`. + // + static const struct { + char const* genericPrefix; + char const* elementType; + } kGatherExtensionCases[] = { + { "__generic<T, let N : int>", "vector<T,N>" }, + + // TODO: need a case here for scalars `T`, but also + // need to ensure that case doesn't accidentally match + // for `T = vector<...>`, which requires actual checking + // of constraints on generic parameters. + }; + for(auto cc : kGatherExtensionCases) + { + // TODO: this should really be an `if` around the entire `Gather` logic + if (isMultisample) break; + + EMIT_LINE_DIRECTIVE(); + sb << cc.genericPrefix << " __extension "; + sb << kBaseTextureAccessLevels[accessLevel].name; + sb << name; + if (isArray) sb << "Array"; + sb << "<" << cc.elementType << " >"; + sb << "\n{\n"; + + + // `Gather` + // (tricky because it returns a 4-vector of the element type + // of the texture components...) + // + // TODO: is it actually correct to restrict these so that, e.g., + // `GatherAlpha()` isn't allowed on `Texture2D<float3>` because + // it nominally doesn't have an alpha component? + static const struct { + int componentIndex; + char const* componentName; + } kGatherComponets[] = { + { 0, "" }, + { 0, "Red" }, + { 1, "Green" }, + { 2, "Blue" }, + { 3, "Alpha" }, + }; + + for(auto cc : kGatherComponets) + { + auto componentIndex = cc.componentIndex; + auto componentName = cc.componentName; + + EMIT_LINE_DIRECTIVE(); + sb << "vector<T, 4> Gather" << componentName << "(SamplerState s, "; + sb << "float" << kBaseTextureTypes[tt].coordCount << " location);\n"; + + EMIT_LINE_DIRECTIVE(); + sb << "vector<T, 4> Gather" << componentName << "(SamplerState s, "; + sb << "float" << kBaseTextureTypes[tt].coordCount << " location, "; + sb << "int" << kBaseTextureTypes[tt].coordCount << " offset);\n"; + + EMIT_LINE_DIRECTIVE(); + sb << "vector<T, 4> Gather" << componentName << "(SamplerState s, "; + sb << "float" << kBaseTextureTypes[tt].coordCount << " location, "; + sb << "int" << kBaseTextureTypes[tt].coordCount << " offset, "; + sb << "out uint status);\n"; + + EMIT_LINE_DIRECTIVE(); + sb << "vector<T, 4> Gather" << componentName << "(SamplerState s, "; + sb << "float" << kBaseTextureTypes[tt].coordCount << " location, "; + sb << "int" << kBaseTextureTypes[tt].coordCount << " offset1, "; + sb << "int" << kBaseTextureTypes[tt].coordCount << " offset2, "; + sb << "int" << kBaseTextureTypes[tt].coordCount << " offset3, "; + sb << "int" << kBaseTextureTypes[tt].coordCount << " offset4);\n"; + + EMIT_LINE_DIRECTIVE(); + sb << "vector<T, 4> Gather" << componentName << "(SamplerState s, "; + sb << "float" << kBaseTextureTypes[tt].coordCount << " location, "; + sb << "int" << kBaseTextureTypes[tt].coordCount << " offset1, "; + sb << "int" << kBaseTextureTypes[tt].coordCount << " offset2, "; + sb << "int" << kBaseTextureTypes[tt].coordCount << " offset3, "; + sb << "int" << kBaseTextureTypes[tt].coordCount << " offset4, "; + sb << "out uint status);\n"; + } + + EMIT_LINE_DIRECTIVE(); + sb << "\n}\n"; + } } } } // Declare additional built-in generic types - + EMIT_LINE_DIRECTIVE(); sb << "__generic<T> __magic_type(ConstantBuffer) struct ConstantBuffer {};\n"; sb << "__generic<T> __magic_type(TextureBuffer) struct TextureBuffer {};\n"; |
