diff --git a/source/slang/slang-ast-modifier.h b/source/slang/slang-ast-modifier.h index 863ffaef23..6d11f09538 100644 --- a/source/slang/slang-ast-modifier.h +++ b/source/slang/slang-ast-modifier.h @@ -693,6 +693,38 @@ class UncheckedAttribute : public AttributeBase Scope* scope = nullptr; }; +// A GLSL layout qualifier whose value has not yet been resolved or validated. +class UncheckedGLSLLayoutAttribute : public AttributeBase +{ + SLANG_AST_CLASS(UncheckedGLSLLayoutAttribute) + + SLANG_UNREFLECTED +}; + +// GLSL `binding` layout qualifier, does not include `set`. +class UncheckedGLSLBindingLayoutAttribute : public UncheckedGLSLLayoutAttribute +{ + SLANG_AST_CLASS(UncheckedGLSLBindingLayoutAttribute) + + SLANG_UNREFLECTED +}; + +// GLSL `set` layout qualifier, does not include `binding`. +class UncheckedGLSLSetLayoutAttribute : public UncheckedGLSLLayoutAttribute +{ + SLANG_AST_CLASS(UncheckedGLSLSetLayoutAttribute) + + SLANG_UNREFLECTED +}; + +// GLSL `offset` layout qualifier. +class UncheckedGLSLOffsetLayoutAttribute : public UncheckedGLSLLayoutAttribute +{ + SLANG_AST_CLASS(UncheckedGLSLOffsetLayoutAttribute) + + SLANG_UNREFLECTED +}; + // A `[name(arg0, ...)]` style attribute that has been validated. class Attribute : public AttributeBase { @@ -854,6 +886,14 @@ class GLSLOffsetLayoutAttribute : public Attribute int64_t offset; }; +// Implicitly added offset qualifier when no offset is specified. +class GLSLImplicitOffsetLayoutAttribute : public AttributeBase +{ + SLANG_AST_CLASS(GLSLImplicitOffsetLayoutAttribute) + + SLANG_UNREFLECTED +}; + class GLSLSimpleIntegerLayoutAttribute : public Attribute { SLANG_AST_CLASS(GLSLSimpleIntegerLayoutAttribute) diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index 0dfa756315..45e8991321 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -614,6 +614,17 @@ struct ImplicitCastMethodKey } }; +/// Used to track offsets for atomic counter storage qualifiers. +struct GLSLBindingOffsetTracker +{ +public: + void setBindingOffset(int binding, int64_t byteOffset); + int64_t getNextBindingOffset(int binding); + +private: + Dictionary bindingToByteOffset; +}; + /// Shared state for a semantics-checking session. struct SharedSemanticsContext : public RefObject { @@ -645,6 +656,8 @@ struct SharedSemanticsContext : public RefObject List importedModulesList; HashSet importedModulesSet; + GLSLBindingOffsetTracker m_glslBindingOffsetTracker; + public: SharedSemanticsContext( Linkage* linkage, @@ -705,6 +718,8 @@ struct SharedSemanticsContext : public RefObject InheritanceCircularityInfo* next = nullptr; }; + GLSLBindingOffsetTracker* getGLSLBindingOffsetTracker() { return &m_glslBindingOffsetTracker; } + /// Get the processed inheritance information for `type`, including all its facets InheritanceInfo getInheritanceInfo( Type* type, @@ -1055,6 +1070,11 @@ struct SemanticsContext OrderedHashSet* getCapturedTypePacks() { return m_capturedTypePacks; } + GLSLBindingOffsetTracker* getGLSLBindingOffsetTracker() + { + return m_shared->getGLSLBindingOffsetTracker(); + } + private: SharedSemanticsContext* m_shared = nullptr; @@ -1647,6 +1667,10 @@ struct SemanticsVisitor : public SemanticsContext UncheckedAttribute* uncheckedAttr, ModifiableSyntaxNode* attrTarget); + AttributeBase* checkGLSLLayoutAttribute( + UncheckedGLSLLayoutAttribute* uncheckedAttr, + ModifiableSyntaxNode* attrTarget); + Modifier* checkModifier( Modifier* m, ModifiableSyntaxNode* syntaxNode, diff --git a/source/slang/slang-check-modifier.cpp b/source/slang/slang-check-modifier.cpp index a1e0f78764..aebfe3b962 100644 --- a/source/slang/slang-check-modifier.cpp +++ b/source/slang/slang-check-modifier.cpp @@ -32,6 +32,7 @@ ConstantIntVal* SemanticsVisitor::checkConstantIntVal(Expr* expr) IntegerConstantExpressionCoercionType::AnyInteger, nullptr, ConstantFoldingKind::CompileTime); + if (!intVal) return nullptr; @@ -524,17 +525,32 @@ Modifier* SemanticsVisitor::validateAttribute( } // TODO(JS): Prior validation currently doesn't ensure both args are ints (as specified in - // core.meta.slang), so check here to make sure they both are - auto binding = checkConstantIntVal(attr->args[0]); - auto set = checkConstantIntVal(attr->args[1]); + // core.meta.slang), so check here to make sure they both are. + // + // Binding attribute may also be created from GLSL style layout qualifiers where only one of + // the args are specified, hence check for each individually. + ConstantIntVal* binding = nullptr; + if (attr->args[0]) + binding = checkConstantIntVal(attr->args[0]); + + ConstantIntVal* set = nullptr; + if (attr->args[1]) + set = checkConstantIntVal(attr->args[1]); - if (binding == nullptr || set == nullptr) + if (!binding && !set) { return nullptr; } - bindingAttr->binding = int32_t(binding->getValue()); - bindingAttr->set = int32_t(set->getValue()); + if (binding) + { + bindingAttr->binding = int32_t(binding->getValue()); + } + + if (set) + { + bindingAttr->set = int32_t(set->getValue()); + } } else if (auto simpleLayoutAttr = as(attr)) { @@ -1430,6 +1446,97 @@ bool isModifierAllowedOnDecl(bool isGLSLInput, ASTNodeType modifierType, Decl* d } } +void GLSLBindingOffsetTracker::setBindingOffset(int binding, int64_t byteOffset) +{ + bindingToByteOffset.set(binding, byteOffset); +} + +int64_t GLSLBindingOffsetTracker::getNextBindingOffset(int binding) +{ + int64_t currentOffset; + if (bindingToByteOffset.addIfNotExists(binding, 0)) + currentOffset = 0; + else + currentOffset = bindingToByteOffset.getValue(binding) + sizeof(uint32_t); + + bindingToByteOffset.set(binding, currentOffset + sizeof(uint32_t)); + return currentOffset; +} + +AttributeBase* SemanticsVisitor::checkGLSLLayoutAttribute( + UncheckedGLSLLayoutAttribute* uncheckedAttr, + ModifiableSyntaxNode* attrTarget) +{ + SLANG_ASSERT(uncheckedAttr->args.getCount() == 1); + + Attribute* attr = nullptr; + + // False if the current unchecked attribute node is deleted and does not result in a new checked + // attribute. + bool addNode = true; + + if (as(uncheckedAttr) || + as(uncheckedAttr)) + { + // Binding and set are coupled together as a descriptor table slot resource for codegen. + // Attempt to retrieve and annotate an existing binding attribute or create a new one. + attr = attrTarget->findModifier(); + if (!attr) + { + attr = m_astBuilder->create(); + } + else + { + addNode = false; + } + + // `validateAttribute`, which will be called to parse the binding arguments, also accepts + // modifiers from vk::binding and gl::binding where both set and binding are specified. + // Binding is the first and set is the second argument - specify them explicitly here. + if (as(uncheckedAttr)) + { + uncheckedAttr->args.add(nullptr); + } + else + { + uncheckedAttr->args.add(uncheckedAttr->args[0]); + uncheckedAttr->args[0] = nullptr; + } + + SLANG_ASSERT(uncheckedAttr->args.getCount() == 2); + } + else if (as(uncheckedAttr)) + { + attr = m_astBuilder->create(); + } + else + { + getSink()->diagnose(uncheckedAttr, Diagnostics::unrecognizedGLSLLayoutQualifier); + } + + if (attr) + { + attr->keywordName = uncheckedAttr->keywordName; + attr->originalIdentifierToken = uncheckedAttr->originalIdentifierToken; + attr->args = uncheckedAttr->args; + attr->loc = uncheckedAttr->loc; + + // Offset constant folding computation is deferred until all other modifiers are checked to + // ensure bindinig is checked first. + if (!as(attr)) + { + validateAttribute(attr, nullptr, attrTarget); + } + } + + if (!addNode) + { + attr = nullptr; + } + + return attr; +} + Modifier* SemanticsVisitor::checkModifier( Modifier* m, ModifiableSyntaxNode* syntaxNode, @@ -1455,6 +1562,21 @@ Modifier* SemanticsVisitor::checkModifier( return checkedAttr; } + if (auto glslLayoutAttribute = as(m)) + { + return checkGLSLLayoutAttribute(glslLayoutAttribute, syntaxNode); + } + + if (const auto glslImplicitOffsetAttribute = as(m)) + { + auto offsetAttr = m_astBuilder->create(); + offsetAttr->loc = glslImplicitOffsetAttribute->loc; + + // Offset constant folding computation is deferred until all other modifiers are checked to + // ensure bindinig is checked first. + return offsetAttr; + } + if (auto decl = as(syntaxNode)) { auto moduleDecl = getModuleDecl(decl); @@ -1903,6 +2025,31 @@ void SemanticsVisitor::checkModifiers(ModifiableSyntaxNode* syntaxNode) // install the new list of modifiers on the declaration syntaxNode->modifiers.first = resultModifiers; + // GLSL offset layout qualifiers are resolved after all other modifiers are checked to ensure + // binding layout qualifiers are processed first. + if (auto glslOffsetAttribute = syntaxNode->findModifier()) + { + if (const auto glslBindingAttribute = syntaxNode->findModifier()) + { + if (glslOffsetAttribute->args.getCount() == 0) + { + glslOffsetAttribute->offset = getGLSLBindingOffsetTracker()->getNextBindingOffset( + glslBindingAttribute->binding); + } + else if (const auto constVal = checkConstantIntVal(glslOffsetAttribute->args[0])) + { + glslOffsetAttribute->offset = uint64_t(constVal->getValue()); + getGLSLBindingOffsetTracker()->setBindingOffset( + glslBindingAttribute->binding, + glslOffsetAttribute->offset); + } + } + else + { + getSink()->diagnose(glslOffsetAttribute, Diagnostics::missingLayoutBindingModifier); + } + } + postProcessingOnModifiers(syntaxNode->modifiers); } diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index d0f743e5c7..d6409e42e7 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -1207,6 +1207,13 @@ DIAGNOSTIC( Error, cannotUseUnsizedTypeInConstantBuffer, "cannot use unsized type '$0' in a constant buffer.") +DIAGNOSTIC(31216, Error, unrecognizedGLSLLayoutQualifier, "GLSL layout qualifier is unrecognized") +DIAGNOSTIC( + 31217, + Error, + unrecognizedGLSLLayoutQualifierOrRequiresAssignment, + "GLSL layout qualifier is unrecognized or requires assignment") + // Enums diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp index 4dc962ce6c..2fb44921d6 100644 --- a/source/slang/slang-parser.cpp +++ b/source/slang/slang-parser.cpp @@ -230,26 +230,6 @@ class Parser lastErrorLoc = loc; } } - -public: - void setBindingOffset(int binding, int64_t byteOffset) - { - bindingToByteOffset.set(binding, byteOffset); - } - int64_t getNextBindingOffset(int binding) - { - int64_t currentOffset; - if (bindingToByteOffset.addIfNotExists(binding, 0)) - currentOffset = 0; - else - currentOffset = bindingToByteOffset.getValue(binding) + sizeof(uint32_t); - - bindingToByteOffset.set(binding, currentOffset + sizeof(uint32_t)); - return currentOffset; - } - -private: - Dictionary bindingToByteOffset; }; // Forward Declarations @@ -1035,6 +1015,49 @@ static void ParseSquareBracketAttributes(Parser* parser, Modifier*** ioModifierL } } +static Modifier* parseUncheckedGLSLLayoutAttribute(Parser* parser, NameLoc& nameLoc) +{ + // Only valued GLSL layout qualifiers should be parsed here. + if (!AdvanceIf(parser, TokenType::OpAssign)) + { + return parser->astBuilder->create(); + } + + UncheckedGLSLLayoutAttribute* attr; + + if (nameLoc.name->text == "binding") + { + // An explicit type for binding is used so that it can be looked up quickly + // through the list builder when implicitly injecting an offset qualifier. + attr = parser->astBuilder->create(); + } + else if (nameLoc.name->text == "offset") + { + // An explicit type for offset is used so that it can be looked up quickly + // through the list builder when implicitly injecting an offset qualifier. + attr = parser->astBuilder->create(); + } + else if (nameLoc.name->text == "set") + { + attr = parser->astBuilder->create(); + } + else + { + attr = parser->astBuilder->create(); + } + + attr->keywordName = nameLoc.name; + attr->loc = nameLoc.loc; + + Expr* arg = parser->ParseArgExpr(); + if (arg) + { + attr->args.add(arg); + } + + return attr; +} + static TokenType peekTokenType(Parser* parser) { return parser->tokenReader.peekTokenType(); @@ -4574,9 +4597,16 @@ static void addSpecialGLSLModifiersBasedOnType(Parser* parser, Decl* decl, Modif auto declRefExpr = as(varDeclBase->type.exp); if (!declRefExpr) return; - auto bindingMod = modifiers->findModifier(); + + AttributeBase* bindingMod = modifiers->findModifier(); if (!bindingMod) + { + bindingMod = modifiers->findModifier(); + } + if (!bindingMod) + { return; + } // here is a problem; we link types into a literal in IR stage post parse // but, order (top down) mattter when parsing atomic_uint offset @@ -4587,14 +4617,10 @@ static void addSpecialGLSLModifiersBasedOnType(Parser* parser, Decl* decl, Modif { if (name->text.equals("atomic_uint")) { - if (!modifiers->findModifier()) + if (!modifiers->findModifier()) { - const int64_t nextOffset = parser->getNextBindingOffset(bindingMod->binding); - GLSLOffsetLayoutAttribute* modifier = - parser->astBuilder->create(); - modifier->keywordName = NULL; // no keyword name given - modifier->loc = bindingMod->loc; // has no location in file, set to parent binding - modifier->offset = nextOffset; + auto* modifier = parser->astBuilder->create(); + modifier->loc = bindingMod->loc; // has no location in file, set to parent Modifiers newModifier; newModifier.first = modifier; @@ -8441,36 +8467,6 @@ static NodeBase* parseLayoutModifier(Parser* parser, void* /*userData*/) inputAttachmentIndexLayoutAttribute->location = intVal; } } - else if (nameText == "binding" || nameText == "set") - { - GLSLBindingAttribute* attr = listBuilder.find(); - if (!attr) - { - attr = parser->astBuilder->create(); - listBuilder.add(attr); - } - - parser->ReadToken(TokenType::OpAssign); - - // If the token asked for is not returned found will put in recovering state, and return - // token found - Token valToken = parser->ReadToken(TokenType::IntegerLiteral); - // If wasn't the desired IntegerLiteral return that couldn't parse - if (valToken.type == TokenType::IntegerLiteral) - { - // Work out the value - auto value = getIntegerLiteralValue(valToken); - - if (nameText == "binding") - { - attr->binding = int32_t(value); - } - else - { - attr->set = int32_t(value); - } - } - } else if (findImageFormatByName(nameText.getUnownedSlice(), &format)) { auto attr = parser->astBuilder->create(); @@ -8494,10 +8490,9 @@ static NodeBase* parseLayoutModifier(Parser* parser, void* /*userData*/) CASE(std140, GLSLStd140Modifier) CASE(std430, GLSLStd430Modifier) CASE(scalar, GLSLScalarModifier) - CASE(offset, GLSLOffsetLayoutAttribute) CASE(location, GLSLLocationLayoutModifier) { - modifier = parser->astBuilder->create(); + modifier = parseUncheckedGLSLLayoutAttribute(parser, nameAndLoc); } SLANG_ASSERT(modifier); #undef CASE @@ -8513,23 +8508,6 @@ static NodeBase* parseLayoutModifier(Parser* parser, void* /*userData*/) if (AdvanceIf(parser, TokenType::OpAssign)) glslModifier->valToken = parser->ReadToken(TokenType::IntegerLiteral); } - // Special handling for GLSLOffsetLayoutAttribute to add to the byte offset tracker at a - // binding location - else if (auto glslOffset = as(modifier)) - { - if (auto binding = listBuilder.find()) - { - // all GLSLOffsetLayoutAttribute have an OpAssign with value token - parser->ReadToken(TokenType::OpAssign); - glslOffset->offset = int64_t( - getIntegerLiteralValue(parser->ReadToken(TokenType::IntegerLiteral))); - parser->setBindingOffset(binding->binding, glslOffset->offset); - } - else - { - parser->diagnose(modifier->loc, Diagnostics::missingLayoutBindingModifier); - } - } else if (auto specConstAttr = as(modifier)) { parser->ReadToken(TokenType::OpAssign); @@ -8537,6 +8515,13 @@ static NodeBase* parseLayoutModifier(Parser* parser, void* /*userData*/) (int)getIntegerLiteralValue(parser->ReadToken(TokenType::IntegerLiteral)); } + if (as(modifier)) + { + parser->diagnose( + modifier, + Diagnostics::unrecognizedGLSLLayoutQualifierOrRequiresAssignment); + } + listBuilder.add(modifier); } diff --git a/tests/bugs/glsl-layout-define.hlsl.expected b/tests/bugs/glsl-layout-define.hlsl.expected index e97928b47c..028c803256 100644 --- a/tests/bugs/glsl-layout-define.hlsl.expected +++ b/tests/bugs/glsl-layout-define.hlsl.expected @@ -1,11 +1,15 @@ result code = -1 standard error = { -tests/bugs/glsl-layout-define.hlsl(4): error 20001: unexpected identifier, expected integer literal +tests/bugs/glsl-layout-define.hlsl(4): error 30015: undefined identifier 'UNDEFINED_VK_BINDING'. binding = UNDEFINED_VK_BINDING, ^~~~~~~~~~~~~~~~~~~~ -tests/bugs/glsl-layout-define.hlsl(5): error 20001: unexpected identifier, expected integer literal +tests/bugs/glsl-layout-define.hlsl(5): error 30015: undefined identifier 'UNDEFINED_VK_SET'. set = UNDEFINED_VK_SET) ^~~~~~~~~~~~~~~~ +(0): error 30015: undefined identifier 'main'. +tests/bugs/glsl-layout-define.hlsl(3): error 38000: no function found matching entry point name 'main' +layout( +^~~~~~ } standard output = { } diff --git a/tests/diagnostics/unrecognized-glsl-layout-modifiers.slang b/tests/diagnostics/unrecognized-glsl-layout-modifiers.slang new file mode 100644 index 0000000000..3012a8828d --- /dev/null +++ b/tests/diagnostics/unrecognized-glsl-layout-modifiers.slang @@ -0,0 +1,23 @@ +//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK): -target spirv -stage vertex -entry main -allow-glsl +#version 310 es +layout(location = 0) in highp vec4 a_position; +layout(location = 1) in highp vec4 a_coords; +layout(location = 0) out mediump vec3 v_color; + + +// CHECK: error 31216 +layout(std140, not_a_set = 0, binding = 0) uniform buff0 { + mediump int ui_zero; +}; + +void main() +{ + gl_Position = a_position; + mediump vec4 coords = a_coords; + mediump vec4 res = coords; + mediump int i = 0; + for (;;) { res = res.yzwx + vec4(1.0); if (i == 1) break; i++; } + res -= vec4(2); + v_color = res.rgb; +} + diff --git a/tests/glsl-intrinsic/atomic/atomicCounterTestMultiple.slang b/tests/glsl-intrinsic/atomic/atomicCounterTestMultiple.slang index ec296968c2..e6a3ae7e90 100644 --- a/tests/glsl-intrinsic/atomic/atomicCounterTestMultiple.slang +++ b/tests/glsl-intrinsic/atomic/atomicCounterTestMultiple.slang @@ -9,7 +9,10 @@ buffer MyBlockName layout(binding = 1, offset = 12) uniform atomic_uint one; layout(binding = 1) uniform atomic_uint two; -layout(binding = 1, offset = 4) uniform atomic_uint three; + +// Layout qualifiers can be specified in any order. +layout(offset = 4, binding = 1) uniform atomic_uint three; + layout(binding = 1) uniform atomic_uint four; layout(binding = 2) uniform atomic_uint five; diff --git a/tests/glsl-intrinsic/atomic/atomicErrorTest1.slang b/tests/glsl-intrinsic/atomic/atomicErrorTest1.slang index 0512d598e3..daf3c0c0f5 100644 --- a/tests/glsl-intrinsic/atomic/atomicErrorTest1.slang +++ b/tests/glsl-intrinsic/atomic/atomicErrorTest1.slang @@ -2,7 +2,7 @@ //DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK): -allow-glsl -stage compute -entry computeMain -target spirv -emit-spirv-directly -DTARGET_SPIRV #version 430 -// CHECK: error 20001 +// CHECK: error 20002 //TEST_INPUT:ubuffer(data=[0 0 0 0 0 0], stride=4):name=one layout(binding = 1, offset = ) uniform atomic_uint one; diff --git a/tests/glsl-intrinsic/atomic/atomicErrorTest3.slang b/tests/glsl-intrinsic/atomic/atomicErrorTest3.slang index b21d27f6d9..70d6bb2661 100644 --- a/tests/glsl-intrinsic/atomic/atomicErrorTest3.slang +++ b/tests/glsl-intrinsic/atomic/atomicErrorTest3.slang @@ -5,7 +5,7 @@ // CHECK: error 20016 //TEST_INPUT:ubuffer(data=[0 0 0 0 0 0], stride=4):name=one -layout(offset ) uniform atomic_uint one; +layout(offset = 4) uniform atomic_uint one; void computeMain() { diff --git a/tests/glsl-intrinsic/atomic/atomicErrorTest4.slang b/tests/glsl-intrinsic/atomic/atomicErrorTest4.slang index 404e2338c5..5b2435c41b 100644 --- a/tests/glsl-intrinsic/atomic/atomicErrorTest4.slang +++ b/tests/glsl-intrinsic/atomic/atomicErrorTest4.slang @@ -2,7 +2,7 @@ //DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK): -allow-glsl -stage compute -entry computeMain -target spirv -emit-spirv-directly -DTARGET_SPIRV #version 430 -// CHECK: error 20001 +// CHECK: error 31217 //TEST_INPUT:ubuffer(data=[0 0 0 0 0 0], stride=4):name=one layout(binding = 1, offset) uniform atomic_uint one; diff --git a/tests/glsl/layout-qualifier-exprs.slang b/tests/glsl/layout-qualifier-exprs.slang new file mode 100644 index 0000000000..442497261d --- /dev/null +++ b/tests/glsl/layout-qualifier-exprs.slang @@ -0,0 +1,34 @@ +//TEST:SIMPLE(filecheck=CHECK): -target spirv -stage compute -entry computeMain -allow-glsl + +#version 450 + +layout(local_size_x = 4, local_size_y = 1, local_size_z = 1) in; + +static const uint BINDING_BASE = 3; +static const uint BINDING_STRIDE = 2; + +static const uint SET_BASE = 1; +static const uint SET_STRIDE = 4; + +//TEST_INPUT:ubuffer(data=[2 2 2 2], stride=4):name=a +layout(set = SET_BASE, binding = BINDING_BASE * BINDING_STRIDE) buffer InputA { + float a[]; +}; + +//TEST_INPUT:ubuffer(data=[2 2 2 2], stride=4):name=b +layout(set = SET_BASE + SET_STRIDE, binding = BINDING_BASE * BINDING_STRIDE * 2) buffer InputB { + float b[]; +}; + +layout(set = SET_BASE + SET_STRIDE * 2, binding = BINDING_BASE * BINDING_STRIDE * 3) buffer Output { + float result[]; +}; + +void computeMain() { + uint index = gl_GlobalInvocationID.x; + + result[index] = a[index] * b[index]; + + // CHECK: OpEntryPoint +} + diff --git a/tests/hlsl-intrinsic/image-swizzle-write.slang b/tests/hlsl-intrinsic/image-swizzle-write.slang index e8a0063146..3a4f233bcc 100644 --- a/tests/hlsl-intrinsic/image-swizzle-write.slang +++ b/tests/hlsl-intrinsic/image-swizzle-write.slang @@ -1,7 +1,7 @@ //TEST:SIMPLE(filecheck=CHECK): -entry computeMain -stage compute -target spirv -emit-spirv-directly //TEST:SIMPLE(filecheck=CHECK): -entry computeMain -stage compute -target spirv -layout(rgba6f) +layout(rgba8) RWTexture2D texture; [numthreads(4, 1, 1)]