summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
authorTim Foley <tfoleyNV@users.noreply.github.com>2019-04-08 11:09:03 -0700
committerRobert Stepinski <rob.stepinski@gmail.com>2019-04-08 14:09:03 -0400
commitdc54f1dd1b694b087816857a791e9d37dc25de6d (patch)
treeb611249a5fb5d01dbd765d67ac646fa12b495800 /source
parentc9d06fe1f46a21c66c378ab9771495d6344db49c (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.cpp18
-rw-r--r--source/slang/compiler.h6
-rw-r--r--source/slang/core.meta.slang3
-rw-r--r--source/slang/core.meta.slang.h3
-rw-r--r--source/slang/diagnostic-defs.h2
-rw-r--r--source/slang/emit.cpp278
-rw-r--r--source/slang/image-format-defs.h47
-rw-r--r--source/slang/ir-clone.cpp19
-rw-r--r--source/slang/ir-clone.h6
-rw-r--r--source/slang/ir-inst-defs.h3
-rw-r--r--source/slang/ir-insts.h23
-rw-r--r--source/slang/ir-legalize-types.cpp40
-rw-r--r--source/slang/lower-to-ir.cpp6
-rw-r--r--source/slang/modifier-defs.h4
-rw-r--r--source/slang/options.cpp4
-rw-r--r--source/slang/slang.vcxproj1
-rw-r--r--source/slang/slang.vcxproj.filters5
-rw-r--r--source/slang/syntax.cpp36
-rw-r--r--source/slang/syntax.h9
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