summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/slang/core.meta.slang4
-rw-r--r--source/slang/glsl.meta.slang460
-rw-r--r--source/slang/slang-ast-modifier.h47
-rw-r--r--source/slang/slang-ast-support-types.h2
-rw-r--r--source/slang/slang-check-decl.cpp32
-rw-r--r--source/slang/slang-check-expr.cpp68
-rw-r--r--source/slang/slang-check-impl.h1
-rw-r--r--source/slang/slang-check-modifier.cpp51
-rw-r--r--source/slang/slang-diagnostic-defs.h4
-rw-r--r--source/slang/slang-emit-c-like.cpp1
-rw-r--r--source/slang/slang-emit-c-like.h1
-rw-r--r--source/slang/slang-emit-glsl.cpp47
-rw-r--r--source/slang/slang-emit-glsl.h2
-rw-r--r--source/slang/slang-emit-spirv.cpp64
-rw-r--r--source/slang/slang-ir-inst-defs.h6
-rw-r--r--source/slang/slang-ir-insts.h4
-rw-r--r--source/slang/slang-ir-spirv-legalize.cpp7
-rw-r--r--source/slang/slang-lower-to-ir.cpp16
-rw-r--r--source/slang/slang-parser.cpp78
19 files changed, 876 insertions, 19 deletions
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang
index 1f4a2908d..583dd5923 100644
--- a/source/slang/core.meta.slang
+++ b/source/slang/core.meta.slang
@@ -2363,6 +2363,10 @@ int __naturalStrideOf()
__intrinsic_op($(kIROp_TreatAsDynamicUniform))
T asDynamicUniform<T>(T v);
+__generic<T>
+__intrinsic_op($(kIROp_GetLegalizedSPIRVGlobalParamAddr))
+Ptr<T> __getLegalizedSPIRVGlobalParamAddr(T val);
+
// Binding Attributes
__attributeTarget(DeclBase)
diff --git a/source/slang/glsl.meta.slang b/source/slang/glsl.meta.slang
index 4101cc626..d7b646810 100644
--- a/source/slang/glsl.meta.slang
+++ b/source/slang/glsl.meta.slang
@@ -2821,6 +2821,466 @@ public vec4 shadow2DProjLod(sampler2DShadow sampler, vec4 coord, float lod)
return textureProjLod(sampler, coord, lod);
}
+//// gimageDim Implementation
+
+public static const int GL_TEXTURE_CUBE_MAP_POSITIVE_X = 0;
+public static const int GL_TEXTURE_CUBE_MAP_NEGATIVE_X = 1;
+public static const int GL_TEXTURE_CUBE_MAP_POSITIVE_Y = 2;
+public static const int GL_TEXTURE_CUBE_MAP_NEGATIVE_Y = 3;
+public static const int GL_TEXTURE_CUBE_MAP_POSITIVE_Z = 4;
+public static const int GL_TEXTURE_CUBE_MAP_NEGATIVE_Z = 5;
+
+__generic<T : __BuiltinType>
+[ForceInline] void typeRequireChecks_image_atomic_tier1()
+{
+ __target_switch
+ {
+ case glsl:
+ {
+ if (__type_equals<T, float>())
+ __requireGLSLExtension("GL_EXT_shader_atomic_float");
+ }
+ case spirv:
+ if (__type_equals<T, float>())
+ {
+ spirv_asm
+ {
+ OpExtension "SPV_EXT_shader_atomic_float_add";
+ OpCapability AtomicFloat32AddEXT
+ };
+ }
+ }
+}
+
+__generic<T : __BuiltinType>
+[ForceInline] void typeRequireChecks_image_atomic_tier2()
+{
+ __target_switch
+ {
+ case glsl:
+ {
+ if (__type_equals<T, float>())
+ __requireGLSLExtension("GL_EXT_shader_atomic_float2");
+ }
+ case spirv:
+ if (__type_equals<T, float>())
+ {
+ spirv_asm
+ {
+ OpExtension "SPV_EXT_shader_atomic_float_min_max";
+ OpCapability AtomicFloat32MinMaxEXT
+ };
+ }
+ }
+}
+
+__generic<T : __BuiltinType>
+[ForceInline] void typeRequireChecks_image_atomic_int64()
+{
+ __target_switch
+ {
+ case spirv:
+ if (__type_equals<T, uint64_t>()
+ || __type_equals<T, int64_t>())
+ {
+ spirv_asm
+ {
+ OpCapability Int64Atomics
+ };
+ }
+ return;
+ }
+}
+
+${{{{
+{
+ struct ImageTypeInfo
+ {
+ const char *prefix;
+ const char *type;
+ bool isInt;
+ const char *SPVTypePrefix;
+ const char *SPVSubTypePrefix;
+ const char *SPVAtomicSuffix;
+ };
+ static const ImageTypeInfo kTypeWithPrefix[] =
+ {
+ { "", "float", false, "F", "F", "EXT"},
+ { "u", "uint", true, "I", "U", ""},
+ { "i", "int", true, "I", "S", ""},
+ { "u64", "uint64_t", true, "I", "U", ""},
+ { "i64", "int64_t", true, "I", "S", ""},
+ };
+ struct ShapeTypeInfo
+ {
+ const char *suffix;
+ int imageSizeIVecDim;
+ int imageCoordIVecIndexerDim;
+ const char *shape;
+ int isArray;
+ int isMS;
+ bool isRect;
+ }
+ static const kShapeType[] =
+ {
+ { "1D", 1, 1,"__Shape1D", 0, 0, 0},
+
+ { "2D", 2, 2, "__Shape2D", 0, 0, 0},
+ { "3D", 3, 3, "__Shape3D", 0, 0, 0},
+ { "Cube", 2, 3, "__ShapeCube", 0, 0, 0},
+ { "2DRect", 2, 2, "__Shape2D", 0, 0, 1},
+ { "1DArray", 2, 2, "__Shape1D", 1, 0, 0},
+
+ { "2DArray", 3, 3, "__Shape2D", 1, 0, 0},
+ { "CubeArray", 3, 3, "__ShapeCube", 1, 0, 0},
+ { "Buffer", 1, 1, "__ShapeBuffer", 0, 0, 0},
+ { "2DMS", 2, 2, "__Shape2D", 0, 1, 0},
+ { "2DMSArray", 3, 3, "__Shape2D", 1, 1, 0},
+ };
+ for (const auto& targetType : kTypeWithPrefix)
+ for (const auto& targetShape : kShapeType)
+ {
+ // gimageDim is the format of image buffers, we
+ // need to resolve a type name from the format:
+ // targetType.prefix is the 'g'
+ // targetShape.suffix is the 'Dim'
+ StringBuilder fullTypeNameBuilder;
+ fullTypeNameBuilder << targetType.prefix << "image" << targetShape.suffix;
+ auto fullTypeName = fullTypeNameBuilder.toString();
+
+ // We need a string to resolve for the imageSize return type
+ // since each shape has a different return which may not be
+ // a vec
+ StringBuilder imageSizeIntOrIVecBuilder;
+ if (targetShape.imageSizeIVecDim == 1)
+ imageSizeIntOrIVecBuilder << "int";
+ else
+ imageSizeIntOrIVecBuilder << "ivec" << targetShape.imageSizeIVecDim;
+ auto imageSizeIntOrIVec = imageSizeIntOrIVecBuilder.toString();
+
+ // Following OpenGL/Vulkan semantics, IMAGE_PARAMS string represents
+ // the changing list of parameters per gimageDim type
+ // https://registry.khronos.org/OpenGL/specs/gl/GLSLangSpec.4.60.pdf
+ StringBuilder IMAGE_PARAMSBuilder;
+ IMAGE_PARAMSBuilder << fullTypeName << " image,";
+ int paramC = targetShape.imageCoordIVecIndexerDim;
+ if (paramC == 1)
+ IMAGE_PARAMSBuilder << "int";
+ else
+ IMAGE_PARAMSBuilder << "ivec" << paramC;
+ IMAGE_PARAMSBuilder << " P";
+ if (targetShape.isMS)
+ {
+ IMAGE_PARAMSBuilder << ", int sample";
+ }
+ auto IMAGE_PARAMS = IMAGE_PARAMSBuilder.toString();
+
+ // SPIR-V requires a 'sample' parameter for all texture
+ // functions. We need to handle a dynamic creation of
+ // 'sample' if 'sample' parameter is not in IMAGE_PARAMS
+ StringBuilder SPV_PREFIX_IMAGE_PARAMSBuilder;
+ StringBuilder SPV_SUFFIX_IMAGE_PARAMSBuilder;
+ StringBuilder SPV_DEFAULT_SAMPLE_VAR_IF_MISSINGBuilder;
+
+ SPV_PREFIX_IMAGE_PARAMSBuilder << "$image $P";
+ SPV_SUFFIX_IMAGE_PARAMSBuilder;
+ if (targetShape.isMS)
+ {
+ SPV_SUFFIX_IMAGE_PARAMSBuilder << " Sample $sample";
+ }
+ else
+ {
+ SPV_DEFAULT_SAMPLE_VAR_IF_MISSINGBuilder << "let sample = 0;";
+ }
+
+ auto SPV_PREFIX_IMAGE_PARAMS = SPV_PREFIX_IMAGE_PARAMSBuilder.toString();
+ auto SPV_SUFFIX_IMAGE_PARAMS = SPV_SUFFIX_IMAGE_PARAMSBuilder.toString();
+ auto SPV_DEFAULT_SAMPLE_VAR_IF_MISSING = SPV_DEFAULT_SAMPLE_VAR_IF_MISSINGBuilder.toString();
+ }}}}
+
+ __generic<let format:int=0>
+ public typealias $(fullTypeName) = __TextureImpl<
+ $(targetType.type),
+ $(targetShape.shape),
+ $(targetShape.isArray), // isArray
+ $(targetShape.isMS), // isMS
+ 0, // sampleCount
+ 1, // access
+ 0, // isShadow
+ 0, // isCombined
+ format
+ >;
+
+${{{{
+ if(targetShape.isRect)
+ continue;
+}}}}
+
+ // readonly writeonly in GLSL means an object only allows information queries.
+ [require(spirv)]
+ [require(glsl)]
+ [__readNone]
+ [ForceInline] public $(imageSizeIntOrIVec) imageSize(readonly writeonly $(fullTypeName) image)
+ {
+ __target_switch
+ {
+ case glsl: __intrinsic_asm "imageSize($*0)";
+ case spirv:
+ return spirv_asm
+ {
+ OpCapability ImageQuery;
+ result:$$$(imageSizeIntOrIVec) = OpImageQuerySize $image;
+ };
+ }
+ }
+ [require(spirv)]
+ [require(glsl)]
+ [__NoSideEffect]
+ [ForceInline] public $(targetType.prefix)vec4 imageLoad(readonly $(IMAGE_PARAMS))
+ {
+ __target_switch
+ {
+ case glsl: __intrinsic_asm "imageLoad($*0)";
+ case spirv:
+ {
+ $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING)
+ return spirv_asm
+ {
+ result:$$$(targetType.prefix)vec4 = OpImageRead $(SPV_PREFIX_IMAGE_PARAMS) $(SPV_SUFFIX_IMAGE_PARAMS);
+ };
+ }
+ }
+ }
+ [require(spirv)]
+ [require(glsl)]
+ [ForceInline] public void imageStore(writeonly $(IMAGE_PARAMS), $(targetType.prefix)vec4 data)
+ {
+ __target_switch
+ {
+ case glsl: __intrinsic_asm "imageStore($*0)";
+ case spirv:
+ {
+ $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING)
+ return spirv_asm
+ {
+ OpImageWrite $(SPV_PREFIX_IMAGE_PARAMS) $data $(SPV_SUFFIX_IMAGE_PARAMS);
+ };
+ }
+ }
+ }
+
+${{{{
+ if (targetShape.isMS)
+ {
+}}}}
+ // readonly writeonly in GLSL means an object only allows information queries.
+ [require(spirv)]
+ [require(glsl)]
+ [__readNone]
+ [ForceInline] public int imageSamples(readonly writeonly $(fullTypeName) image)
+ {
+ __target_switch
+ {
+ case glsl: __intrinsic_asm "imageSamples($*0)";
+ case spirv:
+ return spirv_asm
+ {
+ OpCapability ImageQuery;
+ result:$$int = OpImageQuerySamples $image;
+ };
+ }
+ }
+${{{{
+ }
+}}}}
+ [require(spirv)]
+ [require(glsl)]
+ [ForceInline] public $(targetType.type) imageAtomicAdd($(IMAGE_PARAMS), $(targetType.type) data)
+ {
+ typeRequireChecks_image_atomic_tier1<$(targetType.type)>();
+ __target_switch
+ {
+ case glsl: __intrinsic_asm "imageAtomicAdd($*0)";
+ case spirv:
+ {
+ let imageP = __getLegalizedSPIRVGlobalParamAddr(image);
+ typeRequireChecks_image_atomic_int64<$(targetType.type)>();
+ $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING)
+ return spirv_asm
+ {
+ OpCapability ImageQuery;
+ %ptrType = OpTypePointer Image $$$(targetType.type);
+ %ptr:%ptrType = OpImageTexelPointer $imageP $P $sample;
+ result:$$$(targetType.type) = OpAtomic$(targetType.SPVTypePrefix)Add$(targetType.SPVAtomicSuffix) %ptr Device None $data
+ };
+ }
+ }
+ }
+ [require(spirv)]
+ [require(glsl)]
+ [ForceInline] public $(targetType.type) imageAtomicExchange($(IMAGE_PARAMS), $(targetType.type) data)
+ {
+ typeRequireChecks_image_atomic_tier1<$(targetType.type)>();
+ __target_switch
+ {
+ case glsl: __intrinsic_asm "imageAtomicExchange($*0)";
+ case spirv:
+ {
+ let imageP = __getLegalizedSPIRVGlobalParamAddr(image);
+ typeRequireChecks_image_atomic_int64<$(targetType.type)>();
+ $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING)
+ return spirv_asm
+ {
+ OpCapability ImageQuery;
+ %ptrType = OpTypePointer Image $$$(targetType.type);
+ %ptr:%ptrType = OpImageTexelPointer $imageP $P $sample;
+ result:$$$(targetType.type) = OpAtomicExchange %ptr Device ImageMemory $data
+ };
+ }
+ }
+ }
+ [require(spirv)]
+ [require(glsl)]
+ [ForceInline] public $(targetType.type) imageAtomicMin($(IMAGE_PARAMS), $(targetType.type) data)
+ {
+ typeRequireChecks_image_atomic_tier2<$(targetType.type)>();
+ __target_switch
+ {
+ case glsl: __intrinsic_asm "imageAtomicMin($*0)";
+ case spirv:
+ {
+ let imageP = __getLegalizedSPIRVGlobalParamAddr(image);
+ typeRequireChecks_image_atomic_int64<$(targetType.type)>();
+ $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING)
+ return spirv_asm
+ {
+ OpCapability ImageQuery;
+ %ptrType = OpTypePointer Image $$$(targetType.type);
+ %ptr:%ptrType = OpImageTexelPointer $imageP $P $sample;
+ result:$$$(targetType.type) = OpAtomic$(targetType.SPVSubTypePrefix)Min$(targetType.SPVAtomicSuffix) %ptr Device ImageMemory $data
+ };
+ }
+ }
+ }
+ [require(spirv)]
+ [require(glsl)]
+ [ForceInline] public $(targetType.type) imageAtomicMax($(IMAGE_PARAMS), $(targetType.type) data)
+ {
+ typeRequireChecks_image_atomic_tier2<$(targetType.type)>();
+ __target_switch
+ {
+ case glsl: __intrinsic_asm "imageAtomicMax($*0)";
+ case spirv:
+ {
+ let imageP = __getLegalizedSPIRVGlobalParamAddr(image);
+ typeRequireChecks_image_atomic_int64<$(targetType.type)>();
+ $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING)
+ return spirv_asm
+ {
+ OpCapability ImageQuery;
+ %ptrType = OpTypePointer Image $$$(targetType.type);
+ %ptr:%ptrType = OpImageTexelPointer $imageP $P $sample;
+ result:$$$(targetType.type) = OpAtomic$(targetType.SPVSubTypePrefix)Max$(targetType.SPVAtomicSuffix) %ptr Device ImageMemory $data
+ };
+ }
+ }
+ }
+${{{{
+ if (!targetType.isInt)
+ continue;
+}}}}
+ [require(spirv)]
+ [require(glsl)]
+ [ForceInline] public $(targetType.type) imageAtomicAnd($(IMAGE_PARAMS), $(targetType.type) data)
+ {
+ __target_switch
+ {
+ case glsl: __intrinsic_asm "imageAtomicAnd($*0)";
+ case spirv:
+ {
+ let imageP = __getLegalizedSPIRVGlobalParamAddr(image);
+ typeRequireChecks_image_atomic_int64<$(targetType.type)>();
+ $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING)
+ return spirv_asm
+ {
+ OpCapability ImageQuery;
+ %ptrType = OpTypePointer Image $$$(targetType.type);
+ %ptr:%ptrType = OpImageTexelPointer $imageP $P $sample;
+ result:$$$(targetType.type) = OpAtomicAnd %ptr Device ImageMemory $data
+ };
+ }
+ }
+ }
+ [require(spirv)]
+ [require(glsl)]
+ [ForceInline] public $(targetType.type) imageAtomicOr($(IMAGE_PARAMS), $(targetType.type) data)
+ {
+ __target_switch
+ {
+ case glsl: __intrinsic_asm "imageAtomicOr($*0)";
+ case spirv:
+ {
+ let imageP = __getLegalizedSPIRVGlobalParamAddr(image);
+ typeRequireChecks_image_atomic_int64<$(targetType.type)>();
+ $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING)
+ return spirv_asm
+ {
+ OpCapability ImageQuery;
+ %ptrType = OpTypePointer Image $$$(targetType.type);
+ %ptr:%ptrType = OpImageTexelPointer $imageP $P $sample;
+ result:$$$(targetType.type) = OpAtomicOr %ptr Device ImageMemory $data
+ };
+ }
+ }
+ }
+ [require(spirv)]
+ [require(glsl)]
+ [ForceInline] public $(targetType.type) imageAtomicXor($(IMAGE_PARAMS), $(targetType.type) data)
+ {
+ __target_switch
+ {
+ case glsl: __intrinsic_asm "imageAtomicXor($*0)";
+ case spirv:
+ {
+ let imageP = __getLegalizedSPIRVGlobalParamAddr(image);
+ typeRequireChecks_image_atomic_int64<$(targetType.type)>();
+ $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING)
+ return spirv_asm
+ {
+ OpCapability ImageQuery;
+ %ptrType = OpTypePointer Image $$$(targetType.type);
+ %ptr:%ptrType = OpImageTexelPointer $imageP $P $sample;
+ result:$$$(targetType.type) = OpAtomicXor %ptr Device ImageMemory $data
+ };
+ }
+ }
+ }
+ [require(spirv)]
+ [require(glsl)]
+ [ForceInline] public $(targetType.type) imageAtomicCompSwap($(IMAGE_PARAMS), $(targetType.type) compare, $(targetType.type) data)
+ {
+ __target_switch
+ {
+ case glsl: __intrinsic_asm "imageAtomicCompSwap($*0)";
+ case spirv:
+ {
+ let imageP = __getLegalizedSPIRVGlobalParamAddr(image);
+ typeRequireChecks_image_atomic_int64<$(targetType.type)>();
+ $(SPV_DEFAULT_SAMPLE_VAR_IF_MISSING)
+ return spirv_asm
+ {
+ OpCapability ImageQuery;
+ %ptrType = OpTypePointer Image $$$(targetType.type);
+ %ptr:%ptrType = OpImageTexelPointer $imageP $P $sample;
+ result:$$$(targetType.type) = OpAtomicCompareExchange %ptr Device ImageMemory ImageMemory $data $compare
+ };
+ }
+ }
+ }
+${{{{
+ }
+}
+}}}}
//// RayTracing
diff --git a/source/slang/slang-ast-modifier.h b/source/slang/slang-ast-modifier.h
index 87057b694..4ccca36ea 100644
--- a/source/slang/slang-ast-modifier.h
+++ b/source/slang/slang-ast-modifier.h
@@ -29,7 +29,6 @@ class PrefixModifier : public Modifier { SLANG_AST_CLASS(PrefixModifier)};
class PostfixModifier : public Modifier { SLANG_AST_CLASS(PostfixModifier)};
class ExportedModifier : public Modifier { SLANG_AST_CLASS(ExportedModifier)};
class ConstExprModifier : public Modifier { SLANG_AST_CLASS(ConstExprModifier)};
-class GloballyCoherentModifier : public Modifier { SLANG_AST_CLASS(GloballyCoherentModifier)};
class ExternCppModifier : public Modifier { SLANG_AST_CLASS(ExternCppModifier)};
class GLSLPrecisionModifier : public Modifier { SLANG_AST_CLASS(GLSLPrecisionModifier)};
class GLSLModuleModifier : public Modifier {SLANG_AST_CLASS(GLSLModuleModifier)};
@@ -1493,6 +1492,11 @@ class NoDiffModifier : public TypeModifier
SLANG_AST_CLASS(NoDiffModifier)
};
+class GloballyCoherentModifier : public SimpleModifier
+{
+ SLANG_AST_CLASS(GloballyCoherentModifier)
+};
+
// Some GLSL-specific modifiers
class GLSLBufferModifier : public WrappingTypeModifier
{
@@ -1509,6 +1513,16 @@ class GLSLReadOnlyModifier : public SimpleModifier
SLANG_AST_CLASS(GLSLReadOnlyModifier)
};
+class GLSLVolatileModifier : public SimpleModifier
+{
+ SLANG_AST_CLASS(GLSLVolatileModifier)
+};
+
+class GLSLRestrictModifier : public SimpleModifier
+{
+ SLANG_AST_CLASS(GLSLRestrictModifier)
+};
+
class GLSLPatchModifier : public SimpleModifier
{
SLANG_AST_CLASS(GLSLPatchModifier)
@@ -1531,4 +1545,35 @@ class DynamicUniformModifier : public Modifier
SLANG_AST_CLASS(DynamicUniformModifier)
};
+class MemoryQualifierCollectionModifier : public Modifier
+{
+ SLANG_AST_CLASS(MemoryQualifierCollectionModifier);
+
+ List<Modifier*> memoryModifiers;
+
+ uint32_t memoryQualifiers = 0;
+
+public:
+ struct Flags
+ {
+ enum MemoryQualifiersBit
+ {
+ kNone = 0b0,
+ kCoherent = 0b1,
+ kReadOnly = 0b10,
+ kWriteOnly = 0b100,
+ kVolatile = 0b1000,
+ kRestrict = 0b10000,
+ };
+ };
+
+ void addQualifier(Modifier* mod, Flags::MemoryQualifiersBit type)
+ {
+ memoryModifiers.add(mod);
+ memoryQualifiers |= type;
+ }
+ uint32_t getMemoryQualifierBit() { return memoryQualifiers; }
+ List<Modifier*> getModifiers() { return memoryModifiers; }
+};
+
} // namespace Slang
diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h
index 4ad5fc432..e4e3be384 100644
--- a/source/slang/slang-ast-support-types.h
+++ b/source/slang/slang-ast-support-types.h
@@ -549,6 +549,8 @@ namespace Slang
Type* type = nullptr;
bool isLeftValue;
+ bool hasReadOnlyOnTarget = false;
+ bool isWriteOnly = false;
QualType()
: isLeftValue(false)
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp
index 386a0bba1..c844fb82a 100644
--- a/source/slang/slang-check-decl.cpp
+++ b/source/slang/slang-check-decl.cpp
@@ -944,7 +944,27 @@ namespace Slang
}
}
+ // Ensures child of struct is set read-only or not
+ bool isWriteOnly = false;
+ {
+ for (auto mod : varDeclRef.getDecl()->modifiers)
+ {
+ if (as<GLSLReadOnlyModifier>(mod))
+ {
+ isLValue = false;
+ qualType.hasReadOnlyOnTarget = true;
+ if (isLValue == false && isWriteOnly) break;
+ }
+ if (as<GLSLWriteOnlyModifier>(mod))
+ {
+ isWriteOnly = true;
+ if (isLValue == false && isWriteOnly) break;
+ }
+ }
+ }
+
qualType.isLeftValue = isLValue;
+ qualType.isWriteOnly = isWriteOnly;
return qualType;
}
else if( auto propertyDeclRef = declRef.as<PropertyDecl>() )
@@ -1846,6 +1866,8 @@ namespace Slang
//
initExpr = subVisitor.CheckTerm(initExpr);
+ if (initExpr->type.isWriteOnly)
+ getSink()->diagnose(initExpr, Diagnostics::readingFromWriteOnly);
initExpr = coerce(CoercionSite::Initializer, varDecl->type.Ptr(), initExpr);
varDecl->initExpr = initExpr;
@@ -7023,6 +7045,16 @@ namespace Slang
}
}
}
+
+ // Only texture types are allowed to have memory qualifiers on parameters
+ if(!paramDecl->type || paramDecl->type->astNodeType != ASTNodeType::TextureType)
+ {
+ auto memoryQualifierCollection = paramDecl->findModifier<MemoryQualifierCollectionModifier>();
+ if(!memoryQualifierCollection)
+ return;
+ for(auto mod : memoryQualifierCollection->getModifiers())
+ getSink()->diagnose(paramDecl, Diagnostics::memoryQualifierNotAllowedOnANonImageTypeParameter, mod);
+ }
}
// This checks that the declaration is marked as "out" and changes the hlsl
diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp
index dc7a2d35b..a31e17123 100644
--- a/source/slang/slang-check-expr.cpp
+++ b/source/slang/slang-check-expr.cpp
@@ -412,6 +412,11 @@ namespace Slang
expr->declRef = declRef;
expr->memberOperatorLoc = _getMemberOpLoc(originalExpr);
+ // If any member declares the following value is a
+ // write only, we must declare the parent as a write
+ // only to avoid modifying the child
+ expr->type.isWriteOnly = baseExpr->type.isWriteOnly || expr->type.isWriteOnly;
+
// When referring to a member through an expression,
// the result is only an l-value if both the base
// expression and the member agree that it should be.
@@ -424,7 +429,7 @@ namespace Slang
// One exception to this is if we're reading the contents
// of a GLSL buffer interface block which isn't marked as
// read_only
- expr->type.isLeftValue = isMutableGLSLBufferBlockVarExpr(baseExpr);
+ expr->type.isLeftValue = isMutableGLSLBufferBlockVarExpr(baseExpr) && (expr->type.hasReadOnlyOnTarget == false);
}
else
{
@@ -2078,6 +2083,9 @@ namespace Slang
Expr* SemanticsVisitor::checkAssignWithCheckedOperands(AssignExpr* expr)
{
+ if (expr->right->type.isWriteOnly)
+ getSink()->diagnose(expr, Diagnostics::readingFromWriteOnly);
+
expr->left = maybeOpenRef(expr->left);
auto type = expr->left->type;
auto right = maybeOpenRef(expr->right);
@@ -2177,6 +2185,44 @@ namespace Slang
return _canLValueCoerceScalarType(a, b);
}
+
+ void SemanticsVisitor::compareMemoryQualifierOfParamToArgument(
+ ParamDecl* paramIn,
+ Expr* argIn)
+ {
+ auto arg = as<VarExpr>(argIn);
+ if (!paramIn || !arg)
+ return;
+
+ auto argDeclRef = arg->declRef;
+ if (!argDeclRef)
+ return;
+ auto argDecl = argDeclRef.getDecl();
+ auto argMemMods = argDecl->findModifier<MemoryQualifierCollectionModifier>();
+ if(!argMemMods)
+ return;
+ uint32_t argQualifiers = argMemMods->getMemoryQualifierBit();
+
+ uint32_t paramQualifiers = 0;
+ auto paramMemMods = paramIn->findModifier<MemoryQualifierCollectionModifier>();
+ if(paramMemMods)
+ paramQualifiers = paramMemMods->getMemoryQualifierBit();
+
+ if(argQualifiers & MemoryQualifierCollectionModifier::Flags::kCoherent
+ && !(paramQualifiers & MemoryQualifierCollectionModifier::Flags::kCoherent))
+ getSink()->diagnose(arg, Diagnostics::argumentHasMoreMemoryQualifiersThanParam, "coherent");
+ if(argQualifiers & MemoryQualifierCollectionModifier::Flags::kReadOnly
+ && !(paramQualifiers & MemoryQualifierCollectionModifier::Flags::kReadOnly))
+ getSink()->diagnose(arg, Diagnostics::argumentHasMoreMemoryQualifiersThanParam, "readonly");
+ if(argQualifiers & MemoryQualifierCollectionModifier::Flags::kWriteOnly
+ && !(paramQualifiers & MemoryQualifierCollectionModifier::Flags::kWriteOnly))
+ getSink()->diagnose(arg, Diagnostics::argumentHasMoreMemoryQualifiersThanParam, "writeonly");
+ if(argQualifiers & MemoryQualifierCollectionModifier::Flags::kVolatile
+ && !(paramQualifiers & MemoryQualifierCollectionModifier::Flags::kVolatile))
+ getSink()->diagnose(arg, Diagnostics::argumentHasMoreMemoryQualifiersThanParam, "volatile");
+ // dropping a `restrict` qualifier from arguments is allowed in GLSL with memory qualifiers
+ }
+
Expr* SemanticsVisitor::CheckInvokeExprWithCheckedOperands(InvokeExpr *expr)
{
auto rs = ResolveInvoke(expr);
@@ -2194,10 +2240,25 @@ namespace Slang
}
}
+ auto funcDeclRefExpr = as<DeclRefExpr>(invoke->functionExpr);
+ FunctionDeclBase* funcDeclBase = nullptr;
+ if (funcDeclRefExpr)
+ funcDeclBase = as<FunctionDeclBase>(funcDeclRefExpr->declRef.getDecl());
+
Index paramCount = funcType->getParamCount();
for (Index pp = 0; pp < paramCount; ++pp)
{
auto paramType = funcType->getParamType(pp);
+ Expr* argExpr = nullptr;
+ ParamDecl* paramDecl = nullptr;
+ if (pp < expr->arguments.getCount())
+ {
+ argExpr = expr->arguments[pp];
+ if(funcDeclBase)
+ paramDecl = funcDeclBase->getParameters()[pp];
+ }
+ compareMemoryQualifierOfParamToArgument(paramDecl, argExpr);
+
if (as<OutTypeBase>(paramType) || as<RefType>(paramType))
{
// `out`, `inout`, and `ref` parameters currently require
@@ -2207,9 +2268,8 @@ namespace Slang
// for an `inout` parameter to be converted in both
// directions.
//
- if( pp < expr->arguments.getCount() )
+ if( argExpr )
{
- auto argExpr = expr->arguments[pp];
if( !argExpr->type.isLeftValue)
{
auto implicitCastExpr = as<ImplicitCastExpr>(argExpr);
@@ -3280,6 +3340,8 @@ namespace Slang
{
auto elementType = QualType(pointerLikeType->getElementType());
elementType.isLeftValue = baseType.isLeftValue;
+ elementType.hasReadOnlyOnTarget = baseType.hasReadOnlyOnTarget;
+ elementType.isWriteOnly = baseType.isWriteOnly;
auto derefExpr = m_astBuilder->create<DerefExpr>();
derefExpr->base = expr;
diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h
index 392d78c5a..278fc3265 100644
--- a/source/slang/slang-check-impl.h
+++ b/source/slang/slang-check-impl.h
@@ -2467,6 +2467,7 @@ namespace Slang
Expr* CheckExpr(Expr* expr);
+ void compareMemoryQualifierOfParamToArgument(ParamDecl* paramIn, Expr* argIn);
Expr* CheckInvokeExprWithCheckedOperands(InvokeExpr *expr);
// Get the type to use when referencing a declaration
QualType GetTypeForDeclRef(DeclRef<Decl> declRef, SourceLoc loc);
diff --git a/source/slang/slang-check-modifier.cpp b/source/slang/slang-check-modifier.cpp
index 0b9688cb0..942afd559 100644
--- a/source/slang/slang-check-modifier.cpp
+++ b/source/slang/slang-check-modifier.cpp
@@ -1010,6 +1010,8 @@ namespace Slang
case ASTNodeType::GLSLBufferModifier:
case ASTNodeType::GLSLWriteOnlyModifier:
case ASTNodeType::GLSLReadOnlyModifier:
+ case ASTNodeType::GLSLVolatileModifier:
+ case ASTNodeType::GLSLRestrictModifier:
case ASTNodeType::GLSLPatchModifier:
case ASTNodeType::RayPayloadAccessSemantic:
case ASTNodeType::RayPayloadReadSemantic:
@@ -1092,16 +1094,26 @@ namespace Slang
case ASTNodeType::RefModifier:
case ASTNodeType::ConstRefModifier:
case ASTNodeType::GLSLBufferModifier:
- case ASTNodeType::GLSLWriteOnlyModifier:
- case ASTNodeType::GLSLReadOnlyModifier:
case ASTNodeType::GLSLPatchModifier:
case ASTNodeType::RayPayloadAccessSemantic:
case ASTNodeType::RayPayloadReadSemantic:
case ASTNodeType::RayPayloadWriteSemantic:
return (as<VarDeclBase>(decl) && isGlobalDecl(decl)) || as<ParamDecl>(decl) || as<GLSLInterfaceBlockDecl>(decl);
+ case ASTNodeType::GLSLWriteOnlyModifier:
+ case ASTNodeType::GLSLReadOnlyModifier:
+ case ASTNodeType::GLSLVolatileModifier:
+ case ASTNodeType::GLSLRestrictModifier:
+ if(isGLSLInput)
+ return (as<VarDeclBase>(decl) && (isGlobalDecl(decl)) || as<ParamDecl>(decl) || as<GLSLInterfaceBlockDecl>(decl))
+ || as<StructDecl>(getParentDecl(decl)) && isGlobalDecl(getParentDecl(decl));
+ return (as<VarDeclBase>(decl) && (isGlobalDecl(decl)) || as<ParamDecl>(decl) || as<GLSLInterfaceBlockDecl>(decl));
+
case ASTNodeType::GloballyCoherentModifier:
case ASTNodeType::HLSLVolatileModifier:
+ if(isGLSLInput)
+ return as<VarDecl>(decl) && (isGlobalDecl(decl) || as<StructDecl>(getParentDecl(decl)) || as<GLSLInterfaceBlockDecl>(decl))
+ || as<VarDeclBase>(decl) && isGlobalDecl(decl) || as<ParamDecl>(decl) || (as<StructDecl>(getParentDecl(decl)) && isGlobalDecl(getParentDecl(decl)));
return as<VarDecl>(decl) && (isGlobalDecl(decl) || as<StructDecl>(getParentDecl(decl)) || as<GLSLInterfaceBlockDecl>(decl));
// Allowed only on parameters, struct fields and global variables.
@@ -1216,6 +1228,40 @@ namespace Slang
}
}
+ MemoryQualifierCollectionModifier::Flags::MemoryQualifiersBit memoryQualifierBit =
+ MemoryQualifierCollectionModifier::Flags::kNone;
+ if(as<GloballyCoherentModifier>(m))
+ memoryQualifierBit = MemoryQualifierCollectionModifier::Flags::kCoherent;
+ else if(as<GLSLReadOnlyModifier>(m))
+ memoryQualifierBit = MemoryQualifierCollectionModifier::Flags::kReadOnly;
+ else if(as<GLSLWriteOnlyModifier>(m))
+ memoryQualifierBit = MemoryQualifierCollectionModifier::Flags::kWriteOnly;
+ else if(as<GLSLVolatileModifier>(m))
+ memoryQualifierBit = MemoryQualifierCollectionModifier::Flags::kVolatile;
+ else if(as<GLSLRestrictModifier>(m))
+ memoryQualifierBit = MemoryQualifierCollectionModifier::Flags::kRestrict;
+ if(memoryQualifierBit != MemoryQualifierCollectionModifier::Flags::kNone)
+ {
+ bool newModifier = false;
+ MemoryQualifierCollectionModifier* memoryQualifiers = syntaxNode->findModifier<MemoryQualifierCollectionModifier>();
+ if(!memoryQualifiers)
+ {
+ newModifier = true;
+ memoryQualifiers = getASTBuilder()->create<MemoryQualifierCollectionModifier>();
+ }
+ memoryQualifiers->addQualifier(m,
+ memoryQualifierBit);
+ if (newModifier)
+ {
+ // insert in modifiers list the memoryQualifierCollection
+ Modifier* mod = m->next;
+ m->next = memoryQualifiers;
+ memoryQualifiers->next = mod;
+ return m;
+ }
+ return m;
+ }
+
if (auto hlslSemantic = as<HLSLSimpleSemantic>(m))
{
if (hlslSemantic->name.getName() == getSession()->getCompletionRequestTokenName())
@@ -1519,6 +1565,7 @@ namespace Slang
if (as<SharedModifiers>(modifier))
ignoreUnallowedModifier = true;
+ // may return a list of modifiers
auto checkedModifier = checkModifier(modifier, syntaxNode, ignoreUnallowedModifier);
if(checkedModifier)
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h
index 757ce94ee..e1c929f7e 100644
--- a/source/slang/slang-diagnostic-defs.h
+++ b/source/slang/slang-diagnostic-defs.h
@@ -298,6 +298,7 @@ DIAGNOSTIC(30035, Error, componentOverloadTypeMismatch, "'$0': type of overloade
DIAGNOSTIC(30041, Error, bitOperationNonIntegral, "bit operation: operand must be integral type.")
DIAGNOSTIC(30043, Error, getStringHashRequiresStringLiteral, "getStringHash parameter can only accept a string literal")
DIAGNOSTIC(30047, Error, argumentExpectedLValue, "argument passed to parameter '$0' must be l-value.")
+DIAGNOSTIC(30048, Error, argumentHasMoreMemoryQualifiersThanParam, "argument passed in to parameter has a memory qualifier the parameter type is missing: '$0'")
DIAGNOSTIC(30049, Note, thisIsImmutableByDefault, "a 'this' parameter is an immutable parameter by default in Slang; apply the `[mutating]` attribute to the function declaration to opt in to a mutable `this`")
DIAGNOSTIC(30050, Error, mutatingMethodOnImmutableValue, "mutating method '$0' cannot be called on an immutable value")
@@ -355,6 +356,8 @@ DIAGNOSTIC(30098, Error, nonStaticMemberFunctionNotAllowedAsDiffOperand, "non-st
DIAGNOSTIC(30099, Error, sizeOfArgumentIsInvalid, "argument to sizeof is invalid")
+DIAGNOSTIC(30101, Error, readingFromWriteOnly, "cannot read from writeonly, check modifiers.")
+
// Include
DIAGNOSTIC(30500, Error, includedFileMissingImplementing, "missing 'implementing' declaration in the included source file '$0'.")
DIAGNOSTIC(30501, Error, includedFileMissingImplementingDoYouMeanImport, "missing 'implementing' declaration in the included source file '$0'. The file declares that it defines module '$1', do you mean 'import' instead?")
@@ -444,6 +447,7 @@ DIAGNOSTIC(31202, Error, duplicateModifier, "modifier '$0' is redundant or confl
DIAGNOSTIC(31203, Error, cannotExportIncompleteType, "cannot export incomplete type '$0'")
DIAGNOSTIC(31204, Error, incompleteTypeCannotBeUsedInBuffer, "incomplete type '$0' cannot be used in a buffer")
DIAGNOSTIC(31205, Error, incompleteTypeCannotBeUsedInUniformParameter, "incomplete type '$0' cannot be used in a uniform parameter")
+DIAGNOSTIC(31206, Error, memoryQualifierNotAllowedOnANonImageTypeParameter, "modifier $0 is not allowed on a non image type parameter.")
// Enums
diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp
index af53b545f..b60e0a4ac 100644
--- a/source/slang/slang-emit-c-like.cpp
+++ b/source/slang/slang-emit-c-like.cpp
@@ -3537,6 +3537,7 @@ void CLikeSourceEmitter::emitStructDeclarationsBlock(IRStructType* structType, b
emitPackOffsetModifier(fieldKey, fieldType, packOffsetDecoration);
}
}
+ emitMemoryQualifiers(fieldKey);
emitType(fieldType, getName(fieldKey));
emitSemantics(fieldKey, allowOffsetLayout);
m_writer->emit(";\n");
diff --git a/source/slang/slang-emit-c-like.h b/source/slang/slang-emit-c-like.h
index 46cdf2145..fa99ae061 100644
--- a/source/slang/slang-emit-c-like.h
+++ b/source/slang/slang-emit-c-like.h
@@ -385,6 +385,7 @@ public:
/// Emit type attributes that should appear after, e.g., a `struct` keyword
void emitPostKeywordTypeAttributes(IRInst* inst) { emitPostKeywordTypeAttributesImpl(inst); }
+ virtual void emitMemoryQualifiers(IRInst* /*varInst*/) {};
void emitInterpolationModifiers(IRInst* varInst, IRType* valueType, IRVarLayout* layout);
void emitMeshShaderModifiers(IRInst* varInst);
virtual void emitPackOffsetModifier(IRInst* /*varInst*/, IRType* /*valueType*/, IRPackOffsetDecoration* /*decoration*/) {};
diff --git a/source/slang/slang-emit-glsl.cpp b/source/slang/slang-emit-glsl.cpp
index 7e5c84533..bbd869eda 100644
--- a/source/slang/slang-emit-glsl.cpp
+++ b/source/slang/slang-emit-glsl.cpp
@@ -114,6 +114,38 @@ void GLSLSourceEmitter::_requireGLSLVersion(int version)
}
}
+void GLSLSourceEmitter::_emitMemoryQualifierDecorations(IRInst* varDecl)
+{
+ for (auto decoration : varDecl->getDecorations())
+ {
+ if (as<IRGloballyCoherentDecoration>(decoration))
+ {
+ m_writer->emit("coherent ");
+ }
+ else if (as<IRGLSLVolatileDecoration>(decoration))
+ {
+ m_writer->emit("volatile ");
+ }
+ else if (as<IRGLSLRestrictDecoration>(decoration))
+ {
+ m_writer->emit("restrict ");
+ }
+ else if (as<IRGLSLReadOnlyDecoration>(decoration))
+ {
+ m_writer->emit("readonly ");
+ }
+ else if (as<IRGLSLWriteOnlyDecoration>(decoration))
+ {
+ m_writer->emit("writeonly ");
+ }
+ }
+}
+
+void GLSLSourceEmitter::emitMemoryQualifiers(IRInst* varDecl)
+{
+ _emitMemoryQualifierDecorations(varDecl);
+}
+
void GLSLSourceEmitter::_emitGLSLStructuredBuffer(IRGlobalParam* varDecl, IRHLSLStructuredBufferTypeBase* structuredBufferType)
{
// Shader storage buffer is an OpenGL 430 feature
@@ -182,10 +214,7 @@ void GLSLSourceEmitter::_emitGLSLStructuredBuffer(IRGlobalParam* varDecl, IRHLSL
HLSLAppendStructuredBufferType - Write
HLSLConsumeStructuredBufferType - TODO (JS): Its possible that this can be readonly, but we currently don't support on GLSL
*/
- if (varDecl->findDecoration<IRGloballyCoherentDecoration>())
- {
- m_writer->emit("coherent ");
- }
+ _emitMemoryQualifierDecorations(varDecl);
if (as<IRHLSLStructuredBufferType>(structuredBufferType))
{
m_writer->emit("readonly ");
@@ -288,10 +317,7 @@ void GLSLSourceEmitter::emitSSBOHeader(IRGlobalParam* varDecl, IRType* bufferTyp
}
m_writer->emit(") ");
- if (varDecl->findDecoration<IRGloballyCoherentDecoration>())
- {
- m_writer->emit("coherent ");
- }
+ _emitMemoryQualifierDecorations(varDecl);
/*
If the output type is a buffer, and we can determine it is only readonly we can prefix before
@@ -461,6 +487,11 @@ void GLSLSourceEmitter::_emitGLSLImageFormatModifier(IRInst* var, IRTextureType*
}
else
{
+ auto formatInfo = getImageFormatInfo(format);
+ if (formatInfo.scalarType == SLANG_SCALAR_TYPE_UINT64 || formatInfo.scalarType == SLANG_SCALAR_TYPE_INT64)
+ {
+ _requireGLSLExtension(UnownedStringSlice::fromLiteral("GL_EXT_shader_image_int64"));
+ }
// If there is an explicit format specified, then we
// should emit a `layout` modifier using the GLSL name
// for the format.
diff --git a/source/slang/slang-emit-glsl.h b/source/slang/slang-emit-glsl.h
index 1a95cd346..610a961d2 100644
--- a/source/slang/slang-emit-glsl.h
+++ b/source/slang/slang-emit-glsl.h
@@ -35,6 +35,7 @@ protected:
virtual void emitInterpolationModifiersImpl(IRInst* varInst, IRType* valueType, IRVarLayout* layout) SLANG_OVERRIDE;
virtual void emitPackOffsetModifier(IRInst* varInst, IRType* valueType, IRPackOffsetDecoration* decoration) SLANG_OVERRIDE;
+ virtual void emitMemoryQualifiers(IRInst* varInst) SLANG_OVERRIDE;
virtual void emitMeshShaderModifiersImpl(IRInst* varInst) SLANG_OVERRIDE;
virtual void emitSimpleTypeImpl(IRType* type) SLANG_OVERRIDE;
virtual void emitVectorTypeNameImpl(IRType* elementType, IRIntegerValue elementCount) SLANG_OVERRIDE;
@@ -56,6 +57,7 @@ protected:
virtual void emitSimpleValueImpl(IRInst* inst) SLANG_OVERRIDE;
virtual void emitLoopControlDecorationImpl(IRLoopControlDecoration* decl) SLANG_OVERRIDE;
+ void _emitMemoryQualifierDecorations(IRInst* varDecl);
void _emitGLSLTextureOrTextureSamplerType(IRTextureTypeBase* type, char const* baseName);
void _emitGLSLStructuredBuffer(IRGlobalParam* varDecl, IRHLSLStructuredBufferTypeBase* structuredBufferType);
diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp
index c48f0e978..ddcd5ae4d 100644
--- a/source/slang/slang-emit-spirv.cpp
+++ b/source/slang/slang-emit-spirv.cpp
@@ -1765,6 +1765,40 @@ struct SPIRVEmitContext
}
}
+ void setImageFormatCapabilityAndExtension(SpvImageFormat format, SpvCapability_ setCapabilityMask)
+ {
+ switch (format)
+ {
+ case SpvImageFormatUnknown:
+ case SpvImageFormatRgba32f:
+ case SpvImageFormatRgba16f:
+ case SpvImageFormatR32f:
+ case SpvImageFormatRgba8:
+ case SpvImageFormatRgba8Snorm:
+ case SpvImageFormatRgba32i:
+ case SpvImageFormatRgba16i:
+ case SpvImageFormatRgba8i:
+ case SpvImageFormatR32i:
+ case SpvImageFormatRgba32ui:
+ case SpvImageFormatRgba16ui:
+ case SpvImageFormatRgba8ui:
+ case SpvImageFormatR32ui:
+ if(setCapabilityMask == SpvCapabilityShader) return;
+ requireSPIRVCapability(SpvCapabilityShader);
+ return;
+ case SpvImageFormatR64ui:
+ case SpvImageFormatR64i:
+ if(setCapabilityMask == SpvCapabilityInt64ImageEXT) return;
+ ensureExtensionDeclaration(UnownedStringSlice("SPV_EXT_shader_image_int64"));
+ requireSPIRVCapability(SpvCapabilityInt64ImageEXT);
+ return;
+ default:
+ if(setCapabilityMask == SpvCapabilityStorageImageExtendedFormats) return;
+ requireSPIRVCapability(SpvCapabilityStorageImageExtendedFormats);
+ return;
+ }
+ }
+
SpvInst* ensureTextureType(IRInst* assignee, IRTextureTypeBase* inst)
{
// Some untyped constants from OpTypeImage
@@ -1895,6 +1929,8 @@ struct SPIRVEmitContext
//
// SPIR-V requires that the sampled/rw info on the image isn't unknown
SLANG_ASSERT(sampled == sampledImage || sampled == readWriteImage);
+ if(isMultisampled)
+ requireSPIRVCapability(SpvCapabilityStorageImageMultisample);
switch(dim)
{
case SpvDim1D:
@@ -1933,9 +1969,7 @@ struct SPIRVEmitContext
requireSPIRVCapability(SpvCapabilityStorageImageWriteWithoutFormat);
}
- auto formatCapability = getImageFormatCapability(format);
- if (formatCapability != SpvCapabilityShader)
- requireSPIRVCapability(formatCapability);
+ setImageFormatCapabilityAndExtension(format, SpvCapabilityShader);
//
// The op itself
@@ -3266,6 +3300,30 @@ struct SPIRVEmitContext
dstID,
SpvDecorationCoherent);
break;
+ case kIROp_GLSLVolatileDecoration:
+ emitOpDecorate(getSection(SpvLogicalSectionID::Annotations),
+ decoration,
+ dstID,
+ SpvDecorationVolatile);
+ break;
+ case kIROp_GLSLRestrictDecoration:
+ emitOpDecorate(getSection(SpvLogicalSectionID::Annotations),
+ decoration,
+ dstID,
+ SpvDecorationRestrict);
+ break;
+ case kIROp_GLSLReadOnlyDecoration:
+ emitOpDecorate(getSection(SpvLogicalSectionID::Annotations),
+ decoration,
+ dstID,
+ SpvDecorationNonWritable);
+ break;
+ case kIROp_GLSLWriteOnlyDecoration:
+ emitOpDecorate(getSection(SpvLogicalSectionID::Annotations),
+ decoration,
+ dstID,
+ SpvDecorationNonReadable);
+ break;
// ...
}
diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h
index 63f063154..254a411cd 100644
--- a/source/slang/slang-ir-inst-defs.h
+++ b/source/slang/slang-ir-inst-defs.h
@@ -660,6 +660,8 @@ INST(GetOptiXSbtDataPtr, getOptiXSbtDataPointer, 0, 0)
INST(GetVulkanRayTracingPayloadLocation, GetVulkanRayTracingPayloadLocation, 1, 0)
+INST(GetLegalizedSPIRVGlobalParamAddr, kIROp_GetLegalizedSPIRVGlobalParamAddr, 1, 0)
+
INST(MakeArrayList, makeArrayList, 0, 0)
INST(MakeTensorView, makeTensorView, 0, 0)
INST(AllocateTorchTensor, allocTorchTensor, 0, 0)
@@ -856,6 +858,10 @@ INST(HighLevelDeclDecoration, highLevelDecl, 1, 0)
INST(GlobalInputDecoration, output, 0, 0)
INST(GLSLLocationDecoration, glslLocation, 1, 0)
INST(GLSLOffsetDecoration, glslOffset, 1, 0)
+ INST(GLSLVolatileDecoration, glslVolatile, 1, 0)
+ INST(GLSLRestrictDecoration, glslRestrict, 1, 0)
+ INST(GLSLReadOnlyDecoration, glslReadonly, 1, 0)
+ INST(GLSLWriteOnlyDecoration, glslWriteonly, 1, 0)
INST(PayloadDecoration, payload, 0, 0)
/* Mesh Shader outputs */
diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h
index 36f9159a8..c884dd35f 100644
--- a/source/slang/slang-ir-insts.h
+++ b/source/slang/slang-ir-insts.h
@@ -354,6 +354,10 @@ IR_SIMPLE_DECORATION(ReadNoneDecoration)
IR_SIMPLE_DECORATION(NoSideEffectDecoration)
IR_SIMPLE_DECORATION(EarlyDepthStencilDecoration)
IR_SIMPLE_DECORATION(GloballyCoherentDecoration)
+IR_SIMPLE_DECORATION(GLSLVolatileDecoration)
+IR_SIMPLE_DECORATION(GLSLRestrictDecoration)
+IR_SIMPLE_DECORATION(GLSLReadOnlyDecoration)
+IR_SIMPLE_DECORATION(GLSLWriteOnlyDecoration)
IR_SIMPLE_DECORATION(PreciseDecoration)
IR_SIMPLE_DECORATION(PublicDecoration)
IR_SIMPLE_DECORATION(HLSLExportDecoration)
diff --git a/source/slang/slang-ir-spirv-legalize.cpp b/source/slang/slang-ir-spirv-legalize.cpp
index ca3729abc..68f1e02a2 100644
--- a/source/slang/slang-ir-spirv-legalize.cpp
+++ b/source/slang/slang-ir-spirv-legalize.cpp
@@ -217,7 +217,12 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
IRBuilder builder(user);
builder.setInsertBefore(user);
- if((as<IRGetElement>(user) || as<IRFieldExtract>(user)) &&
+ if(user->getOp() == kIROp_GetLegalizedSPIRVGlobalParamAddr)
+ {
+ user->replaceUsesWith(use->get());
+ user->removeAndDeallocate();
+ }
+ else if((as<IRGetElement>(user) || as<IRFieldExtract>(user)) &&
use == user->getOperands())
{
// If the use is the address operand of a getElement or FieldExtract,
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp
index 3dd8da9f1..41638dc83 100644
--- a/source/slang/slang-lower-to-ir.cpp
+++ b/source/slang/slang-lower-to-ir.cpp
@@ -2217,6 +2217,22 @@ void addVarDecorations(
{
builder->addDynamicUniformDecoration(inst);
}
+ else if (as<GLSLVolatileModifier>(mod))
+ {
+ builder->addSimpleDecoration<IRGLSLVolatileDecoration>(inst);
+ }
+ else if (as<GLSLRestrictModifier>(mod))
+ {
+ builder->addSimpleDecoration<IRGLSLRestrictDecoration>(inst);
+ }
+ else if (as<GLSLReadOnlyModifier>(mod))
+ {
+ builder->addSimpleDecoration<IRGLSLReadOnlyDecoration>(inst);
+ }
+ else if (as<GLSLWriteOnlyModifier>(mod))
+ {
+ builder->addSimpleDecoration<IRGLSLWriteOnlyDecoration>(inst);
+ }
// TODO: what are other modifiers we need to propagate through?
}
if(auto t = composeGetters<IRMeshOutputType>(inst->getFullType(), &IROutTypeBase::getValueType))
diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp
index f7a0376ce..5b8a1af4f 100644
--- a/source/slang/slang-parser.cpp
+++ b/source/slang/slang-parser.cpp
@@ -7843,6 +7843,70 @@ namespace Slang
parser->sink->diagnose(token, Diagnostics::invalidCUDASMVersion);
return nullptr;
}
+ static NodeBase* parseVolatileModifier(Parser* parser, void* /*userData*/)
+ {
+ ModifierListBuilder listBuilder;
+
+ auto hlslMod = parser->astBuilder->create<HLSLVolatileModifier>();
+ hlslMod->keywordName = getName(parser, "volatile");
+ hlslMod->loc = parser->tokenReader.peekLoc();
+ listBuilder.add(hlslMod);
+
+ auto glslMod = parser->astBuilder->create<GLSLVolatileModifier>();
+ glslMod->keywordName = getName(parser, "volatile");
+ glslMod->loc = parser->tokenReader.peekLoc();
+ listBuilder.add(glslMod);
+
+ return listBuilder.getFirst();
+ }
+
+ static NodeBase* parseCoherentModifier(Parser* parser, void* /*userData*/)
+ {
+ ModifierListBuilder listBuilder;
+
+ auto glslMod = parser->astBuilder->create<GloballyCoherentModifier>();
+ glslMod->keywordName = getName(parser, "coherent");
+ glslMod->loc = parser->tokenReader.peekLoc();
+ listBuilder.add(glslMod);
+
+ return listBuilder.getFirst();
+ }
+
+ static NodeBase* parseRestrictModifier(Parser* parser, void* /*userData*/)
+ {
+ ModifierListBuilder listBuilder;
+
+ auto glslMod = parser->astBuilder->create<GLSLRestrictModifier>();
+ glslMod->keywordName = getName(parser, "restrict");
+ glslMod->loc = parser->tokenReader.peekLoc();
+ listBuilder.add(glslMod);
+
+ return listBuilder.getFirst();
+ }
+
+ static NodeBase* parseReadonlyModifier(Parser* parser, void* /*userData*/)
+ {
+ ModifierListBuilder listBuilder;
+
+ auto glslMod = parser->astBuilder->create<GLSLReadOnlyModifier>();
+ glslMod->keywordName = getName(parser, "readonly");
+ glslMod->loc = parser->tokenReader.peekLoc();
+ listBuilder.add(glslMod);
+
+ return listBuilder.getFirst();
+ }
+
+ static NodeBase* parseWriteonlyModifier(Parser* parser, void* /*userData*/)
+ {
+ ModifierListBuilder listBuilder;
+
+ auto glslMod = parser->astBuilder->create<GLSLWriteOnlyModifier>();
+ glslMod->keywordName = getName(parser, "writeonly");
+ glslMod->loc = parser->tokenReader.peekLoc();
+ listBuilder.add(glslMod);
+
+ return listBuilder.getFirst();
+ }
static NodeBase* parseLayoutModifier(Parser* parser, void* /*userData*/)
{
@@ -7850,6 +7914,8 @@ namespace Slang
GLSLLayoutLocalSizeAttribute* numThreadsAttrib = nullptr;
+ ImageFormat format;
+
listBuilder.add(parser->astBuilder->create<GLSLLayoutModifierGroupBegin>());
parser->ReadToken(TokenType::LParent);
@@ -7923,6 +7989,12 @@ namespace Slang
}
}
}
+ else if(findImageFormatByName(nameText.getUnownedSlice(), &format))
+ {
+ auto attr = parser->astBuilder->create<FormatAttribute>();
+ attr->format = format;
+ listBuilder.add(attr);
+ }
else
{
Modifier* modifier = nullptr;
@@ -8208,7 +8280,11 @@ namespace Slang
_makeParseModifier("groupshared", HLSLGroupSharedModifier::kReflectClassInfo),
_makeParseModifier("static", HLSLStaticModifier::kReflectClassInfo),
_makeParseModifier("uniform", HLSLUniformModifier::kReflectClassInfo),
- _makeParseModifier("volatile", HLSLVolatileModifier::kReflectClassInfo),
+ _makeParseModifier("volatile", parseVolatileModifier),
+ _makeParseModifier("coherent", parseCoherentModifier),
+ _makeParseModifier("restrict", parseRestrictModifier),
+ _makeParseModifier("readonly", parseReadonlyModifier),
+ _makeParseModifier("writeonly", parseWriteonlyModifier),
_makeParseModifier("export", HLSLExportModifier::kReflectClassInfo),
_makeParseModifier("dynamic_uniform", DynamicUniformModifier::kReflectClassInfo),