summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2021-05-15 10:52:55 -0400
committerGitHub <noreply@github.com>2021-05-15 10:52:55 -0400
commit1027225ac7ec8da0e471b633f358333c8a95b010 (patch)
tree39575cd03fed47dffb56d7ca0ec7eff3385d1407 /source
parent1856b8ad85266ed66985b42bd2321a35f8573a00 (diff)
Support for HW format conversions for RWTexture on CUDA (#1840)
* #include an absolute path didn't work - because paths were taken to always be relative. * Fix for writing to RWTexture with half types on CUDA. * CUDA half functionality doc updates. * First pass support for sust.p RWTexture format conversion on write. * Tidy up implementation of $C. Made clamping mode #define able. * A simple test for RWTexture CUDA format conversion.
Diffstat (limited to 'source')
-rw-r--r--source/slang/core.meta.slang2
-rw-r--r--source/slang/slang-ast-support-types.h12
-rw-r--r--source/slang/slang-image-format-defs.h80
-rw-r--r--source/slang/slang-intrinsic-expand.cpp114
-rw-r--r--source/slang/slang-intrinsic-expand.h1
-rw-r--r--source/slang/slang-syntax.cpp40
6 files changed, 188 insertions, 61 deletions
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang
index 934d30c18..c268c2a58 100644
--- a/source/slang/core.meta.slang
+++ b/source/slang/core.meta.slang
@@ -1132,7 +1132,7 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt)
}
sb << (isArray ? "Layered" : "");
- sb << "write<$T0>($2, $0";
+ sb << "write$C<$T0>($2, $0";
for (int i = 0; i < vecCount; ++i)
{
sb << ", ($1)";
diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h
index 168d358d6..c172ea83c 100644
--- a/source/slang/slang-ast-support-types.h
+++ b/source/slang/slang-ast-support-types.h
@@ -122,10 +122,20 @@ namespace Slang
enum class ImageFormat
{
-#define FORMAT(NAME) NAME,
+#define FORMAT(NAME, OTHER) NAME,
#include "slang-image-format-defs.h"
};
+ struct ImageFormatInfo
+ {
+ SlangScalarType scalarType; ///< If image format is not made up of channels of set sizes this will be SLANG_SCALAR_TYPE_NONE
+ uint8_t channelCount; ///< The number of channels
+ uint8_t sizeInBytes; ///< Size in bytes
+ UnownedStringSlice name; ///< The name associated with this type. NOTE! Currently these names *are* the GLSL format names.
+ };
+
+ const ImageFormatInfo& getImageFormatInfo(ImageFormat format);
+
bool findImageFormatByName(char const* name, ImageFormat* outFormat);
char const* getGLSLNameForImageFormat(ImageFormat format);
diff --git a/source/slang/slang-image-format-defs.h b/source/slang/slang-image-format-defs.h
index aa6ffec50..25dbae16a 100644
--- a/source/slang/slang-image-format-defs.h
+++ b/source/slang/slang-image-format-defs.h
@@ -3,45 +3,45 @@
#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)
+FORMAT(unknown, (NONE, 0, 0))
+FORMAT(rgba32f, (FLOAT32, 4, sizeof(float) * 4))
+FORMAT(rgba16f, (FLOAT16, 4, sizeof(uint16_t) * 4))
+FORMAT(rg32f, (FLOAT32, 2, sizeof(float) * 2))
+FORMAT(rg16f, (FLOAT16, 2, sizeof(uint16_t) * 2))
+FORMAT(r11f_g11f_b10f, (NONE, 3, sizeof(uint32_t)))
+FORMAT(r32f, (FLOAT32, 1, sizeof(float)))
+FORMAT(r16f, (FLOAT16, 1, sizeof(uint16_t)))
+FORMAT(rgba16, (UINT16, 4, sizeof(uint16_t) * 4))
+FORMAT(rgb10_a2, (NONE, 4, sizeof(uint32_t)))
+FORMAT(rgba8, (UINT8, 4, sizeof(uint32_t)))
+FORMAT(rg16, (UINT16, 2, sizeof(uint16_t) * 2 ))
+FORMAT(rg8, (UINT8, 2, sizeof(char) * 2))
+FORMAT(r16, (UINT16, 1, sizeof(uint16_t)))
+FORMAT(r8, (UINT8, 1, sizeof(uint8_t)))
+FORMAT(rgba16_snorm, (UINT16, 4, sizeof(uint16_t) * 4))
+FORMAT(rgba8_snorm, (UINT8, 4, sizeof(uint8_t) * 4))
+FORMAT(rg16_snorm, (UINT16, 2, sizeof(uint16_t) * 2))
+FORMAT(rg8_snorm, (UINT8, 2, sizeof(uint8_t) * 2))
+FORMAT(r16_snorm, (UINT16, 1, sizeof(uint16_t)))
+FORMAT(r8_snorm, (UINT8, 1, sizeof(uint8_t)))
+FORMAT(rgba32i, (INT32, 4, sizeof(int32_t) * 4))
+FORMAT(rgba16i, (INT16, 4, sizeof(int16_t) * 4))
+FORMAT(rgba8i, (INT8, 4, sizeof(int8_t) * 4))
+FORMAT(rg32i, (INT32, 2, sizeof(int32_t) * 2))
+FORMAT(rg16i, (INT16, 2, sizeof(int16_t) * 2))
+FORMAT(rg8i, (INT8, 2, sizeof(int8_t) * 2))
+FORMAT(r32i, (INT32, 1, sizeof(int32_t)))
+FORMAT(r16i, (INT16, 1, sizeof(int16_t)))
+FORMAT(r8i, (INT8, 1, sizeof(int8_t)))
+FORMAT(rgba32ui, (UINT32, 4, sizeof(uint32_t) * 4))
+FORMAT(rgba16ui, (UINT16, 4, sizeof(uint16_t) * 4))
+FORMAT(rgb10_a2ui, (NONE, 4, sizeof(uint32_t)))
+FORMAT(rgba8ui, (UINT8, 4, sizeof(uint8_t) * 4))
+FORMAT(rg32ui, (UINT32, 2, sizeof(uint32_t) * 2))
+FORMAT(rg16ui, (UINT16, 2, sizeof(uint16_t) * 2))
+FORMAT(rg8ui, (UINT8, 2, sizeof(uint8_t) * 2))
+FORMAT(r32ui, (UINT32, 1, sizeof(uint32_t)))
+FORMAT(r16ui, (UINT16, 1, sizeof(uint16_t)))
+FORMAT(r8ui, (UINT8, 1, sizeof(uint8_t)))
#undef FORMAT
diff --git a/source/slang/slang-intrinsic-expand.cpp b/source/slang/slang-intrinsic-expand.cpp
index c6cf65e5a..c1e886621 100644
--- a/source/slang/slang-intrinsic-expand.cpp
+++ b/source/slang/slang-intrinsic-expand.cpp
@@ -8,6 +8,7 @@ void IntrinsicExpandContext::emit(IRCall* inst, IRUse* args, Int argCount, const
m_args = args;
m_argCount = argCount;
m_text = intrinsicText;
+ m_callInst = inst;
const auto returnType = inst->getDataType();
@@ -59,6 +60,93 @@ void IntrinsicExpandContext::emit(IRCall* inst, IRUse* args, Int argCount, const
}
}
+static BaseType _getBaseTypeFromScalarType(SlangScalarType type)
+{
+ switch (type)
+ {
+ case SLANG_SCALAR_TYPE_INT32: return BaseType::Int;
+ case SLANG_SCALAR_TYPE_UINT32: return BaseType::UInt;
+ case SLANG_SCALAR_TYPE_INT16: return BaseType::Int16;
+ case SLANG_SCALAR_TYPE_UINT16: return BaseType::UInt16;
+ case SLANG_SCALAR_TYPE_INT64: return BaseType::Int64;
+ case SLANG_SCALAR_TYPE_UINT64: return BaseType::UInt64;
+ case SLANG_SCALAR_TYPE_INT8: return BaseType::Int8;
+ case SLANG_SCALAR_TYPE_UINT8: return BaseType::UInt8;
+ case SLANG_SCALAR_TYPE_FLOAT16: return BaseType::Half;
+ case SLANG_SCALAR_TYPE_FLOAT32: return BaseType::Float;
+ case SLANG_SCALAR_TYPE_FLOAT64: return BaseType::Double;
+ case SLANG_SCALAR_TYPE_BOOL: return BaseType::Bool;
+ default: return BaseType::Void;
+ }
+}
+
+// TODO(JS): There is an inherent problem here:
+//
+// TimF: The big gotcha you'd have with trying to look up the IRVar or whatever from an intrinsic is that it is very easy for the user to "smuggle" a resource-type value through an intermediate function:
+//
+// ```
+// Imagine this is user code...
+// void f(RWTexture2D t) { t.YourOpThatYouAdded(...); }[attributeYouCareAbout(...)]
+// RWTexture2D gTex;
+// ...
+// f(gTex);
+//
+// ```
+//
+// So when emitting IR code for f, there is no way to trace t back to gTex and get at[attributeYouCareAbout(...)]
+// Structurally, you can get back to the IRParam for t and that's it.
+// And even if there was some magic way to trace back through the call site, you would run into the problem that some call sites
+// might call f(gTex) and other might call f(gSomeOtherTex) and there is no guarantee the attributes on those two textures would match.
+//
+// The VK back-end gets away with this kind of coincidentally, since the "legalization" we have to do for resources means that there wouldn't be a single f() function any more.
+// But for CUDA and C++ that's not the case or generally desirable.
+
+IRFormatDecoration* _findImageFormatDecoration(IRInst* inst)
+{
+ // JS(TODO):
+ // There could perhaps be other situations, that need to be covered
+
+ // If this is a load, we need to get the decoration from the field key
+ if (IRLoad* load = as<IRLoad>(inst))
+ {
+ if (IRFieldAddress* fieldAddress = as<IRFieldAddress>(load->getOperand(0)))
+ {
+ IRInst* field = fieldAddress->getField();
+ return field->findDecoration<IRFormatDecoration>();
+ }
+ }
+ // Otherwise just try on the instruction
+ return inst->findDecoration<IRFormatDecoration>();
+}
+
+bool _isImageFormatCompatible(ImageFormat imageFormat, IRType* dataType)
+{
+ int numElems = 1;
+
+ if (auto vecType = as<IRVectorType>(dataType))
+ {
+ numElems = int(getIntVal(vecType->getElementCount()));
+ dataType = vecType->getElementType();
+ }
+
+ BaseType baseType = BaseType::Void;
+ if (auto basicType = as<IRBasicType>(dataType))
+ {
+ baseType = basicType->getBaseType();
+ }
+
+ const auto& imageFormatInfo = getImageFormatInfo(imageFormat);
+ const BaseType formatBaseType = _getBaseTypeFromScalarType(imageFormatInfo.scalarType);
+
+ if (numElems != imageFormatInfo.channelCount)
+ {
+ SLANG_ASSERT(!"Format doesn't match channel count");
+ return false;
+ }
+
+ return formatBaseType == baseType;
+}
+
const char* IntrinsicExpandContext::_emitSpecial(const char* cursor)
{
const char*const end = m_text.end();
@@ -168,6 +256,32 @@ const char* IntrinsicExpandContext::_emitSpecial(const char* cursor)
}
break;
+ case 'C':
+ {
+ // The $C intrinsic is a mechanism to change the name of an invocation depending on if there is a format
+ // conversion required between the type associated by the resource and the backing ImageFormat.
+ // Currently this is only implemented on CUDA, where there are specialized versions of the RWTexture
+ // writes that will do a format conversion.
+ if (m_emitter->getTarget() == CodeGenTarget::CUDASource)
+ {
+ IRInst* arg0 = m_callInst->getArg(0);
+
+ if (IRFormatDecoration* formatDecoration = _findImageFormatDecoration(arg0))
+ {
+ const ImageFormat imageFormat = formatDecoration->getFormat();
+ auto textureType = as<IRTextureTypeBase>(arg0->getDataType());
+ IRType* elementType = textureType ? textureType->getElementType() : nullptr;
+
+ if (elementType && ! _isImageFormatCompatible(imageFormat, elementType))
+ {
+ // Append _convert on the name to signify we need to use a code path, that will automatically
+ // do the format conversion.
+ m_writer->emit("_convert");
+ }
+ }
+ }
+ break;
+ }
case 'c':
{
// When doing texture access in glsl the result may need to be cast.
diff --git a/source/slang/slang-intrinsic-expand.h b/source/slang/slang-intrinsic-expand.h
index 468e1f80a..b52e3e8f5 100644
--- a/source/slang/slang-intrinsic-expand.h
+++ b/source/slang/slang-intrinsic-expand.h
@@ -24,6 +24,7 @@ protected:
SourceWriter* m_writer;
UnownedStringSlice m_text;
+ IRCall* m_callInst;
IRUse* m_args = nullptr;
Int m_argCount = 0;
Index m_openParenCount = 0;
diff --git a/source/slang/slang-syntax.cpp b/source/slang/slang-syntax.cpp
index d5f2c13db..6b2140056 100644
--- a/source/slang/slang-syntax.cpp
+++ b/source/slang/slang-syntax.cpp
@@ -1186,38 +1186,40 @@ Module* getModule(Decl* decl)
return moduleDecl->module;
}
-bool findImageFormatByName(char const* name, ImageFormat* outFormat)
+static const ImageFormatInfo kImageFormatInfos[] =
{
- static const struct
- {
- char const* name;
- ImageFormat format;
- } kFormats[] =
- {
-#define FORMAT(NAME) { #NAME, ImageFormat::NAME },
+#define SLANG_IMAGE_FORMAT_INFO(TYPE, COUNT, SIZE) SLANG_SCALAR_TYPE_##TYPE, uint8_t(COUNT), uint8_t(SIZE)
+#define FORMAT(NAME, OTHER) \
+ { SLANG_IMAGE_FORMAT_INFO OTHER, UnownedStringSlice::fromLiteral(#NAME) },
#include "slang-image-format-defs.h"
- };
+#undef FORMAT
+#undef SLANG_IMAGE_FORMAT_INFO
+};
- for( auto item : kFormats )
+bool findImageFormatByName(char const* inName, ImageFormat* outFormat)
+{
+ const UnownedStringSlice name(inName);
+
+ for (Index i = 0; i < SLANG_COUNT_OF(kImageFormatInfos); ++i)
{
- if( strcmp(item.name, name) == 0 )
+ const auto& info = kImageFormatInfos[i];
+ if (info.name == name)
{
- *outFormat = item.format;
+ *outFormat = ImageFormat(i);
return true;
}
}
-
return false;
}
char const* getGLSLNameForImageFormat(ImageFormat format)
{
- switch( format )
- {
- default: return "unhandled";
-#define FORMAT(NAME) case ImageFormat::NAME: return #NAME;
-#include "slang-image-format-defs.h"
- }
+ return kImageFormatInfos[Index(format)].name.begin();
}
+ const ImageFormatInfo& getImageFormatInfo(ImageFormat format)
+ {
+ return kImageFormatInfos[Index(format)];
+ }
+
} // namespace Slang