summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
authorTheresa Foley <10618364+tangent-vector@users.noreply.github.com>2023-07-03 14:40:20 -0700
committerGitHub <noreply@github.com>2023-07-03 14:40:20 -0700
commitf9b73eab7edcedc9dc2c7825fcd4171631d14ac7 (patch)
treedf04e8989aa55ea6a44caf13ef78d1633fe206af /source
parentae4273810c1bad35ffe0f745404cb14f2f20c104 (diff)
Refactor "meta" decls for stdlib texture types (#2932)
We use some ad-hoc "template engine" code generation / metaprogramming to generate many of the declarations in the Slang standard library. In many cases the level of meta-ness is (relatively) manageable, but one of the biggest tangles in the whole thing is the generation of the texture-related types. We basically have a single set of nested `for` loops that generate all types of the form: (RW|RasterizerOrdered|/**/)(Texture|Sampler)(1D|2D|...)Array?MS? Inside that loop we then have tons of conditional logic to determine: * Which points in the cross-product space should be skipped, rather than emitted as a type. * Which methods to emit, or not. * The type signature(s) of those methods. * The translation of those methods for each target (via `__target_intrinsic`) The code ends up being long, complicated, and very hard to maintain or extend. This change takes a first small step to try to help us get the complexity more under control. The basic approach is that the data that defines each point in the cross-product space is aggregated into a `TextureTypeInfo` structure in the meta-level code, and then the logic for emitting the declarations related to a given texture type is expressed as a member function of that type. The intention is that this design will more easily allow the meta-level code to be factored into distinct subroutines, and enable us to clean up and re-use recurring bits of text that need to appear in the output. It is possible (though I am not yet predicting it) that we will end up wanting to utilize a bit of an inheritance hierarchy on `TextureTypeInfo` to allow us to more cleanly factor out code that is specific to certain cases (e.g., there is only a small amount of sharing between `RW`/`RasterizerOrdered` and read-only texture types). It is intentional that this step introduces no significant changes to the logic that used to be inside the loop (and is now inside of a method). Instead, the goal is to minimize the scale of the diffs that reviewers might be expectecd to deal with in follow-on changes. Co-authored-by: Yong He <yonghe@outlook.com>
Diffstat (limited to 'source')
-rw-r--r--source/slang/core.meta.slang1644
1 files changed, 835 insertions, 809 deletions
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang
index 1677d6e12..d99b241c0 100644
--- a/source/slang/core.meta.slang
+++ b/source/slang/core.meta.slang
@@ -1243,20 +1243,18 @@ struct SamplerComparisonState
${{{{
-static const struct {
+static const struct BaseTextureShapeInfo {
char const* shapeName;
TextureFlavor::Shape baseShape;
int coordCount;
-} kBaseTextureTypes[] = {
+} kBaseTextureShapes[] = {
{ "1D", TextureFlavor::Shape::Shape1D, 1 },
{ "2D", TextureFlavor::Shape::Shape2D, 2 },
{ "3D", TextureFlavor::Shape::Shape3D, 3 },
{ "Cube", TextureFlavor::Shape::ShapeCube,3 },
};
-static const int kBaseTextureTypeCount = sizeof(kBaseTextureTypes) / sizeof(kBaseTextureTypes[0]);
-
-static const struct {
+static const struct BaseTextureAccessInfo {
char const* name;
SlangResourceAccess access;
} kBaseTextureAccessLevels[] = {
@@ -1264,7 +1262,6 @@ static const struct {
{ "RW", SLANG_RESOURCE_ACCESS_READ_WRITE },
{ "RasterizerOrdered", SLANG_RESOURCE_ACCESS_RASTER_ORDERED },
};
-static const int kBaseTextureAccessLevelCount = sizeof(kBaseTextureAccessLevels) / sizeof(kBaseTextureAccessLevels[0]);
static const struct TextureTypePrefixInfo
{
@@ -1276,950 +1273,979 @@ static const struct TextureTypePrefixInfo
{ "Sampler", true },
};
-for(auto& prefixInfo : kTexturePrefixes)
-for (int tt = 0; tt < kBaseTextureTypeCount; ++tt)
-{
- char const* baseName = prefixInfo.name;
- char const* baseShapeName = kBaseTextureTypes[tt].shapeName;
- TextureFlavor::Shape baseShape = kBaseTextureTypes[tt].baseShape;
+struct TextureTypeInfo
+{
+ TextureTypeInfo(
+ TextureTypePrefixInfo const& prefixInfo,
+ BaseTextureShapeInfo const& base,
+ bool isArray,
+ bool isMultisample,
+ BaseTextureAccessInfo const& accessInfo,
+ StringBuilder& inSB,
+ String const& inPath)
+ : prefixInfo(prefixInfo)
+ , base(base)
+ , isArray(isArray)
+ , isMultisample(isMultisample)
+ , accessInfo(accessInfo)
+ , sb(inSB)
+ , path(inPath)
+ {
+ }
+
+ TextureTypePrefixInfo const& prefixInfo;
+ BaseTextureShapeInfo const& base;
+ bool isArray;
+ bool isMultisample;
+ BaseTextureAccessInfo const& accessInfo;
+ StringBuilder& sb;
+ String path;
- for (int isArray = 0; isArray < 2; ++isArray)
+ void emitTypeDecl()
{
+ char const* baseName = prefixInfo.name;
+ char const* baseShapeName = base.shapeName;
+ TextureFlavor::Shape baseShape = base.baseShape;
+
// Arrays of 3D textures aren't allowed
- if (isArray && baseShape == TextureFlavor::Shape::Shape3D) continue;
+ if (isArray && baseShape == TextureFlavor::Shape::Shape3D) return;
+
+ auto access = accessInfo.access;
+
+ // No such thing as RWTextureCube
+ if (access == SLANG_RESOURCE_ACCESS_READ_WRITE && baseShape == TextureFlavor::Shape::ShapeCube)
+ {
+ return;
+ }
+
+ bool isReadOnly = (access == SLANG_RESOURCE_ACCESS_READ);
+ // TODO: any constraints to enforce on what gets to be multisampled?
+
+ unsigned flavor = baseShape;
+ if (isArray) flavor |= TextureFlavor::ArrayFlag;
+ if (isMultisample) flavor |= TextureFlavor::MultisampleFlag;
+// if (isShadow) flavor |= TextureFlavor::ShadowFlag;
+
+ flavor |= (access << 8);
+
+ // emit a generic signature
+ // TODO: allow for multisample count to come in as well...
+ sb << "__generic<T = float4> ";
- for (int isMultisample = 0; isMultisample < 2; ++isMultisample)
+ if(prefixInfo.combined)
+ {
+ sb << "__magic_type(TextureSampler," << int(flavor) << ")\n";
+ sb << "__intrinsic_type(" << (kIROp_TextureSamplerType + (int(flavor) << kIROpMeta_OtherShift)) << ")\n";
+ }
+ else
+ {
+ sb << "__magic_type(Texture," << int(flavor) << ")\n";
+ sb << "__intrinsic_type(" << (kIROp_TextureType + (int(flavor) << kIROpMeta_OtherShift)) << ")\n";
+ }
+ sb << "struct ";
+ sb << accessInfo.name;
+ sb << baseName;
+ sb << baseShapeName;
+ if (isMultisample) sb << "MS";
+ if (isArray) sb << "Array";
+// if (isShadow) sb << "Shadow";
+ sb << "\n{";
+
+ char const* samplerStateParam = prefixInfo.combined ? "" : "SamplerState s, ";
+
+ if( !isMultisample )
+ {
+ sb << "float CalculateLevelOfDetail(" << samplerStateParam;
+ sb << "float" << base.coordCount << " location);\n";
+
+ sb << "float CalculateLevelOfDetailUnclamped(" << samplerStateParam;
+ sb << "float" << base.coordCount << " location);\n";
+ }
+
+ // `GetDimensions`
+ const char* dimParamTypes[] = {"out float ", "out int ", "out uint "};
+ for(auto t : dimParamTypes)
+ for(int includeMipInfo = 0; includeMipInfo < 2; ++includeMipInfo)
{
- for (int accessLevel = 0; accessLevel < kBaseTextureAccessLevelCount; ++accessLevel)
{
- auto access = kBaseTextureAccessLevels[accessLevel].access;
+ sb << "__glsl_version(450)\n";
+ sb << "__glsl_extension(GL_EXT_samplerless_texture_functions)";
+ sb << "__target_intrinsic(glsl, \"(";
- // No such thing as RWTextureCube
- if (access == SLANG_RESOURCE_ACCESS_READ_WRITE && baseShape == TextureFlavor::Shape::ShapeCube)
+ int aa = 1;
+ String lodStr = ", 0";
+ if (includeMipInfo)
{
- continue;
+ int mipLevelArg = aa++;
+ lodStr = ", int($";
+ lodStr.append(mipLevelArg);
+ lodStr.append(")");
}
- bool isReadOnly = (access == SLANG_RESOURCE_ACCESS_READ);
- // TODO: any constraints to enforce on what gets to be multisampled?
+ String opStr = " = textureSize($0" + lodStr;
+ switch( access )
+ {
+ case SLANG_RESOURCE_ACCESS_READ_WRITE:
+ case SLANG_RESOURCE_ACCESS_RASTER_ORDERED:
+ opStr = " = imageSize($0";
+ break;
- unsigned flavor = baseShape;
- if (isArray) flavor |= TextureFlavor::ArrayFlag;
- if (isMultisample) flavor |= TextureFlavor::MultisampleFlag;
- // if (isShadow) flavor |= TextureFlavor::ShadowFlag;
+ default:
+ break;
+ }
- flavor |= (access << 8);
- // emit a generic signature
- // TODO: allow for multisample count to come in as well...
- sb << "__generic<T = float4> ";
+ int cc = 0;
+ switch(baseShape)
+ {
+ case TextureFlavor::Shape::Shape1D:
+ sb << "($" << aa++ << opStr << ")";
+ if (isArray)
+ {
+ sb << ".x";
+ }
+ sb << ")";
+ cc = 1;
+ break;
+
+ case TextureFlavor::Shape::Shape2D:
+ case TextureFlavor::Shape::ShapeCube:
+ sb << "($" << aa++ << opStr << ").x)";
+ sb << ", ($" << aa++ << opStr << ").y)";
+ cc = 2;
+ break;
+
+ case TextureFlavor::Shape::Shape3D:
+ sb << "($" << aa++ << opStr << ").x)";
+ sb << ", ($" << aa++ << opStr << ").y)";
+ sb << ", ($" << aa++ << opStr << ").z)";
+ cc = 3;
+ break;
+
+ default:
+ SLANG_UNEXPECTED("unhandled resource shape");
+ break;
+ }
- if(prefixInfo.combined)
+ if(isArray)
{
- sb << "__magic_type(TextureSampler," << int(flavor) << ")\n";
- sb << "__intrinsic_type(" << (kIROp_TextureSamplerType + (int(flavor) << kIROpMeta_OtherShift)) << ")\n";
+ sb << ", ($" << aa++ << opStr << ")." << kComponentNames[cc] << ")";
}
- else
+
+ if(isMultisample)
{
- sb << "__magic_type(Texture," << int(flavor) << ")\n";
- sb << "__intrinsic_type(" << (kIROp_TextureType + (int(flavor) << kIROpMeta_OtherShift)) << ")\n";
+ sb << ", ($" << aa++ << " = textureSamples($0))";
}
- sb << "struct ";
- sb << kBaseTextureAccessLevels[accessLevel].name;
- sb << baseName;
- sb << baseShapeName;
- if (isMultisample) sb << "MS";
- if (isArray) sb << "Array";
- // if (isShadow) sb << "Shadow";
- sb << "\n{";
-
- char const* samplerStateParam = prefixInfo.combined ? "" : "SamplerState s, ";
-
- if( !isMultisample )
+
+ if (includeMipInfo)
{
- sb << "float CalculateLevelOfDetail(" << samplerStateParam;
- sb << "float" << kBaseTextureTypes[tt].coordCount << " location);\n";
+ sb << ", ($" << aa++ << " = textureQueryLevels($0))";
+ }
+
+
+ sb << ")\")\n";
+ }
+
+ sb << "[__readNone]\n";
+ sb << "void GetDimensions(";
+ if(includeMipInfo)
+ sb << "uint mipLevel, ";
+
+ switch(baseShape)
+ {
+ case TextureFlavor::Shape::Shape1D:
+ sb << t << "width";
+ break;
+
+ case TextureFlavor::Shape::Shape2D:
+ case TextureFlavor::Shape::ShapeCube:
+ sb << t << "width,";
+ sb << t << "height";
+ break;
+
+ case TextureFlavor::Shape::Shape3D:
+ sb << t << "width,";
+ sb << t << "height,";
+ sb << t << "depth";
+ break;
+
+ default:
+ assert(!"unexpected");
+ break;
+ }
+
+ if(isArray)
+ {
+ sb << ", " << t << "elements";
+ }
+
+ if(isMultisample)
+ {
+ sb << ", " << t << "sampleCount";
+ }
+
+ if(includeMipInfo)
+ sb << ", " << t << "numberOfLevels";
+
+ sb << ");\n";
+ }
+
+ // `GetSamplePosition()`
+ if( isMultisample )
+ {
+ sb << "float2 GetSamplePosition(int s);\n";
+ }
- sb << "float CalculateLevelOfDetailUnclamped(" << samplerStateParam;
- sb << "float" << kBaseTextureTypes[tt].coordCount << " location);\n";
+ // `Load()`
+
+ if( base.coordCount + isArray < 4 )
+ {
+ // The `Load()` operation on an ordinary `Texture2D` takes
+ // an `int3` for the location, where `.xy` holds the texel
+ // coordinates, and `.z` holds the mip level to use.
+ //
+ // The third coordinate for mip level is absent in
+ // `Texure2DMS.Load()` and `RWTexture2D.Load`. This pattern
+ // is repreated for all the other texture shapes.
+ //
+ bool needsMipLevel = !isMultisample && (access == SLANG_RESOURCE_ACCESS_READ);
+
+ int loadCoordCount = base.coordCount + isArray + (needsMipLevel?1:0);
+
+ char const* glslFuncName = (access == SLANG_RESOURCE_ACCESS_READ) ? "texelFetch" : "imageLoad";
+
+ // When translating to GLSL, we need to break apart the `location` argument.
+ //
+ // TODO: this should realy be handled by having this member actually get lowered!
+ static const char* kGLSLLoadCoordsSwizzle[] = { "", "", "x", "xy", "xyz", "xyzw" };
+ static const char* kGLSLLoadLODSwizzle[] = { "", "", "y", "z", "w", "error" };
+
+ // TODO: The GLSL translations here only handle the read-only texture
+ // cases (stuff that lowers to `texture*` in GLSL) and not the stuff
+ // that lowers to `image*`.
+ //
+ // At some point it may make sense to separate the read-only and
+ // `RW`/`RasterizerOrdered` cases here rather than try to share code.
+
+ if (isMultisample)
+ {
+ sb << "__glsl_extension(GL_EXT_samplerless_texture_functions)";
+ sb << "__target_intrinsic(glsl, \"$c" << glslFuncName << "($0, $1, $2)$z\")\n";
+ }
+ else
+ {
+ sb << "__glsl_extension(GL_EXT_samplerless_texture_functions)";
+ sb << "__target_intrinsic(glsl, \"$c" << glslFuncName << "($0, ";
+ if( needsMipLevel )
+ {
+ sb << "($1)." << kGLSLLoadCoordsSwizzle[loadCoordCount] << ", ($1)." << kGLSLLoadLODSwizzle[loadCoordCount];
}
+ else
+ {
+ sb << "$1";
+ }
+ sb << ")$z\")\n";
+
+ }
- // `GetDimensions`
- const char* dimParamTypes[] = {"out float ", "out int ", "out uint "};
- for(auto t : dimParamTypes)
- for(int includeMipInfo = 0; includeMipInfo < 2; ++includeMipInfo)
+ // CUDA
+ if (isMultisample)
+ {
+ }
+ else
+ {
+ if (access == SLANG_RESOURCE_ACCESS_READ_WRITE)
{
- {
- sb << "__glsl_version(450)\n";
- sb << "__glsl_extension(GL_EXT_samplerless_texture_functions)";
- sb << "__target_intrinsic(glsl, \"(";
+ const int coordCount = base.coordCount;
+ const int vecCount = coordCount + int(isArray);
- int aa = 1;
- String lodStr = ", 0";
- if (includeMipInfo)
+ if( baseShape != TextureFlavor::Shape::ShapeCube )
+ {
+ sb << "__target_intrinsic(cuda, \"surf" << coordCount << "D";
+ if (isArray)
{
- int mipLevelArg = aa++;
- lodStr = ", int($";
- lodStr.append(mipLevelArg);
- lodStr.append(")");
+ sb << "Layered";
}
-
- String opStr = " = textureSize($0" + lodStr;
- switch( access )
+ sb << "read";
+ sb << "<$T0>($0";
+ for (int i = 0; i < coordCount; ++i)
{
- case SLANG_RESOURCE_ACCESS_READ_WRITE:
- case SLANG_RESOURCE_ACCESS_RASTER_ORDERED:
- opStr = " = imageSize($0";
- break;
-
- default:
- break;
- }
-
+ sb << ", ($1)";
+ if (vecCount > 1)
+ {
+ sb << '.' << char(i + 'x');
+ }
- int cc = 0;
- switch(baseShape)
- {
- case TextureFlavor::Shape::Shape1D:
- sb << "($" << aa++ << opStr << ")";
- if (isArray)
+ // Surface access is *byte* addressed in x in CUDA
+ if (i == 0)
{
- sb << ".x";
+ sb << " * $E";
}
- sb << ")";
- cc = 1;
- break;
-
- case TextureFlavor::Shape::Shape2D:
- case TextureFlavor::Shape::ShapeCube:
- sb << "($" << aa++ << opStr << ").x)";
- sb << ", ($" << aa++ << opStr << ").y)";
- cc = 2;
- break;
-
- case TextureFlavor::Shape::Shape3D:
- sb << "($" << aa++ << opStr << ").x)";
- sb << ", ($" << aa++ << opStr << ").y)";
- sb << ", ($" << aa++ << opStr << ").z)";
- cc = 3;
- break;
-
- default:
- SLANG_UNEXPECTED("unhandled resource shape");
- break;
}
-
- if(isArray)
+ if (isArray)
{
- sb << ", ($" << aa++ << opStr << ")." << kComponentNames[cc] << ")";
+ sb << ", int(($1)." << char(coordCount + 'x') << ")";
}
-
- if(isMultisample)
+ sb << ", SLANG_CUDA_BOUNDARY_MODE)\")\n";
+ }
+ else
+ {
+ sb << "__target_intrinsic(cuda, \"surfCubemap";
+ if (isArray)
{
- sb << ", ($" << aa++ << " = textureSamples($0))";
+ sb << "Layered";
}
+ sb << "read";
- if (includeMipInfo)
+ // Surface access is *byte* addressed in x in CUDA
+ sb << "<$T0>($0, ($1).x * $E, ($1).y, ($1).z";
+ if (isArray)
{
- sb << ", ($" << aa++ << " = textureQueryLevels($0))";
+ sb << ", int(($1).w)";
}
-
-
- sb << ")\")\n";
+ sb << ", SLANG_CUDA_BOUNDARY_MODE)\")\n";
}
-
- sb << "[__readNone]\n";
- sb << "void GetDimensions(";
- if(includeMipInfo)
- sb << "uint mipLevel, ";
-
- switch(baseShape)
- {
- case TextureFlavor::Shape::Shape1D:
- sb << t << "width";
- break;
-
- case TextureFlavor::Shape::Shape2D:
- case TextureFlavor::Shape::ShapeCube:
- sb << t << "width,";
- sb << t << "height";
- break;
-
- case TextureFlavor::Shape::Shape3D:
- sb << t << "width,";
- sb << t << "height,";
- sb << t << "depth";
- break;
-
- default:
- assert(!"unexpected");
- break;
- }
-
- if(isArray)
- {
- sb << ", " << t << "elements";
- }
-
- if(isMultisample)
+ }
+ else if (access == SLANG_RESOURCE_ACCESS_READ)
+ {
+ // We can allow this on Texture1D
+ if( baseShape == TextureFlavor::Shape::Shape1D && isArray == false)
{
- sb << ", " << t << "sampleCount";
+ sb << "__target_intrinsic(cuda, \"tex1Dfetch<$T0>($0, ($1).x)\")\n";
}
+ }
+ }
- if(includeMipInfo)
- sb << ", " << t << "numberOfLevels";
+ if (isReadOnly)
+ sb << "[__readNone]\n";
+ sb << "T Load(";
+ sb << "int" << loadCoordCount << " location";
+ if(isMultisample)
+ {
+ sb << ", int sampleIndex";
+ }
+ sb << ");\n";
- sb << ");\n";
+ // GLSL
+ if (isMultisample)
+ {
+ sb << "__glsl_extension(GL_EXT_samplerless_texture_functions)";
+ sb << "__target_intrinsic(glsl, \"$c" << glslFuncName << "($0, $0, $1, $2)$z\")\n";
+ }
+ else
+ {
+ sb << "__glsl_extension(GL_EXT_samplerless_texture_functions)";
+ sb << "__target_intrinsic(glsl, \"$c" << glslFuncName << "($0, ";
+ if( needsMipLevel )
+ {
+ sb << "($1)." << kGLSLLoadCoordsSwizzle[loadCoordCount] << ", ($1)." << kGLSLLoadLODSwizzle[loadCoordCount];
}
-
- // `GetSamplePosition()`
- if( isMultisample )
+ else
{
- sb << "float2 GetSamplePosition(int s);\n";
+ sb << "$1, 0";
}
+ sb << ", $2)$z\")\n";
+ }
- // `Load()`
+ if (isReadOnly)
+ sb << "[__readNone]\n";
+ sb << "T Load(";
+ sb << "int" << loadCoordCount << " location";
+ if(isMultisample)
+ {
+ sb << ", int sampleIndex";
+ }
+ sb << ", constexpr int" << base.coordCount << " offset";
+ sb << ");\n";
+
+ if (isReadOnly)
+ sb << "[__readNone]\n";
+ sb << "T Load(";
+ sb << "int" << loadCoordCount << " location";
+ if(isMultisample)
+ {
+ sb << ", int sampleIndex";
+ }
+ sb << ", constexpr int" << base.coordCount << " offset";
+ sb << ", out uint status";
+ sb << ");\n";
+ }
+
+ if(baseShape != TextureFlavor::Shape::ShapeCube)
+ {
+ int N = base.coordCount + isArray;
- if( kBaseTextureTypes[tt].coordCount + isArray < 4 )
+ char const* uintNs[] = { "", "uint", "uint2", "uint3", "uint4" };
+ char const* ivecNs[] = { "", "int", "ivec2", "ivec3", "ivec4" };
+
+ auto uintN = uintNs[N];
+ auto ivecN = ivecNs[N];
+
+ // subscript operator
+ sb << "__subscript(" << uintN << " location) -> T {\n";
+
+ // !!!!!!!!!!!!!!!!!!!! get !!!!!!!!!!!!!!!!!!!!!!!
+
+ // GLSL/SPIR-V distinguished sampled vs. non-sampled images
+ {
+ switch( access )
{
- // The `Load()` operation on an ordinary `Texture2D` takes
- // an `int3` for the location, where `.xy` holds the texel
- // coordinates, and `.z` holds the mip level to use.
- //
- // The third coordinate for mip level is absent in
- // `Texure2DMS.Load()` and `RWTexture2D.Load`. This pattern
- // is repreated for all the other texture shapes.
- //
- bool needsMipLevel = !isMultisample && (access == SLANG_RESOURCE_ACCESS_READ);
-
- int loadCoordCount = kBaseTextureTypes[tt].coordCount + isArray + (needsMipLevel?1:0);
-
- char const* glslFuncName = (access == SLANG_RESOURCE_ACCESS_READ) ? "texelFetch" : "imageLoad";
-
- // When translating to GLSL, we need to break apart the `location` argument.
- //
- // TODO: this should realy be handled by having this member actually get lowered!
- static const char* kGLSLLoadCoordsSwizzle[] = { "", "", "x", "xy", "xyz", "xyzw" };
- static const char* kGLSLLoadLODSwizzle[] = { "", "", "y", "z", "w", "error" };
-
- // TODO: The GLSL translations here only handle the read-only texture
- // cases (stuff that lowers to `texture*` in GLSL) and not the stuff
- // that lowers to `image*`.
- //
- // At some point it may make sense to separate the read-only and
- // `RW`/`RasterizerOrdered` cases here rather than try to share code.
-
- if (isMultisample)
+ case SLANG_RESOURCE_ACCESS_NONE:
+ case SLANG_RESOURCE_ACCESS_READ:
+ sb << "__glsl_extension(GL_EXT_samplerless_texture_functions)";
+ sb << "__target_intrinsic(glsl, \"$ctexelFetch($0, " << ivecN << "($1)";
+ if( !isMultisample )
{
- sb << "__glsl_extension(GL_EXT_samplerless_texture_functions)";
- sb << "__target_intrinsic(glsl, \"$c" << glslFuncName << "($0, $1, $2)$z\")\n";
+ sb << ", 0";
}
else
{
- sb << "__glsl_extension(GL_EXT_samplerless_texture_functions)";
- sb << "__target_intrinsic(glsl, \"$c" << glslFuncName << "($0, ";
- if( needsMipLevel )
- {
- sb << "($1)." << kGLSLLoadCoordsSwizzle[loadCoordCount] << ", ($1)." << kGLSLLoadLODSwizzle[loadCoordCount];
- }
- else
- {
- sb << "$1";
- }
- sb << ")$z\")\n";
-
+ // TODO: how to handle passing through sample index?
+ sb << ", 0";
}
+ break;
- // CUDA
- if (isMultisample)
+ default:
+ sb << "__target_intrinsic(glsl, \"$cimageLoad($0, " << ivecN << "($1)";
+ if( isMultisample )
{
+ // TODO: how to handle passing through sample index?
+ sb << ", 0";
}
- else
- {
- if (access == SLANG_RESOURCE_ACCESS_READ_WRITE)
- {
- const int coordCount = kBaseTextureTypes[tt].coordCount;
- const int vecCount = coordCount + int(isArray);
+ break;
+ }
+ sb << ")$z\")\n";
+ }
- if( baseShape != TextureFlavor::Shape::ShapeCube )
- {
- sb << "__target_intrinsic(cuda, \"surf" << coordCount << "D";
- if (isArray)
- {
- sb << "Layered";
- }
- sb << "read";
- sb << "<$T0>($0";
- for (int i = 0; i < coordCount; ++i)
- {
- sb << ", ($1)";
- if (vecCount > 1)
- {
- sb << '.' << char(i + 'x');
- }
-
- // Surface access is *byte* addressed in x in CUDA
- if (i == 0)
- {
- sb << " * $E";
- }
- }
- if (isArray)
- {
- sb << ", int(($1)." << char(coordCount + 'x') << ")";
- }
- sb << ", SLANG_CUDA_BOUNDARY_MODE)\")\n";
- }
- else
- {
- sb << "__target_intrinsic(cuda, \"surfCubemap";
- if (isArray)
- {
- sb << "Layered";
- }
- sb << "read";
-
- // Surface access is *byte* addressed in x in CUDA
- sb << "<$T0>($0, ($1).x * $E, ($1).y, ($1).z";
- if (isArray)
- {
- sb << ", int(($1).w)";
- }
- sb << ", SLANG_CUDA_BOUNDARY_MODE)\")\n";
- }
- }
- else if (access == SLANG_RESOURCE_ACCESS_READ)
- {
- // We can allow this on Texture1D
- if( baseShape == TextureFlavor::Shape::Shape1D && isArray == false)
- {
- sb << "__target_intrinsic(cuda, \"tex1Dfetch<$T0>($0, ($1).x)\")\n";
- }
- }
- }
+ // CUDA
+ {
+ if (access == SLANG_RESOURCE_ACCESS_READ_WRITE)
+ {
+ const int coordCount = base.coordCount;
+ const int vecCount = coordCount + int(isArray);
- if (isReadOnly)
- sb << "[__readNone]\n";
- sb << "T Load(";
- sb << "int" << loadCoordCount << " location";
- if(isMultisample)
+ sb << "__target_intrinsic(cuda, \"surf";
+ if( baseShape != TextureFlavor::Shape::ShapeCube )
{
- sb << ", int sampleIndex";
+ sb << coordCount << "D";
}
- sb << ");\n";
-
- // GLSL
- if (isMultisample)
+ else
{
- sb << "__glsl_extension(GL_EXT_samplerless_texture_functions)";
- sb << "__target_intrinsic(glsl, \"$c" << glslFuncName << "($0, $0, $1, $2)$z\")\n";
+ sb << "Cubemap";
}
- else
+
+ sb << (isArray ? "Layered" : "");
+ sb << "read$C<$T0>($0";
+
+ for (int i = 0; i < vecCount; ++i)
{
- sb << "__glsl_extension(GL_EXT_samplerless_texture_functions)";
- sb << "__target_intrinsic(glsl, \"$c" << glslFuncName << "($0, ";
- if( needsMipLevel )
+ sb << ", ($1)";
+ if (vecCount > 1)
{
- sb << "($1)." << kGLSLLoadCoordsSwizzle[loadCoordCount] << ", ($1)." << kGLSLLoadLODSwizzle[loadCoordCount];
+ sb << '.' << char(i + 'x');
}
- else
+ // Surface access is *byte* addressed in x in CUDA
+ if (i == 0)
{
- sb << "$1, 0";
+ sb << " * $E";
}
- sb << ", $2)$z\")\n";
}
- if (isReadOnly)
- sb << "[__readNone]\n";
- sb << "T Load(";
- sb << "int" << loadCoordCount << " location";
- if(isMultisample)
- {
- sb << ", int sampleIndex";
- }
- sb << ", constexpr int" << kBaseTextureTypes[tt].coordCount << " offset";
- sb << ");\n";
-
- if (isReadOnly)
- sb << "[__readNone]\n";
- sb << "T Load(";
- sb << "int" << loadCoordCount << " location";
- if(isMultisample)
+ sb << ", SLANG_CUDA_BOUNDARY_MODE)\")\n";
+ }
+ else if (access == SLANG_RESOURCE_ACCESS_READ)
+ {
+ // We can allow this on Texture1D
+ if( baseShape == TextureFlavor::Shape::Shape1D && isArray == false)
{
- sb << ", int sampleIndex";
+ sb << "__target_intrinsic(cuda, \"tex1Dfetch<$T0>($0, $1)\")\n";
}
- sb << ", constexpr int" << kBaseTextureTypes[tt].coordCount << " offset";
- sb << ", out uint status";
- sb << ");\n";
}
+ }
- if(baseShape != TextureFlavor::Shape::ShapeCube)
- {
- int N = kBaseTextureTypes[tt].coordCount + isArray;
-
- char const* uintNs[] = { "", "uint", "uint2", "uint3", "uint4" };
- char const* ivecNs[] = { "", "int", "ivec2", "ivec3", "ivec4" };
+ // Output that has get
+ if (isReadOnly)
+ sb << "[__readNone]\n";
+ sb << " get;\n";
- auto uintN = uintNs[N];
- auto ivecN = ivecNs[N];
+ // !!!!!!!!!!!!!!!!!!!! set !!!!!!!!!!!!!!!!!!!!!!!
- // subscript operator
- sb << "__subscript(" << uintN << " location) -> T {\n";
+ if (!(access == SLANG_RESOURCE_ACCESS_NONE || access == SLANG_RESOURCE_ACCESS_READ))
+ {
+ // GLSL
+ sb << "__target_intrinsic(glsl, \"imageStore($0, " << ivecN << "($1), $V2)\")\n";
- // !!!!!!!!!!!!!!!!!!!! get !!!!!!!!!!!!!!!!!!!!!!!
+ // CUDA
+ {
+ const int coordCount = base.coordCount;
+ const int vecCount = coordCount + int(isArray);
- // GLSL/SPIR-V distinguished sampled vs. non-sampled images
+ sb << "__target_intrinsic(cuda, \"surf";
+ if( baseShape != TextureFlavor::Shape::ShapeCube )
{
- switch( access )
- {
- case SLANG_RESOURCE_ACCESS_NONE:
- case SLANG_RESOURCE_ACCESS_READ:
- sb << "__glsl_extension(GL_EXT_samplerless_texture_functions)";
- sb << "__target_intrinsic(glsl, \"$ctexelFetch($0, " << ivecN << "($1)";
- if( !isMultisample )
- {
- sb << ", 0";
- }
- else
- {
- // TODO: how to handle passing through sample index?
- sb << ", 0";
- }
- break;
-
- default:
- sb << "__target_intrinsic(glsl, \"$cimageLoad($0, " << ivecN << "($1)";
- if( isMultisample )
- {
- // TODO: how to handle passing through sample index?
- sb << ", 0";
- }
- break;
- }
- sb << ")$z\")\n";
+ sb << coordCount << "D";
+ }
+ else
+ {
+ sb << "Cubemap";
}
- // CUDA
+ sb << (isArray ? "Layered" : "");
+ sb << "write$C<$T0>($2, $0";
+ for (int i = 0; i < vecCount; ++i)
{
- if (access == SLANG_RESOURCE_ACCESS_READ_WRITE)
+ sb << ", ($1)";
+ if (vecCount > 1)
{
- const int coordCount = kBaseTextureTypes[tt].coordCount;
- const int vecCount = coordCount + int(isArray);
-
- sb << "__target_intrinsic(cuda, \"surf";
- if( baseShape != TextureFlavor::Shape::ShapeCube )
- {
- sb << coordCount << "D";
- }
- else
- {
- sb << "Cubemap";
- }
-
- sb << (isArray ? "Layered" : "");
- sb << "read$C<$T0>($0";
-
- for (int i = 0; i < vecCount; ++i)
- {
- sb << ", ($1)";
- if (vecCount > 1)
- {
- sb << '.' << char(i + 'x');
- }
- // Surface access is *byte* addressed in x in CUDA
- if (i == 0)
- {
- sb << " * $E";
- }
- }
-
- sb << ", SLANG_CUDA_BOUNDARY_MODE)\")\n";
+ sb << '.' << char(i + 'x');
}
- else if (access == SLANG_RESOURCE_ACCESS_READ)
+
+ // Surface access is *byte* addressed in x in CUDA
+ if (i == 0)
{
- // We can allow this on Texture1D
- if( baseShape == TextureFlavor::Shape::Shape1D && isArray == false)
- {
- sb << "__target_intrinsic(cuda, \"tex1Dfetch<$T0>($0, $1)\")\n";
- }
+ sb << " * $E";
}
}
- // Output that has get
- if (isReadOnly)
- sb << "[__readNone]\n";
- sb << " get;\n";
-
- // !!!!!!!!!!!!!!!!!!!! set !!!!!!!!!!!!!!!!!!!!!!!
+ sb << ", SLANG_CUDA_BOUNDARY_MODE)\")\n";
+ }
- if (!(access == SLANG_RESOURCE_ACCESS_NONE || access == SLANG_RESOURCE_ACCESS_READ))
- {
- // GLSL
- sb << "__target_intrinsic(glsl, \"imageStore($0, " << ivecN << "($1), $V2)\")\n";
+ // Set
+ sb << " [nonmutating] set;\n";
+ }
- // CUDA
- {
- const int coordCount = kBaseTextureTypes[tt].coordCount;
- const int vecCount = coordCount + int(isArray);
+ // !!!!!!!!!!!!!!!!!! ref !!!!!!!!!!!!!!!!!!!!!!!!!
+
+ // Depending on the access level of the texture type,
+ // we either have just a getter (the default), or both
+ // a getter and setter.
+ switch( access )
+ {
+ case SLANG_RESOURCE_ACCESS_NONE:
+ case SLANG_RESOURCE_ACCESS_READ:
+ break;
+ default:
+ sb << "__intrinsic_op(" << int(kIROp_ImageSubscript) << ") ref;\n";
+ break;
+ }
- sb << "__target_intrinsic(cuda, \"surf";
- if( baseShape != TextureFlavor::Shape::ShapeCube )
- {
- sb << coordCount << "D";
- }
- else
- {
- sb << "Cubemap";
- }
+ sb << "}\n";
+ }
- sb << (isArray ? "Layered" : "");
- sb << "write$C<$T0>($2, $0";
- for (int i = 0; i < vecCount; ++i)
- {
- sb << ", ($1)";
- if (vecCount > 1)
- {
- sb << '.' << char(i + 'x');
- }
-
- // Surface access is *byte* addressed in x in CUDA
- if (i == 0)
- {
- sb << " * $E";
- }
- }
+ if( !isMultisample )
+ {
+ // `Sample()`
- sb << ", SLANG_CUDA_BOUNDARY_MODE)\")\n";
- }
+ sb << "__target_intrinsic(glsl, \"$ctexture($p, $2)$z\")\n";
- // Set
- sb << " [nonmutating] set;\n";
- }
+ // CUDA
+ {
+ const int coordCount = base.coordCount;
+ const int vecCount = coordCount + int(isArray);
- // !!!!!!!!!!!!!!!!!! ref !!!!!!!!!!!!!!!!!!!!!!!!!
-
- // Depending on the access level of the texture type,
- // we either have just a getter (the default), or both
- // a getter and setter.
- switch( access )
+ if( baseShape != TextureFlavor::Shape::ShapeCube )
+ {
+ sb << "__target_intrinsic(cuda, \"tex" << coordCount << "D";
+ if (isArray)
{
- case SLANG_RESOURCE_ACCESS_NONE:
- case SLANG_RESOURCE_ACCESS_READ:
- break;
- default:
- sb << "__intrinsic_op(" << int(kIROp_ImageSubscript) << ") ref;\n";
- break;
+ sb << "Layered";
}
-
- sb << "}\n";
- }
-
- if( !isMultisample )
- {
- // `Sample()`
-
- sb << "__target_intrinsic(glsl, \"$ctexture($p, $2)$z\")\n";
-
- // CUDA
+ sb << "<$T0>($0";
+ for (int i = 0; i < coordCount; ++i)
{
- const int coordCount = kBaseTextureTypes[tt].coordCount;
- const int vecCount = coordCount + int(isArray);
-
- if( baseShape != TextureFlavor::Shape::ShapeCube )
+ sb << ", ($2)";
+ if (vecCount > 1)
{
- sb << "__target_intrinsic(cuda, \"tex" << coordCount << "D";
- if (isArray)
- {
- sb << "Layered";
- }
- sb << "<$T0>($0";
- for (int i = 0; i < coordCount; ++i)
- {
- sb << ", ($2)";
- if (vecCount > 1)
- {
- sb << '.' << char(i + 'x');
- }
- }
- if (isArray)
- {
- sb << ", int(($2)." << char(coordCount + 'x') << ")";
- }
- sb << ")\")\n";
- }
- else
- {
- sb << "__target_intrinsic(cuda, \"texCubemap";
- if (isArray)
- {
- sb << "Layered";
- }
- sb << "<$T0>($0, ($2).x, ($2).y, ($2).z";
- if (isArray)
- {
- sb << ", int(($2).w)";
- }
- sb << ")\")\n";
+ sb << '.' << char(i + 'x');
}
}
-
- if (isReadOnly)
- sb << "[__readNone]\n";
- sb << "T Sample(" << samplerStateParam;;
- sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location);\n";
-
- if( baseShape != TextureFlavor::Shape::ShapeCube )
+ if (isArray)
{
- sb << "__target_intrinsic(glsl, \"$ctextureOffset($p, $2, $3)$z\")\n";
- if (isReadOnly)
- sb << "[__readNone]\n";
- sb << "T Sample(" << samplerStateParam;;
- sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, ";
- sb << "constexpr int" << kBaseTextureTypes[tt].coordCount << " offset);\n";
+ sb << ", int(($2)." << char(coordCount + 'x') << ")";
}
-
- if (isReadOnly)
- sb << "[__readNone]\n";
- sb << "T Sample(" << samplerStateParam;
- sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, ";
- if( baseShape != TextureFlavor::Shape::ShapeCube )
+ sb << ")\")\n";
+ }
+ else
+ {
+ sb << "__target_intrinsic(cuda, \"texCubemap";
+ if (isArray)
{
- sb << "constexpr int" << kBaseTextureTypes[tt].coordCount << " offset, ";
+ sb << "Layered";
}
- sb << "float clamp);\n";
-
- if (isReadOnly)
- sb << "[__readNone]\n";
- sb << "T Sample(" << samplerStateParam;
- sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, ";
- if( baseShape != TextureFlavor::Shape::ShapeCube )
+ sb << "<$T0>($0, ($2).x, ($2).y, ($2).z";
+ if (isArray)
{
- sb << "constexpr int" << kBaseTextureTypes[tt].coordCount << " offset, ";
+ sb << ", int(($2).w)";
}
- sb << "float clamp, out uint status);\n";
+ sb << ")\")\n";
+ }
+ }
- // `SampleBias()`
- sb << "__target_intrinsic(glsl, \"$ctexture($p, $2, $3)$z\")\n";
- if (isReadOnly)
- sb << "[__readNone]\n";
- sb << "T SampleBias(" << samplerStateParam;
- sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, float bias);\n";
+ if (isReadOnly)
+ sb << "[__readNone]\n";
+ sb << "T Sample(" << samplerStateParam;;
+ sb << "float" << base.coordCount + isArray << " location);\n";
- if( baseShape != TextureFlavor::Shape::ShapeCube )
- {
- sb << "__target_intrinsic(glsl, \"$ctextureOffset($p, $2, $3, $4)$z\")\n";
- if (isReadOnly)
- sb << "[__readNone]\n";
- sb << "T SampleBias(" << samplerStateParam;
- sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, float bias, ";
- sb << "constexpr int" << kBaseTextureTypes[tt].coordCount << " offset);\n";
- }
- int baseCoordCount = kBaseTextureTypes[tt].coordCount;
- int arrCoordCount = baseCoordCount + isArray;
- if (arrCoordCount <= 3)
- {
- // `SampleCmp()` and `SampleCmpLevelZero`
- sb << "__target_intrinsic(glsl, \"texture($p, vec" << arrCoordCount + 1 << "($2, $3))\")";
- if (isReadOnly)
- sb << "[__readNone]\n";
- sb << "float SampleCmp(SamplerComparisonState s, ";
- sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, ";
- sb << "float compareValue";
- sb << ");\n";
- sb << "__target_intrinsic(glsl, \"texture($p, vec" << arrCoordCount + 1 << "($2, $3))\")";
- if (isReadOnly)
- sb << "[__readNone]\n";
- sb << "float SampleCmpLevelZero(SamplerComparisonState s, ";
- sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, ";
- sb << "float compareValue";
- sb << ");\n";
- }
- if (arrCoordCount < 3)
- {
- int extCoordCount = arrCoordCount + 1;
+ if( baseShape != TextureFlavor::Shape::ShapeCube )
+ {
+ sb << "__target_intrinsic(glsl, \"$ctextureOffset($p, $2, $3)$z\")\n";
+ if (isReadOnly)
+ sb << "[__readNone]\n";
+ sb << "T Sample(" << samplerStateParam;;
+ sb << "float" << base.coordCount + isArray << " location, ";
+ sb << "constexpr int" << base.coordCount << " offset);\n";
+ }
- if (extCoordCount < 3)
- extCoordCount = 3;
+ if (isReadOnly)
+ sb << "[__readNone]\n";
+ sb << "T Sample(" << samplerStateParam;
+ sb << "float" << base.coordCount + isArray << " location, ";
+ if( baseShape != TextureFlavor::Shape::ShapeCube )
+ {
+ sb << "constexpr int" << base.coordCount << " offset, ";
+ }
+ sb << "float clamp);\n";
- sb << "__target_intrinsic(glsl, \"$ctextureLod($p, ";
+ if (isReadOnly)
+ sb << "[__readNone]\n";
+ sb << "T Sample(" << samplerStateParam;
+ sb << "float" << base.coordCount + isArray << " location, ";
+ if( baseShape != TextureFlavor::Shape::ShapeCube )
+ {
+ sb << "constexpr int" << base.coordCount << " offset, ";
+ }
+ sb << "float clamp, out uint status);\n";
- sb << "vec" << extCoordCount << "($2,";
- for (int ii = arrCoordCount; ii < extCoordCount - 1; ++ii)
- {
- sb << " 0.0,";
- }
- sb << "$3)";
+ // `SampleBias()`
+ sb << "__target_intrinsic(glsl, \"$ctexture($p, $2, $3)$z\")\n";
+ if (isReadOnly)
+ sb << "[__readNone]\n";
+ sb << "T SampleBias(" << samplerStateParam;
+ sb << "float" << base.coordCount + isArray << " location, float bias);\n";
- sb << ", 0.0)$z\")\n";
- }
- else if(arrCoordCount <= 3)
- {
- int extCoordCount = arrCoordCount + 1;
+ if( baseShape != TextureFlavor::Shape::ShapeCube )
+ {
+ sb << "__target_intrinsic(glsl, \"$ctextureOffset($p, $2, $3, $4)$z\")\n";
+ if (isReadOnly)
+ sb << "[__readNone]\n";
+ sb << "T SampleBias(" << samplerStateParam;
+ sb << "float" << base.coordCount + isArray << " location, float bias, ";
+ sb << "constexpr int" << base.coordCount << " offset);\n";
+ }
+ int baseCoordCount = base.coordCount;
+ int arrCoordCount = baseCoordCount + isArray;
+ if (arrCoordCount <= 3)
+ {
+ // `SampleCmp()` and `SampleCmpLevelZero`
+ sb << "__target_intrinsic(glsl, \"texture($p, vec" << arrCoordCount + 1 << "($2, $3))\")";
+ if (isReadOnly)
+ sb << "[__readNone]\n";
+ sb << "float SampleCmp(SamplerComparisonState s, ";
+ sb << "float" << base.coordCount + isArray << " location, ";
+ sb << "float compareValue";
+ sb << ");\n";
+ sb << "__target_intrinsic(glsl, \"texture($p, vec" << arrCoordCount + 1 << "($2, $3))\")";
+ if (isReadOnly)
+ sb << "[__readNone]\n";
+ sb << "float SampleCmpLevelZero(SamplerComparisonState s, ";
+ sb << "float" << base.coordCount + isArray << " location, ";
+ sb << "float compareValue";
+ sb << ");\n";
+ }
+ if (arrCoordCount < 3)
+ {
+ int extCoordCount = arrCoordCount + 1;
- if (extCoordCount < 3)
- extCoordCount = 3;
+ if (extCoordCount < 3)
+ extCoordCount = 3;
- sb << "__target_intrinsic(glsl, \"$ctextureGrad($p, ";
+ sb << "__target_intrinsic(glsl, \"$ctextureLod($p, ";
- sb << "vec" << extCoordCount << "($2,";
- for (int ii = arrCoordCount; ii < extCoordCount - 1; ++ii)
- {
- sb << " 0.0,";
- }
- sb << "$3)";
+ sb << "vec" << extCoordCount << "($2,";
+ for (int ii = arrCoordCount; ii < extCoordCount - 1; ++ii)
+ {
+ sb << " 0.0,";
+ }
+ sb << "$3)";
- // Construct gradients
- sb << ", vec" << baseCoordCount << "(0.0)";
- sb << ", vec" << baseCoordCount << "(0.0)";
- sb << ")$z\")\n";
- }
+ sb << ", 0.0)$z\")\n";
+ }
+ else if(arrCoordCount <= 3)
+ {
+ int extCoordCount = arrCoordCount + 1;
+
+ if (extCoordCount < 3)
+ extCoordCount = 3;
+
+ sb << "__target_intrinsic(glsl, \"$ctextureGrad($p, ";
+
+ sb << "vec" << extCoordCount << "($2,";
+ for (int ii = arrCoordCount; ii < extCoordCount - 1; ++ii)
+ {
+ sb << " 0.0,";
+ }
+ sb << "$3)";
+
+ // Construct gradients
+ sb << ", vec" << baseCoordCount << "(0.0)";
+ sb << ", vec" << baseCoordCount << "(0.0)";
+ sb << ")$z\")\n";
+ }
- if( baseShape != TextureFlavor::Shape::ShapeCube )
- {
- // Note(tfoley): MSDN seems confused, and claims that the `offset`
- // parameter for `SampleCmp` is available for everything but 3D
- // textures, while `Sample` and `SampleBias` are consistent in
- // saying they only exclude `offset` for cube maps (which makes
- // sense). I'm going to assume the documentation for `SampleCmp`
- // is just wrong.
- if (isReadOnly)
- sb << "[__readNone]\n";
- sb << "float SampleCmp(SamplerComparisonState s, ";
- sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, ";
- sb << "float compareValue, ";
- sb << "constexpr int" << kBaseTextureTypes[tt].coordCount << " offset);\n";
-
- if (isReadOnly)
- sb << "[__readNone]\n";
- sb << "float SampleCmpLevelZero(SamplerComparisonState s, ";
- sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, ";
- sb << "float compareValue, ";
- sb << "constexpr int" << kBaseTextureTypes[tt].coordCount << " offset);\n";
- }
+ if( baseShape != TextureFlavor::Shape::ShapeCube )
+ {
+ // Note(tfoley): MSDN seems confused, and claims that the `offset`
+ // parameter for `SampleCmp` is available for everything but 3D
+ // textures, while `Sample` and `SampleBias` are consistent in
+ // saying they only exclude `offset` for cube maps (which makes
+ // sense). I'm going to assume the documentation for `SampleCmp`
+ // is just wrong.
+ if (isReadOnly)
+ sb << "[__readNone]\n";
+ sb << "float SampleCmp(SamplerComparisonState s, ";
+ sb << "float" << base.coordCount + isArray << " location, ";
+ sb << "float compareValue, ";
+ sb << "constexpr int" << base.coordCount << " offset);\n";
- // TODO(JS): Not clear how to map this to CUDA, because in HLSL, the gradient is a vector based on
- // the dimension. On CUDA there is texNDGrad, but it always just takes ddx, ddy.
- // I could just assume 0 for elements not supplied, and ignore z. For now will just leave
- sb << "__target_intrinsic(glsl, \"$ctextureGrad($p, $2, $3, $4)$z\")\n";
- if (isReadOnly)
- sb << "[__readNone]\n";
- sb << "T SampleGrad(" << samplerStateParam;
- sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, ";
- sb << "float" << kBaseTextureTypes[tt].coordCount << " gradX, ";
- sb << "float" << kBaseTextureTypes[tt].coordCount << " gradY";
- sb << ");\n";
+ if (isReadOnly)
+ sb << "[__readNone]\n";
+ sb << "float SampleCmpLevelZero(SamplerComparisonState s, ";
+ sb << "float" << base.coordCount + isArray << " location, ";
+ sb << "float compareValue, ";
+ sb << "constexpr int" << base.coordCount << " offset);\n";
+ }
- if( baseShape != TextureFlavor::Shape::ShapeCube )
- {
- sb << "__target_intrinsic(glsl, \"$ctextureGradOffset($p, $2, $3, $4, $5)$z\")\n";
- if (isReadOnly)
- sb << "[__readNone]\n";
- sb << "T SampleGrad(" << samplerStateParam;
- sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, ";
- sb << "float" << kBaseTextureTypes[tt].coordCount << " gradX, ";
- sb << "float" << kBaseTextureTypes[tt].coordCount << " gradY, ";
- sb << "constexpr int" << kBaseTextureTypes[tt].coordCount << " offset);\n";
-
- sb << "__glsl_extension(GL_ARB_sparse_texture_clamp)";
- sb << "__target_intrinsic(glsl, \"$ctextureGradOffsetClampARB($p, $2, $3, $4, $5, $6)$z\")\n";
- if (isReadOnly)
- sb << "[__readNone]\n";
- sb << "T SampleGrad(" << samplerStateParam;
- sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, ";
- sb << "float" << kBaseTextureTypes[tt].coordCount << " gradX, ";
- sb << "float" << kBaseTextureTypes[tt].coordCount << " gradY, ";
- sb << "constexpr int" << kBaseTextureTypes[tt].coordCount << " offset, ";
- sb << "float lodClamp);\n";
+ // TODO(JS): Not clear how to map this to CUDA, because in HLSL, the gradient is a vector based on
+ // the dimension. On CUDA there is texNDGrad, but it always just takes ddx, ddy.
+ // I could just assume 0 for elements not supplied, and ignore z. For now will just leave
+ sb << "__target_intrinsic(glsl, \"$ctextureGrad($p, $2, $3, $4)$z\")\n";
+ if (isReadOnly)
+ sb << "[__readNone]\n";
+ sb << "T SampleGrad(" << samplerStateParam;
+ sb << "float" << base.coordCount + isArray << " location, ";
+ sb << "float" << base.coordCount << " gradX, ";
+ sb << "float" << base.coordCount << " gradY";
+ sb << ");\n";
+
+ if( baseShape != TextureFlavor::Shape::ShapeCube )
+ {
+ sb << "__target_intrinsic(glsl, \"$ctextureGradOffset($p, $2, $3, $4, $5)$z\")\n";
+ if (isReadOnly)
+ sb << "[__readNone]\n";
+ sb << "T SampleGrad(" << samplerStateParam;
+ sb << "float" << base.coordCount + isArray << " location, ";
+ sb << "float" << base.coordCount << " gradX, ";
+ sb << "float" << base.coordCount << " gradY, ";
+ sb << "constexpr int" << base.coordCount << " offset);\n";
+
+ sb << "__glsl_extension(GL_ARB_sparse_texture_clamp)";
+ sb << "__target_intrinsic(glsl, \"$ctextureGradOffsetClampARB($p, $2, $3, $4, $5, $6)$z\")\n";
+ if (isReadOnly)
+ sb << "[__readNone]\n";
+ sb << "T SampleGrad(" << samplerStateParam;
+ sb << "float" << base.coordCount + isArray << " location, ";
+ sb << "float" << base.coordCount << " gradX, ";
+ sb << "float" << base.coordCount << " gradY, ";
+ sb << "constexpr int" << base.coordCount << " offset, ";
+ sb << "float lodClamp);\n";
- }
+ }
- // `SampleLevel`
+ // `SampleLevel`
- sb << "__target_intrinsic(glsl, \"$ctextureLod($p, $2, $3)$z\")\n";
+ sb << "__target_intrinsic(glsl, \"$ctextureLod($p, $2, $3)$z\")\n";
- // CUDA
- {
- const int coordCount = kBaseTextureTypes[tt].coordCount;
- const int vecCount = coordCount + int(isArray);
+ // CUDA
+ {
+ const int coordCount = base.coordCount;
+ const int vecCount = coordCount + int(isArray);
- if( baseShape != TextureFlavor::Shape::ShapeCube )
- {
- sb << "__target_intrinsic(cuda, \"tex" << coordCount << "D";
- if (isArray)
- {
- sb << "Layered";
- }
- sb << "Lod<$T0>($0";
- for (int i = 0; i < coordCount; ++i)
- {
- sb << ", ($2)";
- if (vecCount > 1)
- {
- sb << '.' << char(i + 'x');
- }
- }
- if (isArray)
- {
- sb << ", int(($2)." << char(coordCount + 'x') << ")";
- }
- sb << ", $3)\")\n";
- }
- else
+ if( baseShape != TextureFlavor::Shape::ShapeCube )
+ {
+ sb << "__target_intrinsic(cuda, \"tex" << coordCount << "D";
+ if (isArray)
+ {
+ sb << "Layered";
+ }
+ sb << "Lod<$T0>($0";
+ for (int i = 0; i < coordCount; ++i)
+ {
+ sb << ", ($2)";
+ if (vecCount > 1)
{
- sb << "__target_intrinsic(cuda, \"texCubemap";
- if (isArray)
- {
- sb << "Layered";
- }
- sb << "Lod<$T0>($0, ($2).x, ($2).y, ($2).z";
- if (isArray)
- {
- sb << ", int(($2).w)";
- }
- sb << ", $3)\")\n";
+ sb << '.' << char(i + 'x');
}
}
- if (isReadOnly)
- sb << "[__readNone]\n";
- sb << "T SampleLevel(" << samplerStateParam;
- sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, ";
- sb << "float level);\n";
-
- if( baseShape != TextureFlavor::Shape::ShapeCube )
+ if (isArray)
{
- sb << "__target_intrinsic(glsl, \"$ctextureLodOffset($p, $2, $3, $4)$z\")\n";
- if (isReadOnly)
- sb << "[__readNone]\n";
- sb << "T SampleLevel(" << samplerStateParam;
- sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, ";
- sb << "float level, ";
- sb << "constexpr int" << kBaseTextureTypes[tt].coordCount << " offset);\n";
+ sb << ", int(($2)." << char(coordCount + 'x') << ")";
}
+ sb << ", $3)\")\n";
}
-
- 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;
- char const* outputType;
- } kGatherExtensionCases[] = {
- { "__generic<T, let N : int>", "vector<T,N>", "vector<T, 4>" },
- { "", "float", "vector<float, 4>" },
- { "", "int" , "vector<int, 4>"},
- { "", "uint", "vector<uint, 4>"},
-
- // 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)
+ else
{
- // 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 << baseName;
- sb << baseShapeName;
- 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 kk : kGatherComponets)
+ sb << "__target_intrinsic(cuda, \"texCubemap";
+ if (isArray)
{
- auto componentIndex = kk.componentIndex;
- auto componentName = kk.componentName;
+ sb << "Layered";
+ }
+ sb << "Lod<$T0>($0, ($2).x, ($2).y, ($2).z";
+ if (isArray)
+ {
+ sb << ", int(($2).w)";
+ }
+ sb << ", $3)\")\n";
+ }
+ }
+ if (isReadOnly)
+ sb << "[__readNone]\n";
+ sb << "T SampleLevel(" << samplerStateParam;
+ sb << "float" << base.coordCount + isArray << " location, ";
+ sb << "float level);\n";
- auto outputType = cc.outputType;
+ if( baseShape != TextureFlavor::Shape::ShapeCube )
+ {
+ sb << "__target_intrinsic(glsl, \"$ctextureLodOffset($p, $2, $3, $4)$z\")\n";
+ if (isReadOnly)
+ sb << "[__readNone]\n";
+ sb << "T SampleLevel(" << samplerStateParam;
+ sb << "float" << base.coordCount + isArray << " location, ";
+ sb << "float level, ";
+ sb << "constexpr int" << base.coordCount << " offset);\n";
+ }
+ }
- EMIT_LINE_DIRECTIVE();
+ sb << "\n};\n";
- sb << "__target_intrinsic(glsl, \"textureGather($p, $2, " << componentIndex << ")\")\n";
- if (kBaseTextureTypes[tt].coordCount == 2)
- {
- // Gather only works on 2D in CUDA
- // "It is based on the base type of DataType except when readMode is equal to cudaReadModeNormalizedFloat (see Texture Reference API), in which case it is always float4."
- sb << "__target_intrinsic(cuda, \"tex2Dgather<$T0>($0, ($2).x, ($2).y, " << componentIndex << ")\")\n";
- }
- if (isReadOnly)
- sb << "[__readNone]\n";
- sb << outputType << " Gather" << componentName << "(" << samplerStateParam;
- sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location);\n";
-
- if (isReadOnly)
- sb << "[__readNone]\n";
- EMIT_LINE_DIRECTIVE();
- sb << "__target_intrinsic(glsl, \"textureGatherOffset($p, $2, $3, " << componentIndex << ")\")\n";
- sb << outputType << " Gather" << componentName << "(" << samplerStateParam;
- sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, ";
- sb << "constexpr int" << kBaseTextureTypes[tt].coordCount << " offset);\n";
-
- if (isReadOnly)
- sb << "[__readNone]\n";
- EMIT_LINE_DIRECTIVE();
- sb << outputType << " Gather" << componentName << "(" << samplerStateParam;
- sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, ";
- sb << "constexpr int" << kBaseTextureTypes[tt].coordCount << " offset, ";
- sb << "out uint status);\n";
-
- if (isReadOnly)
- sb << "[__readNone]\n";
- EMIT_LINE_DIRECTIVE();
- sb << "__target_intrinsic(glsl, \"textureGatherOffsets($p, $2, int" << kBaseTextureTypes[tt].coordCount << "[]($3, $4, $5, $6), " << componentIndex << ")\")\n";
- sb << outputType << " Gather" << componentName << "(" << samplerStateParam;
- sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " 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";
-
- if (isReadOnly)
- sb << "[__readNone]\n";
- EMIT_LINE_DIRECTIVE();
- sb << outputType << " Gather" << componentName << "(" << samplerStateParam;
- sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " 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";
- }
+ // `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;
+ char const* outputType;
+ } kGatherExtensionCases[] = {
+ { "__generic<T, let N : int>", "vector<T,N>", "vector<T, 4>" },
+ { "", "float", "vector<float, 4>" },
+ { "", "int" , "vector<int, 4>"},
+ { "", "uint", "vector<uint, 4>"},
+
+ // 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 << accessInfo.name;
+ sb << baseName;
+ sb << baseShapeName;
+ 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 kk : kGatherComponets)
+ {
+ auto componentIndex = kk.componentIndex;
+ auto componentName = kk.componentName;
+
+ auto outputType = cc.outputType;
- EMIT_LINE_DIRECTIVE();
- sb << "\n}\n";
+ EMIT_LINE_DIRECTIVE();
+
+ sb << "__target_intrinsic(glsl, \"textureGather($p, $2, " << componentIndex << ")\")\n";
+ if (base.coordCount == 2)
+ {
+ // Gather only works on 2D in CUDA
+ // "It is based on the base type of DataType except when readMode is equal to cudaReadModeNormalizedFloat (see Texture Reference API), in which case it is always float4."
+ sb << "__target_intrinsic(cuda, \"tex2Dgather<$T0>($0, ($2).x, ($2).y, " << componentIndex << ")\")\n";
}
+ if (isReadOnly)
+ sb << "[__readNone]\n";
+ sb << outputType << " Gather" << componentName << "(" << samplerStateParam;
+ sb << "float" << base.coordCount + isArray << " location);\n";
+
+ if (isReadOnly)
+ sb << "[__readNone]\n";
+ EMIT_LINE_DIRECTIVE();
+ sb << "__target_intrinsic(glsl, \"textureGatherOffset($p, $2, $3, " << componentIndex << ")\")\n";
+ sb << outputType << " Gather" << componentName << "(" << samplerStateParam;
+ sb << "float" << base.coordCount + isArray << " location, ";
+ sb << "constexpr int" << base.coordCount << " offset);\n";
+
+ if (isReadOnly)
+ sb << "[__readNone]\n";
+ EMIT_LINE_DIRECTIVE();
+ sb << outputType << " Gather" << componentName << "(" << samplerStateParam;
+ sb << "float" << base.coordCount + isArray << " location, ";
+ sb << "constexpr int" << base.coordCount << " offset, ";
+ sb << "out uint status);\n";
+
+ if (isReadOnly)
+ sb << "[__readNone]\n";
+ EMIT_LINE_DIRECTIVE();
+ sb << "__target_intrinsic(glsl, \"textureGatherOffsets($p, $2, int" << base.coordCount << "[]($3, $4, $5, $6), " << componentIndex << ")\")\n";
+ sb << outputType << " Gather" << componentName << "(" << samplerStateParam;
+ sb << "float" << base.coordCount + isArray << " location, ";
+ sb << "int" << base.coordCount << " offset1, ";
+ sb << "int" << base.coordCount << " offset2, ";
+ sb << "int" << base.coordCount << " offset3, ";
+ sb << "int" << base.coordCount << " offset4);\n";
+
+ if (isReadOnly)
+ sb << "[__readNone]\n";
+ EMIT_LINE_DIRECTIVE();
+ sb << outputType << " Gather" << componentName << "(" << samplerStateParam;
+ sb << "float" << base.coordCount + isArray << " location, ";
+ sb << "int" << base.coordCount << " offset1, ";
+ sb << "int" << base.coordCount << " offset2, ";
+ sb << "int" << base.coordCount << " offset3, ";
+ sb << "int" << base.coordCount << " offset4, ";
+ sb << "out uint status);\n";
}
+
+ EMIT_LINE_DIRECTIVE();
+ sb << "\n}\n";
}
- }
+ } // TextureTypeInfo::emitTypeDecl
+}; // struct TextureTypeInfo
+
+for(auto& prefixInfo : kTexturePrefixes)
+for(auto& shapeInfo : kBaseTextureShapes)
+for(int isArray = 0; isArray < 2; ++isArray)
+for(int isMultisample = 0; isMultisample < 2; ++isMultisample)
+for(auto& accessInfo : kBaseTextureAccessLevels)
+{
+ TextureTypeInfo info(prefixInfo, shapeInfo, isArray, isMultisample, accessInfo, sb, path);
+ info.emitTypeDecl();
}
}}}}