diff options
| author | Ellie Hermaszewska <ellieh@nvidia.com> | 2023-09-05 23:26:59 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-09-05 23:26:59 +0800 |
| commit | 2c2294d3310b24fd73cd41ec51338a736f3a2886 (patch) | |
| tree | 0e02393fa772e7741eb38079a79f5cacaa1ba7b0 /source/slang/core.meta.slang | |
| parent | 641f7bdc4ea4f75385c30d833cce4619a411ec67 (diff) | |
SPIR-V image operations (#3163)
* Add __truncate and __sampledType for spirv_asm
Allows some texture tests to start passing
* add __isVector
Currently unused
* Add 1-vector legalization pass (WIP)
* Add capabilities for image types
* neaten instruction dumping
* add 1-vector test
* Add a couple of cases to vec1 legalization
* Remove texture tests from expected failures
* comment
* regenerate vs projects
* Remove redundant define form synchapi emulation
* refactoring image methods
* All sample functions refactored
* Remove incorrect glsl intrinsics
Partially addresses https://github.com/shader-slang/slang/issues/3174
* __subscript image ops via writing funcs
* Extract texture struct writing from core.meta.slang
* Abstract out cuda intrinsic
* Remvoe erroneous call to opDecorateIndex
* spirv asm IR utils
* Correct position of loads for SPIR-V asm inst operands
* Raise constructors to global scope during spir-v legalization
* Correct snippet output
* Implement most texture sampling ops for SPIR-V
* Legalize 1-vectors for glsl too
* Make SPIR-V inst operands non-hoistable
* Better 1-vector legalization
* Put textures in ptrs for spirv
* insert missing break
* Add vec1 legalization test
* Add some missing pieces to slang-ir-insts
* Greatly neaten vec1 legalization
* a
* Neaten vec1 legalization
* Add image read and write intrinsics for spir-v
* Squash warnings
* regenerate vs projects
* Drop redundant guards
* Drop 5 tests from expected failure list
* Inst numbering changes to cross compile tests
* vec1 legalization tests only on vk
* Correct location of asm op emit
* Inline constant in spirv-asm
* Correct signedness for lane in wave intrinsics
* Extract element from float1 for cuda
* squash warnings
* Neaten spirv-emit
* dedupe more capabilities
* warnings
* neaten assert
* comments
* comments
Diffstat (limited to 'source/slang/core.meta.slang')
| -rw-r--r-- | source/slang/core.meta.slang | 1061 |
1 files changed, 11 insertions, 1050 deletions
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang index 96e6d284a..956a5b29a 100644 --- a/source/slang/core.meta.slang +++ b/source/slang/core.meta.slang @@ -1065,8 +1065,6 @@ __generic<T> __extension vector<T, 4> ${{{{ -static const char* kComponentNames[]{ "x", "y", "z", "w" }; - // The above extensions are generic in the *type* of the vector, // but explicit in the *size*. We will now declare an extension // for each builtin type that is generic in the size. @@ -1256,1054 +1254,6 @@ struct SamplerComparisonState ${{{{ -static const struct BaseTextureShapeInfo { - char const* shapeName; - TextureFlavor::Shape baseShape; - int coordCount; -} kBaseTextureShapes[] = { - { "1D", TextureFlavor::Shape::Shape1D, 1 }, - { "2D", TextureFlavor::Shape::Shape2D, 2 }, - { "3D", TextureFlavor::Shape::Shape3D, 3 }, - { "Cube", TextureFlavor::Shape::ShapeCube,3 }, -}; - -static const struct BaseTextureAccessInfo { - char const* name; - SlangResourceAccess access; -} kBaseTextureAccessLevels[] = { - { "", SLANG_RESOURCE_ACCESS_READ }, - { "RW", SLANG_RESOURCE_ACCESS_READ_WRITE }, - { "RasterizerOrdered", SLANG_RESOURCE_ACCESS_RASTER_ORDERED }, -}; - -static const struct TextureTypePrefixInfo -{ - char const* name; - bool combined; -} kTexturePrefixes[] = -{ - { "Texture", false }, - { "Sampler", true }, -}; - -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; - - 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) 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 - sb << "__generic<T = float4"; - // Multi-sample rw texture types have an optional sampleCount parameter. - if (isMultisample) - sb << ", let sampleCount : int = 0"; - sb << ">"; - - if(prefixInfo.combined) - { - sb << "__magic_type(TextureSamplerType," << int(flavor) << ")\n"; - sb << "__intrinsic_type(" << (kIROp_TextureSamplerType + (int(flavor) << kIROpMeta_OtherShift)) << ")\n"; - } - else - { - sb << "__magic_type(TextureType," << 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 << "__target_intrinsic(glsl, \"textureQueryLod($p, $2).x\")"; - sb << "float CalculateLevelOfDetail(" << samplerStateParam; - sb << "float" << base.coordCount << " location);\n"; - - sb << "__target_intrinsic(glsl, \"textureQueryLod($p, $2).y\")"; - 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) - { - { - sb << "__glsl_version(450)\n"; - sb << "__glsl_extension(GL_EXT_samplerless_texture_functions)"; - sb << "__target_intrinsic(glsl, \"("; - - int aa = 1; - String lodStr = ", 0"; - if (includeMipInfo) - { - int mipLevelArg = aa++; - lodStr = ", int($"; - lodStr.append(mipLevelArg); - lodStr.append(")"); - } - - String opStr = " = textureSize($0" + lodStr; - switch( access ) - { - case SLANG_RESOURCE_ACCESS_READ_WRITE: - case SLANG_RESOURCE_ACCESS_RASTER_ORDERED: - opStr = " = imageSize($0"; - break; - - default: - break; - } - - - 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(isArray) - { - sb << ", ($" << aa++ << opStr << ")." << kComponentNames[cc] << ")"; - } - - if(isMultisample) - { - sb << ", ($" << aa++ << " = textureSamples($0))"; - } - - if (includeMipInfo) - { - 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"; - } - - // `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"; - - } - - // CUDA - if (isMultisample) - { - } - else - { - if (access == SLANG_RESOURCE_ACCESS_READ_WRITE) - { - const int coordCount = base.coordCount; - const int vecCount = coordCount + int(isArray); - - 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"; - } - } - } - - if (isReadOnly) - sb << "[__readNone]\n"; - sb << "T Load("; - sb << "int" << loadCoordCount << " location"; - if(isMultisample) - { - sb << ", int sampleIndex"; - } - sb << ");\n"; - - - // GLSL - glslFuncName = (access == SLANG_RESOURCE_ACCESS_READ) ? "texelFetchOffset" : "imageLoad"; - 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]; - sb << ", $2)$z\")\n"; - } - else - { - sb << "$1, 0, $2)$z\")\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 << ");\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; - - 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 ) - { - 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"; - } - - // CUDA - { - if (access == SLANG_RESOURCE_ACCESS_READ_WRITE) - { - const int coordCount = base.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"; - } - 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)\")\n"; - } - } - } - - // Output that has get - if (isReadOnly) - sb << "[__readNone]\n"; - sb << " get;\n"; - - // !!!!!!!!!!!!!!!!!!!! set !!!!!!!!!!!!!!!!!!!!!!! - - if (!(access == SLANG_RESOURCE_ACCESS_NONE || access == SLANG_RESOURCE_ACCESS_READ)) - { - // GLSL - sb << "__target_intrinsic(glsl, \"imageStore($0, " << ivecN << "($1), $V2)\")\n"; - - // CUDA - { - const int coordCount = base.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 << "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"; - } - } - - sb << ", SLANG_CUDA_BOUNDARY_MODE)\")\n"; - } - - // Set - sb << " [nonmutating] set;\n"; - } - - // !!!!!!!!!!!!!!!!!! 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 << "}\n"; - } - - if( !isMultisample ) - { - // `Sample()` - - sb << "__target_intrinsic(glsl, \"$ctexture($p, $2)$z\")\n"; - - // 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 << "<$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"; - } - } - - 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)$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 (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"; - - 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"; - - // `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"; - - 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, \"textureLod($p, vec" << arrCoordCount + 1 << "($2, $3), 0)\")"; - 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; - - sb << "__target_intrinsic(glsl, \"$ctextureLod($p, "; - - sb << "vec" << extCoordCount << "($2,"; - for (int ii = arrCoordCount; ii < extCoordCount - 1; ++ii) - { - sb << " 0.0,"; - } - sb << "$3)"; - - 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. - sb << "__target_intrinsic(glsl, \"textureOffset($p, vec" << arrCoordCount + 1 << "($2, $3), $4)\")"; - 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"; - - sb << "__target_intrinsic(glsl, \"textureLodOffset($p, vec" << arrCoordCount + 1 << "($2, $3), 0, $4)\")"; - 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"; - } - - // 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` - - sb << "__target_intrinsic(glsl, \"$ctextureLod($p, $2, $3)$z\")\n"; - - // SPIR-V - { - // TODO: - // Need to: - // - Construct sampled image type OpTypeSampledImage of image type - // - Construct OpSampledImage from image and sampler - // - Call OpImageSampleExplicitLod - // test ./tests/compute/texture-simpler.slang - } - - // 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 - { - 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"; - } - } - if (isReadOnly) - sb << "[__readNone]\n"; - sb << "T SampleLevel(" << samplerStateParam; - sb << "float" << base.coordCount + isArray << " location, "; - sb << "float level);\n"; - - 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"; - } - } - - 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) - { - // 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" }, - }; - enum Cmp - { NotCmp, - Cmp - }; - - for(auto cmp : {NotCmp, Cmp}) - for(auto kk : kGatherComponets) - { - auto samplerOrComparisonSampler = cmp == Cmp ? "SamplerComparisonState s, " : samplerStateParam; - - auto componentIndex = kk.componentIndex; - auto componentName = kk.componentName; - - auto outputType = cc.outputType; - - const auto cmpName = cmp == Cmp ? "Cmp" : ""; - const auto cmpValueParam = cmp == Cmp ? "float compareValue, " : ""; - const auto cmpValueParamEnd = cmp == Cmp ? ", float compareValue" : ""; - const auto supportsGLSL = componentIndex == 0 || cmp == NotCmp; - - EMIT_LINE_DIRECTIVE(); - - if(supportsGLSL) - { - if(cmp == Cmp) - sb << "__target_intrinsic(glsl, \"textureGather($p, $2, $3)\")\n"; - else - sb << "__target_intrinsic(glsl, \"textureGather($p, $2, " << componentIndex << ")\")\n"; - } - if (base.coordCount == 2 && cmp == NotCmp) - { - // Gather only works on 2D in CUDA without comparison - // "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" << cmpName << componentName << "(" << samplerOrComparisonSampler; - sb << "float" << base.coordCount + isArray << " location" << cmpValueParamEnd << ");\n"; - - if (isReadOnly) - sb << "[__readNone]\n"; - EMIT_LINE_DIRECTIVE(); - if(supportsGLSL) - { - if(cmp == Cmp) - sb << "__target_intrinsic(glsl, \"textureGatherOffset($p, $2, $3, $4)\")\n"; - else - sb << "__target_intrinsic(glsl, \"textureGatherOffset($p, $2, $3, " << componentIndex << ")\")\n"; - } - sb << outputType << " Gather" << cmpName << componentName << "(" << samplerOrComparisonSampler; - sb << "float" << base.coordCount + isArray << " location, "; - sb << cmpValueParam; - sb << "constexpr int" << base.coordCount << " offset);\n"; - - if (isReadOnly) - sb << "[__readNone]\n"; - EMIT_LINE_DIRECTIVE(); - sb << outputType << " Gather" << cmpName << componentName << "(" << samplerOrComparisonSampler; - sb << "float" << base.coordCount + isArray << " location, "; - sb << cmpValueParam; - sb << "constexpr int" << base.coordCount << " offset, "; - sb << "out uint status);\n"; - - if (isReadOnly) - sb << "[__readNone]\n"; - EMIT_LINE_DIRECTIVE(); - if(supportsGLSL) - { - if(cmp == Cmp) - sb << "__target_intrinsic(glsl, \"textureGatherOffsets($p, $2, $3, ivec" << base.coordCount << "[]($4, $5, $6, $7))\")\n"; - else - sb << "__target_intrinsic(glsl, \"textureGatherOffsets($p, $2, ivec" << base.coordCount << "[]($3, $4, $5, $6), " << componentIndex << ")\")\n"; - } - sb << outputType << " Gather" << cmpName << componentName << "(" << samplerOrComparisonSampler; - sb << "float" << base.coordCount + isArray << " location, "; - sb << cmpValueParam; - 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" << cmpName << componentName << "(" << samplerOrComparisonSampler; - sb << "float" << base.coordCount + isArray << " location, "; - sb << cmpValueParam; - 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) @@ -3067,6 +2017,17 @@ bool __isSignedInt() return __isSignedInt_impl(__declVal<T>()); } +__generic<T> +__intrinsic_op($(kIROp_IsVector)) +bool __isVector_impl(T t); + +__generic<T> +[__unsafeForceInlineEarly] +bool __isVector() +{ + return __isVector_impl(__declVal<T>()); +} + // Provide implementations to public generic arithmetic interfaces for builtin types. ${{{{ |
