diff options
| author | Tim Foley <tfoleyNV@users.noreply.github.com> | 2019-04-08 11:09:03 -0700 |
|---|---|---|
| committer | Robert Stepinski <rob.stepinski@gmail.com> | 2019-04-08 14:09:03 -0400 |
| commit | dc54f1dd1b694b087816857a791e9d37dc25de6d (patch) | |
| tree | b611249a5fb5d01dbd765d67ac646fa12b495800 /source | |
| parent | c9d06fe1f46a21c66c378ab9771495d6344db49c (diff) | |
Add better control over image formats for GLSL/SPIR-V targets (#939)
* Add better control over image formats for GLSL/SPIR-V targets
Currently Slang emits GLSL code assuming all R/W images need to have explicit formats, and thus we try to infer a format from the element type of the image.
E.g., given a `RWTexture2D<half4>` we might infer that a qualifier of `layout(rgba16f)` should be used.
This strategy has two notable shortcomings:
* Sometimes the user will want a format that doesn't match an existing HLSL type. E.g., if they want the equivalent of `layout(r11f_g11f_b10f)`, then what should they put in their `RWTexture2D<...>` to make the inference do what they need?
* Sometimes the user knows that they don't need to specify a format *at all*, because using the `GL_EXT_shader_image_load_formatted` extension, they can still perform non-atomic load/store on images with no format specified in the SPIR-V.
This change adds two features directed at these challenges.
First, we add an explicit `[format(...)]` attribute that can be used to specify an explicit image format, including ones that don't match any HLSL type.
An example of using this new attribute is:
```hlsl
[format("r11f_g11f_b10f")]
RWTexture2D<float3> myImage;
```
For simplicity in initial bring-up, the new formats all use the same naming as formats in GLSL (this should make it easy for a programmer who knows what they expect to get in the GLSL output). We can change the naming convention for formats at a later time, so long as we keep these existing names in as a compatibility feature.
Note that this is *not* given a `vk::` prefix since the attribute should signal the programmer's intent to provide an image with that format on *all* targets (although only some targets might act on that information).
Also note that the attribute takes a string (`[format("rgba8")`) instead of a bare identifier (`[format(rgba8)]`) because this is consistent with the existing convention for attributes in HLSL.
When `[format(...)]` is left off, the default compiler behavior will still be to infer a format, but this behavior can be overidden for a single image using an explicit format of `"unknown"`:
```hlsl
[format("unknown")]
RWTexture2D<float4> mysteryMachine;
```
The second new feature is that if a user knows they are coding for a GPU that supports the `"unknown"` format in all non-atomic cases, then they can opt into making that the default for images without an explicit `[format(...)]`, using the new `-default-image-format-unknown` command-line option for `slangc`.
The new test case included with this change confirms that we correctly see the explicit formats in the output GLSL and *no* formats for images without explicit `[format(...)]` when using the new command-line option. The test stresses images declared at global scope, in parameter blocks, and in entry-point parameter lists, to try and make sure that all the relevant IR passes in the compiler preserve the format information.
* fixup: missing file
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang/check.cpp | 18 | ||||
| -rw-r--r-- | source/slang/compiler.h | 6 | ||||
| -rw-r--r-- | source/slang/core.meta.slang | 3 | ||||
| -rw-r--r-- | source/slang/core.meta.slang.h | 3 | ||||
| -rw-r--r-- | source/slang/diagnostic-defs.h | 2 | ||||
| -rw-r--r-- | source/slang/emit.cpp | 278 | ||||
| -rw-r--r-- | source/slang/image-format-defs.h | 47 | ||||
| -rw-r--r-- | source/slang/ir-clone.cpp | 19 | ||||
| -rw-r--r-- | source/slang/ir-clone.h | 6 | ||||
| -rw-r--r-- | source/slang/ir-inst-defs.h | 3 | ||||
| -rw-r--r-- | source/slang/ir-insts.h | 23 | ||||
| -rw-r--r-- | source/slang/ir-legalize-types.cpp | 40 | ||||
| -rw-r--r-- | source/slang/lower-to-ir.cpp | 6 | ||||
| -rw-r--r-- | source/slang/modifier-defs.h | 4 | ||||
| -rw-r--r-- | source/slang/options.cpp | 4 | ||||
| -rw-r--r-- | source/slang/slang.vcxproj | 1 | ||||
| -rw-r--r-- | source/slang/slang.vcxproj.filters | 5 | ||||
| -rw-r--r-- | source/slang/syntax.cpp | 36 | ||||
| -rw-r--r-- | source/slang/syntax.h | 9 |
19 files changed, 400 insertions, 113 deletions
diff --git a/source/slang/check.cpp b/source/slang/check.cpp index 166fff771..e327834c0 100644 --- a/source/slang/check.cpp +++ b/source/slang/check.cpp @@ -2905,6 +2905,24 @@ namespace Slang getSink()->diagnose(attr, Diagnostics::notEnoughArguments, attr->args.Count(), params.Count()); } } + else if (auto formatAttr = as<FormatAttribute>(attr)) + { + SLANG_ASSERT(attr->args.Count() == 1); + + String formatName; + if(!checkLiteralStringVal(attr->args[0], &formatName)) + { + return false; + } + + ImageFormat format = ImageFormat::unknown; + if(!findImageFormatByName(formatName.Buffer(), &format)) + { + getSink()->diagnose(attr->args[0], Diagnostics::unknownImageFormatName, formatName); + } + + formatAttr->format = format; + } else { if(attr->args.Count() == 0) diff --git a/source/slang/compiler.h b/source/slang/compiler.h index a0568a047..5199d2540 100644 --- a/source/slang/compiler.h +++ b/source/slang/compiler.h @@ -1131,6 +1131,12 @@ namespace Slang Program* getProgram() { return m_program; } void setProgram(Program* program) { m_program = program; } + // Should R/W images without explicit formats be assumed to have "unknown" format? + // + // The default behavior is to make a best-effort guess as to what format is intended. + // + bool useUnknownImageFormatAsDefault = false; + private: RefPtr<Program> m_program; }; diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang index dc7d1f3fb..a3d73f66a 100644 --- a/source/slang/core.meta.slang +++ b/source/slang/core.meta.slang @@ -1309,3 +1309,6 @@ enum _AttributeTargets }; __attributeTarget(StructDecl) attribute_syntax [__AttributeUsage(target : _AttributeTargets)] : AttributeUsageAttribute; + +__attributeTarget(VarDeclBase) +attribute_syntax [format(format : String)] : FormatAttribute; diff --git a/source/slang/core.meta.slang.h b/source/slang/core.meta.slang.h index 819387074..ba6636ffc 100644 --- a/source/slang/core.meta.slang.h +++ b/source/slang/core.meta.slang.h @@ -1340,3 +1340,6 @@ SLANG_RAW(",\n") SLANG_RAW("};\n") SLANG_RAW("__attributeTarget(StructDecl)\n") SLANG_RAW("attribute_syntax [__AttributeUsage(target : _AttributeTargets)] : AttributeUsageAttribute;\n") +SLANG_RAW("\n") +SLANG_RAW("__attributeTarget(VarDeclBase)\n") +SLANG_RAW("attribute_syntax [format(format : String)] : FormatAttribute;\n") diff --git a/source/slang/diagnostic-defs.h b/source/slang/diagnostic-defs.h index dbbf0a563..59d840997 100644 --- a/source/slang/diagnostic-defs.h +++ b/source/slang/diagnostic-defs.h @@ -266,6 +266,8 @@ DIAGNOSTIC(31005, Error, expectedSingleStringArg, "attribute '$0' expects a sing DIAGNOSTIC(31006, Error, attributeFunctionNotFound, "Could not find function '$0' for attribute'$1'") DIAGNOSTIC(31100, Error, unknownStageName, "unknown stage name '$0'") +DIAGNOSTIC(31101, Error, unknownImageFormatName, "unknown image format '$0'") + DIAGNOSTIC(31120, Error, invalidAttributeTarget, "invalid syntax target for user defined attribute") // Enums diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp index 7615b0b28..1e9970b1a 100644 --- a/source/slang/emit.cpp +++ b/source/slang/emit.cpp @@ -5678,6 +5678,178 @@ struct EmitVisitor return value; } + void emitGLSLImageFormatModifier( + IRInst* var, + IRTextureType* resourceType) + { + // If the user specified a format manually, using `[format(...)]`, + // then we will respect that format and emit a matching `layout` modifier. + // + if(auto formatDecoration = var->findDecoration<IRFormatDecoration>()) + { + auto format = formatDecoration->getFormat(); + if(format == ImageFormat::unknown) + { + // If the user explicitly opts out of having a format, then + // the output shader will require the extension to support + // load/store from format-less images. + // + // TODO: We should have a validation somewhere in the compiler + // that atomic operations are only allowed on images with + // explicit formats (and then only on specific formats). + // This is really an argument that format should be part of + // the image *type* (with a "base type" for images with + // unknown format). + // + requireGLSLExtension("GL_EXT_shader_image_load_formatted"); + } + else + { + // If there is an explicit format specified, then we + // should emit a `layout` modifier using the GLSL name + // for the format. + // + Emit("layout("); + Emit(getGLSLNameForImageFormat(format)); + Emit(")\n"); + } + + // No matter what, if an explicit `[format(...)]` was given, + // then we don't need to emit anything else. + // + return; + } + + + // When no explicit format is specified, we need to either + // emit the image as having an unknown format, or else infer + // a format from the type. + // + // For now our default behavior is to infer (so that unmodified + // HLSL input is more likely to generate valid SPIR-V that + // runs anywhere), but we provide a flag to opt into + // treating images without explicit formats as having + // unknown format. + // + if(this->context->shared->compileRequest->useUnknownImageFormatAsDefault) + { + requireGLSLExtension("GL_EXT_shader_image_load_formatted"); + return; + } + + // At this point we have a resource type like `RWTexture2D<X>` + // and we want to infer a reasonable format from the element + // type `X` that was specified. + // + // E.g., if `X` is `float` then we can infer a format like `r32f`, + // and so forth. The catch of course is that it is possible to + // specify a shader parameter with a type like `RWTexture2D<float4>` but + // provide an image at runtime with a format like `rgba8`, so + // this inference is never guaranteed to give perfect results. + // + // If users don't like our inferred result, they need to use a + // `[format(...)]` attribute to manually specify what they want. + // + // TODO: We should consider whether we can expand the space of + // allowed types for `X` in `RWTexture2D<X>` to include special + // pseudo-types that act just like, e.g., `float4`, but come + // with attached/implied format information. + // + auto elementType = resourceType->getElementType(); + Int vectorWidth = 1; + if(auto elementVecType = as<IRVectorType>(elementType)) + { + if(auto intLitVal = as<IRIntLit>(elementVecType->getElementCount())) + { + vectorWidth = (Int) intLitVal->getValue(); + } + else + { + vectorWidth = 0; + } + elementType = elementVecType->getElementType(); + } + if(auto elementBasicType = as<IRBasicType>(elementType)) + { + Emit("layout("); + switch(vectorWidth) + { + default: Emit("rgba"); break; + + case 3: + { + // TODO: GLSL doesn't support 3-component formats so for now we are going to + // default to rgba + // + // The SPIR-V spec (https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.pdf) + // section 3.11 on Image Formats it does not list rgbf32. + // + // It seems SPIR-V can support having an image with an unknown-at-compile-time + // format, so long as the underlying API supports it. Ideally this would mean that we can + // just drop all these qualifiers when emitting GLSL for Vulkan targets. + // + // This raises the question of what to do more long term. For Vulkan hopefully we can just + // drop the layout. For OpenGL targets it would seem reasonable to have well-defined rules + // for inferring the format (and just document that 3-component formats map to 4-component formats, + // but that shouldn't matter because the API wouldn't let the user allocate those 3-component formats anyway), + // and add an attribute for specifying the format manually if you really want to override our + // inference (e.g., to specify r11fg11fb10f). + + Emit("rgba"); + //Emit("rgb"); + break; + } + + case 2: Emit("rg"); break; + case 1: Emit("r"); break; + } + switch(elementBasicType->getBaseType()) + { + default: + case BaseType::Float: Emit("32f"); break; + case BaseType::Half: Emit("16f"); break; + case BaseType::UInt: Emit("32ui"); break; + case BaseType::Int: Emit("32i"); break; + + // TODO: Here are formats that are available in GLSL, + // but that are not handled by the above cases. + // + // r11f_g11f_b10f + // + // rgba16 + // rgb10_a2 + // rgba8 + // rg16 + // rg8 + // r16 + // r8 + // + // rgba16_snorm + // rgba8_snorm + // rg16_snorm + // rg8_snorm + // r16_snorm + // r8_snorm + // + // rgba16i + // rgba8i + // rg16i + // rg8i + // r16i + // r8i + // + // rgba16ui + // rgb10_a2ui + // rgba8ui + // rg16ui + // rg8ui + // r16ui + // r8ui + } + Emit(")\n"); + } + } + void emitIRVarModifiers( EmitContext* ctx, VarLayout* layout, @@ -5703,6 +5875,7 @@ struct EmitVisitor emit(")\n"); emit("callableDataNV\n"); } + if(varDecl->findDecoration<IRVulkanHitAttributesDecoration>()) { emit("hitAttributeNV\n"); @@ -5741,110 +5914,7 @@ struct EmitVisitor case SLANG_RESOURCE_ACCESS_READ_WRITE: case SLANG_RESOURCE_ACCESS_RASTER_ORDERED: { - // We have a resource type like `RWTexture2D<X>` and when we emit - // this as an image declaration in GLSL, we need to specify the - // correct in-memory format for the image (e.g., `layout(rgba32f)`). - // - // TODO: There are modifiers in GLSL that can specify this information, - // and we should support the same ones that dxc does (e.g., - // some kind of `[[vk::format(...)]]` or what-have-you. - // - // For now we will simply infer a reasonable format from the - // element type that was specified. - // - auto elementType = resourceType->getElementType(); - Int vectorWidth = 1; - if(auto elementVecType = as<IRVectorType>(elementType)) - { - if(auto intLitVal = as<IRIntLit>(elementVecType->getElementCount())) - { - vectorWidth = (Int) intLitVal->getValue(); - } - else - { - vectorWidth = 0; - } - elementType = elementVecType->getElementType(); - } - if(auto elementBasicType = as<IRBasicType>(elementType)) - { - Emit("layout("); - switch(vectorWidth) - { - default: Emit("rgba"); break; - - case 3: - { - // TODO: GLSL doesn't support 3-component formats so for now we are going to - // default to rgba - // - // The SPIR-V spec (https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.pdf) - // section 3.11 on Image Formats it does not list rgbf32. - // - // It seems SPIR-V can support having an image with an unknown-at-compile-time - // format, so long as the underlying API supports it. Ideally this would mean that we can - // just drop all these qualifiers when emitting GLSL for Vulkan targets. - // - // This raises the question of what to do more long term. For Vulkan hopefully we can just - // drop the layout. For OpenGL targets it would seem reasonable to have well-defined rules - // for inferring the format (and just document that 3-component formats map to 4-component formats, - // but that shouldn't matter because the API wouldn't let the user allocate those 3-component formats anyway), - // and add an attribute for specifying the format manually if you really want to override our - // inference (e.g., to specify r11fg11fb10f). - - Emit("rgba"); - //Emit("rgb"); - break; - } - - case 2: Emit("rg"); break; - case 1: Emit("r"); break; - } - switch(elementBasicType->getBaseType()) - { - default: - case BaseType::Float: Emit("32f"); break; - case BaseType::Half: Emit("16f"); break; - case BaseType::UInt: Emit("32ui"); break; - case BaseType::Int: Emit("32i"); break; - - // TODO: Here are formats that are available in GLSL, - // but that are not handled by the above cases. - // - // r11f_g11f_b10f - // - // rgba16 - // rgb10_a2 - // rgba8 - // rg16 - // rg8 - // r16 - // r8 - // - // rgba16_snorm - // rgba8_snorm - // rg16_snorm - // rg8_snorm - // r16_snorm - // r8_snorm - // - // rgba16i - // rgba8i - // rg16i - // rg8i - // r16i - // r8i - // - // rgba16ui - // rgb10_a2ui - // rgba8ui - // rg16ui - // rg8ui - // r16ui - // r8ui - } - Emit(")\n"); - } + emitGLSLImageFormatModifier(varDecl, resourceType); } break; diff --git a/source/slang/image-format-defs.h b/source/slang/image-format-defs.h new file mode 100644 index 000000000..bbd60456d --- /dev/null +++ b/source/slang/image-format-defs.h @@ -0,0 +1,47 @@ +// image-format-defs.h +#ifndef FORMAT +#error Must define FORMAT macro before including image-format-defs.h +#endif + +FORMAT(unknown) +FORMAT(rgba32f) +FORMAT(rgba16f) +FORMAT(rg32f) +FORMAT(rg16f) +FORMAT(r11f_g11f_b10f) +FORMAT(r32f) +FORMAT(r16f) +FORMAT(rgba16) +FORMAT(rgb10_a2) +FORMAT(rgba8) +FORMAT(rg16) +FORMAT(rg8) +FORMAT(r16) +FORMAT(r8) +FORMAT(rgba16_snorm) +FORMAT(rgba8_snorm) +FORMAT(rg16_snorm) +FORMAT(rg8_snorm) +FORMAT(r16_snorm) +FORMAT(r8_snorm) +FORMAT(rgba32i) +FORMAT(rgba16i) +FORMAT(rgba8i) +FORMAT(rg32i) +FORMAT(rg16i) +FORMAT(rg8i) +FORMAT(r32i) +FORMAT(r16i) +FORMAT(r8i) +FORMAT(rgba32ui) +FORMAT(rgba16ui) +FORMAT(rgb10_a2ui) +FORMAT(rgba8ui) +FORMAT(rg32ui) +FORMAT(rg16ui) +FORMAT(rg8ui) +FORMAT(r32ui) +FORMAT(r16ui) +FORMAT(r8ui) + +#undef FORMAT diff --git a/source/slang/ir-clone.cpp b/source/slang/ir-clone.cpp index df9cf2bf6..b648efec6 100644 --- a/source/slang/ir-clone.cpp +++ b/source/slang/ir-clone.cpp @@ -239,6 +239,25 @@ IRInst* cloneInst( return newInst; } +void cloneDecoration( + IRDecoration* oldDecoration, + IRInst* newParent) +{ + SharedIRBuilder sharedBuilder; + sharedBuilder.module = newParent->getModule(); + + IRBuilder builder; + builder.sharedBuilder = &sharedBuilder; + + if(auto first = newParent->getFirstDecorationOrChild()) + builder.setInsertBefore(first); + else + builder.setInsertInto(newParent); + + IRCloneEnv env; + cloneInst(&env, &builder, oldDecoration); +} + bool IRSimpleSpecializationKey::operator==(IRSimpleSpecializationKey const& other) const { auto valCount = vals.Count(); diff --git a/source/slang/ir-clone.h b/source/slang/ir-clone.h index f1e27b785..ce5ebed42 100644 --- a/source/slang/ir-clone.h +++ b/source/slang/ir-clone.h @@ -125,6 +125,12 @@ IRInst* cloneInst( IRBuilder* builder, IRInst* oldInst); + /// Clone `oldDecoration` and attach the clone to `newParent`. + /// +void cloneDecoration( + IRDecoration* oldDecoration, + IRInst* newParent); + /// Find the "cloned" value to use for an operand. /// diff --git a/source/slang/ir-inst-defs.h b/source/slang/ir-inst-defs.h index 809b588ef..5ac7bd24e 100644 --- a/source/slang/ir-inst-defs.h +++ b/source/slang/ir-inst-defs.h @@ -414,6 +414,9 @@ INST(HighLevelDeclDecoration, highLevelDecl, 1, 0) INST(BindExistentialSlotsDecoration, bindExistentialSlots, 0, 0) + /// A `[format(f)]` decoration specifies that the format of an image should be `f` + INST(FormatDecoration, format, 1, 0) + /* LinkageDecoration */ INST(ImportDecoration, import, 1, 0) INST(ExportDecoration, export, 1, 0) diff --git a/source/slang/ir-insts.h b/source/slang/ir-insts.h index 86ad114c6..26a5b32be 100644 --- a/source/slang/ir-insts.h +++ b/source/slang/ir-insts.h @@ -258,6 +258,19 @@ struct IRExportDecoration : IRLinkageDecoration IR_LEAF_ISA(ExportDecoration) }; +struct IRFormatDecoration : IRDecoration +{ + enum { kOp = kIROp_FormatDecoration }; + IR_LEAF_ISA(FormatDecoration) + + IRConstant* getFormatOperand() { return cast<IRConstant>(getOperand(0)); } + + ImageFormat getFormat() + { + return ImageFormat(getFormatOperand()->value.intVal); + } +}; + // An instruction that specializes another IR value // (representing a generic) to a particular set of generic arguments // (instructions representing types, witness tables, etc.) @@ -1257,6 +1270,16 @@ struct IRBuilder { addDecoration(inst, kIROp_DependsOnDecoration, dependency); } + + void addFormatDecoration(IRInst* inst, ImageFormat format) + { + addFormatDecoration(inst, getIntValue(getIntType(), IRIntegerValue(format))); + } + + void addFormatDecoration(IRInst* inst, IRInst* format) + { + addDecoration(inst, kIROp_FormatDecoration, format); + } }; void addHoistableInst( diff --git a/source/slang/ir-legalize-types.cpp b/source/slang/ir-legalize-types.cpp index 7b6c4d79d..127593dd5 100644 --- a/source/slang/ir-legalize-types.cpp +++ b/source/slang/ir-legalize-types.cpp @@ -11,6 +11,7 @@ // that the concrete type of everything is known. #include "ir.h" +#include "ir-clone.h" #include "ir-insts.h" #include "legalize-types.h" #include "mangle.h" @@ -125,6 +126,7 @@ static LegalVal declareVars( TypeLayout* typeLayout, LegalVarChain const& varChain, UnownedStringSlice nameHint, + IRInst* leafVar, IRGlobalNameInfo* globalNameInfo); /// Unwrap a value with flavor `wrappedBuffer` @@ -1309,7 +1311,7 @@ static LegalVal legalizeLocalVar( UnownedStringSlice nameHint = findNameHint(irLocalVar); context->builder->setInsertBefore(irLocalVar); - LegalVal newVal = declareVars(context, kIROp_Var, legalValueType, typeLayout, varChain, nameHint, nullptr); + LegalVal newVal = declareVars(context, kIROp_Var, legalValueType, typeLayout, varChain, nameHint, irLocalVar, nullptr); // Remove the old local var. irLocalVar->removeFromParent(); @@ -1343,7 +1345,7 @@ static LegalVal legalizeParam( UnownedStringSlice nameHint = findNameHint(originalParam); context->builder->setInsertBefore(originalParam); - auto newVal = declareVars(context, kIROp_Param, legalParamType, nullptr, LegalVarChain(), nameHint, nullptr); + auto newVal = declareVars(context, kIROp_Param, legalParamType, nullptr, LegalVarChain(), nameHint, originalParam, nullptr); originalParam->removeFromParent(); context->replacedInstructions.Add(originalParam); @@ -1586,6 +1588,7 @@ static LegalVal declareSimpleVar( TypeLayout* typeLayout, LegalVarChain const& varChain, UnownedStringSlice nameHint, + IRInst* leafVar, IRGlobalNameInfo* globalNameInfo) { SLANG_UNUSED(globalNameInfo); @@ -1676,6 +1679,23 @@ static LegalVal declareSimpleVar( { context->builder->addNameHintDecoration(irVar, nameHint); } + + if( leafVar ) + { + for( auto decoration : leafVar->getDecorations() ) + { + switch( decoration->op ) + { + case kIROp_FormatDecoration: + cloneDecoration(decoration, irVar); + break; + + default: + break; + } + } + } + } return legalVarVal; @@ -2202,6 +2222,7 @@ static LegalVal declareVars( TypeLayout* typeLayout, LegalVarChain const& varChain, UnownedStringSlice nameHint, + IRInst* leafVar, IRGlobalNameInfo* globalNameInfo) { switch (type.flavor) @@ -2210,7 +2231,7 @@ static LegalVal declareVars( return LegalVal(); case LegalType::Flavor::simple: - return declareSimpleVar(context, op, type.getSimple(), typeLayout, varChain, nameHint, globalNameInfo); + return declareSimpleVar(context, op, type.getSimple(), typeLayout, varChain, nameHint, leafVar, globalNameInfo); break; case LegalType::Flavor::implicitDeref: @@ -2225,6 +2246,7 @@ static LegalVal declareVars( typeLayout, varChain, nameHint, + leafVar, globalNameInfo); return LegalVal::implicitDeref(val); } @@ -2233,8 +2255,8 @@ static LegalVal declareVars( case LegalType::Flavor::pair: { auto pairType = type.getPair(); - auto ordinaryVal = declareVars(context, op, pairType->ordinaryType, typeLayout, varChain, nameHint, globalNameInfo); - auto specialVal = declareVars(context, op, pairType->specialType, typeLayout, varChain, nameHint, globalNameInfo); + auto ordinaryVal = declareVars(context, op, pairType->ordinaryType, typeLayout, varChain, nameHint, leafVar, globalNameInfo); + auto specialVal = declareVars(context, op, pairType->specialType, typeLayout, varChain, nameHint, leafVar, globalNameInfo); return LegalVal::pair(ordinaryVal, specialVal, pairType->pairInfo); } @@ -2282,6 +2304,7 @@ static LegalVal declareVars( fieldTypeLayout, newVarChain, fieldNameHint, + ee.key, globalNameInfo); TuplePseudoVal::Element element; @@ -2307,6 +2330,7 @@ static LegalVal declareVars( wrappedTypeLayout, varChain, nameHint, + leafVar, globalNameInfo); return LegalVal::wrappedBuffer(innerVal, wrappedBuffer->elementInfo); @@ -2349,7 +2373,7 @@ static LegalVal legalizeGlobalVar( UnownedStringSlice nameHint = findNameHint(irGlobalVar); context->builder->setInsertBefore(irGlobalVar); - LegalVal newVal = declareVars(context, kIROp_GlobalVar, legalValueType, nullptr, LegalVarChain(), nameHint, &globalNameInfo); + LegalVal newVal = declareVars(context, kIROp_GlobalVar, legalValueType, nullptr, LegalVarChain(), nameHint, irGlobalVar, &globalNameInfo); // Register the new value as the replacement for the old registerLegalizedValue(context, irGlobalVar, newVal); @@ -2393,7 +2417,7 @@ static LegalVal legalizeGlobalConstant( UnownedStringSlice nameHint = findNameHint(irGlobalConstant); context->builder->setInsertBefore(irGlobalConstant); - LegalVal newVal = declareVars(context, kIROp_GlobalConstant, legalValueType, nullptr, LegalVarChain(), nameHint, &globalNameInfo); + LegalVal newVal = declareVars(context, kIROp_GlobalConstant, legalValueType, nullptr, LegalVarChain(), nameHint, irGlobalConstant, &globalNameInfo); // Register the new value as the replacement for the old registerLegalizedValue(context, irGlobalConstant, newVal); @@ -2442,7 +2466,7 @@ static LegalVal legalizeGlobalParam( UnownedStringSlice nameHint = findNameHint(irGlobalParam); context->builder->setInsertBefore(irGlobalParam); - LegalVal newVal = declareVars(context, kIROp_GlobalParam, legalValueType, typeLayout, varChain, nameHint, &globalNameInfo); + LegalVal newVal = declareVars(context, kIROp_GlobalParam, legalValueType, typeLayout, varChain, nameHint, irGlobalParam, &globalNameInfo); // Register the new value as the replacement for the old registerLegalizedValue(context, irGlobalParam, newVal); diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp index 1e50c8aff..0cc5b2a5c 100644 --- a/source/slang/lower-to-ir.cpp +++ b/source/slang/lower-to-ir.cpp @@ -1680,6 +1680,10 @@ void addVarDecorations( { builder->addSimpleDecoration<IRGloballyCoherentDecoration>(inst); } + else if(auto formatAttr = as<FormatAttribute>(mod)) + { + builder->addFormatDecoration(inst, formatAttr->format); + } // TODO: what are other modifiers we need to propagate through? } @@ -5653,6 +5657,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> IRParam* irParamPtr = subBuilder->emitParam(irParamType); if(auto paramDecl = paramInfo.decl) { + addVarDecorations(context, irParamPtr, paramDecl); subBuilder->addHighLevelDeclDecoration(irParamPtr, paramDecl); } addParamNameHint(irParamPtr, paramInfo); @@ -5680,6 +5685,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> IRParam* irParam = subBuilder->emitParam(irParamType); if( paramDecl ) { + addVarDecorations(context, irParam, paramDecl); subBuilder->addHighLevelDeclDecoration(irParam, paramDecl); } addParamNameHint(irParam, paramInfo); diff --git a/source/slang/modifier-defs.h b/source/slang/modifier-defs.h index 76d806fea..1fa3a1f8e 100644 --- a/source/slang/modifier-defs.h +++ b/source/slang/modifier-defs.h @@ -457,3 +457,7 @@ SYNTAX_CLASS(ImplicitConversionModifier, Modifier) // The conversion cost, used to rank conversions FIELD(ConversionCost, cost) END_SYNTAX_CLASS() + +SYNTAX_CLASS(FormatAttribute, Attribute) + FIELD(ImageFormat, format) +END_SYNTAX_CLASS() diff --git a/source/slang/options.cpp b/source/slang/options.cpp index dc37873a4..6474f2afe 100644 --- a/source/slang/options.cpp +++ b/source/slang/options.cpp @@ -773,6 +773,10 @@ struct OptionsParser { spSetDebugInfoLevel(compileRequest, SLANG_DEBUG_INFO_LEVEL_MAXIMAL); } + else if( argStr == "-default-image-format-unknown" ) + { + requestImpl->getBackEndReq()->useUnknownImageFormatAsDefault = true; + } else if (argStr == "--") { // The `--` option causes us to stop trying to parse options, diff --git a/source/slang/slang.vcxproj b/source/slang/slang.vcxproj index 40306899f..bb4aa66ff 100644 --- a/source/slang/slang.vcxproj +++ b/source/slang/slang.vcxproj @@ -181,6 +181,7 @@ <ClInclude Include="expr-defs.h" /> <ClInclude Include="glsl.meta.slang.h" /> <ClInclude Include="hlsl.meta.slang.h" /> + <ClInclude Include="image-format-defs.h" /> <ClInclude Include="ir-bind-existentials.h" /> <ClInclude Include="ir-clone.h" /> <ClInclude Include="ir-constexpr.h" /> diff --git a/source/slang/slang.vcxproj.filters b/source/slang/slang.vcxproj.filters index 5afd32765..18530d11a 100644 --- a/source/slang/slang.vcxproj.filters +++ b/source/slang/slang.vcxproj.filters @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> +<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> <Filter Include="Header Files"> @@ -195,6 +195,9 @@ <ClInclude Include="visitor.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="image-format-defs.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="check.cpp"> diff --git a/source/slang/syntax.cpp b/source/slang/syntax.cpp index b1b9f6d80..c48eb7755 100644 --- a/source/slang/syntax.cpp +++ b/source/slang/syntax.cpp @@ -2723,5 +2723,41 @@ Module* getModule(Decl* decl) return nullptr; } +bool findImageFormatByName(char const* name, ImageFormat* outFormat) +{ + static const struct + { + char const* name; + ImageFormat format; + } kFormats[] = + { +#define FORMAT(NAME) { #NAME, ImageFormat::NAME }, +#include "image-format-defs.h" + }; + + for( auto item : kFormats ) + { + if( strcmp(item.name, name) == 0 ) + { + *outFormat = item.format; + return true; + } + } + + return false; +} + +char const* getGLSLNameForImageFormat(ImageFormat format) +{ + switch( format ) + { + default: return "unhandled"; +#define FORMAT(NAME) case ImageFormat::NAME: return #NAME; +#include "image-format-defs.h" + } +} + + + } // namespace Slang diff --git a/source/slang/syntax.h b/source/slang/syntax.h index cb45c0363..41d8b2cec 100644 --- a/source/slang/syntax.h +++ b/source/slang/syntax.h @@ -83,6 +83,15 @@ namespace Slang kConversionCost_Impossible = 0xFFFFFFFF, }; + enum class ImageFormat + { +#define FORMAT(NAME) NAME, +#include "image-format-defs.h" + }; + + bool findImageFormatByName(char const* name, ImageFormat* outFormat); + char const* getGLSLNameForImageFormat(ImageFormat format); + // TODO(tfoley): We should ditch this enumeration // and just use the IR opcodes that represent these // types directly. The one major complication there |
