Repository: shader-slang/slang (C++)

Issue:
Metal issues with RWTexture objects of certain formats
Slang crashes within `libslang.dylib!Slang::legalizeIRForMetal(Slang::IRModule*, Slang::DiagnosticSink*)` when trying to create RWTexture for certain formats.

This came up writing a test in slang-rhi that copies from one texture to another using different texture types (1D, 2D, 3D) and various formats. For now the following formats lead to the mentioned crash:

- `RG8Uint`
- `RG8Sint`
- `RG8Unorm`
- `RG8Snorm`
- `RG16Uint`
- `RG16Sint`
- `RG16Unorm`
- `RG16Snorm`
- `RG16Float`
- `RG32Uint`
- `RG32Sint`
- `RG32Float`

The crash can be reproduced by running the `texture-view` test in slang-rhi with the following lines commented out:
https://github.com/shader-slang/slang-rhi/blob/main/tests/test-texture-view.cpp#L281-L299



Fix (patch):
diff --git a/source/core/list.h b/source/core/list.h
index 68563f20c6..6c4a04fc7b 100644
--- a/source/core/list.h
+++ b/source/core/list.h
@@ -4,6 +4,7 @@
 #include "allocator.h"
 #include "slang-math.h"
 #include "array-view.h"
+#include "slang-defines.h"
 
 #include <algorithm>
 #include <new>
@@ -29,6 +30,17 @@ namespace Slang
 				new (buffer + i) T();
 		}
 	};
+    template<typename T>
+    class Initializer<T, 1>
+    {
+    public:
+        static void Initialize(T * buffer, int size)
+        {
+            // It's pod so no initialization required
+            //for (int i = 0; i < size; i++)
+            //    new (buffer + i) T;
+        }
+    };
 
 	template<typename T, typename TAllocator>
 	class AllocateMethod
@@ -67,16 +79,6 @@ namespace Slang
 		}
 	};
 
-	template<typename T>
-	class Initializer<T, 1>
-	{
-	public:
-		static void Initialize(T * buffer, int size)
-		{
-			for (int i = 0; i<size; i++)
-				new (buffer + i) T;
-		}
-	};
 
 	template<typename T, typename TAllocator = StandardAllocator>
 	class List
@@ -201,10 +203,10 @@ namespace Slang
 			T* tmpBuffer = this->buffer;
 			this->buffer = other.buffer;
 			other.buffer = tmpBuffer;
-			int tmpBufferSize = this->bufferSize;
+			auto tmpBufferSize = this->bufferSize;
 			this->bufferSize = other.bufferSize;
 			other.bufferSize = tmpBufferSize;
-			int tmpCount = this->_count;
+			auto tmpCount = this->_count;
 			this->_count = other._count;
 			other._count = tmpCount;
 			TAllocator tmpAlloc = _Move(this->allocator);
@@ -468,15 +470,7 @@ namespace Slang
 			}
 		}
 
-#ifndef FORCE_INLINE
-#ifdef _MSC_VER
-#define FORCE_INLINE __forceinline
-#else
-#define FORCE_INLINE inline
-#endif
-#endif
-
-		FORCE_INLINE T & operator [](UInt id) const
+		SLANG_FORCE_INLINE T & operator [](UInt id) const
 		{
 #if _DEBUG
 			if(id >= _count)
diff --git a/source/core/slang-result.h b/source/core/slang-result.h
index da88c18b2b..767d2c737b 100644
--- a/source/core/slang-result.h
+++ b/source/core/slang-result.h
@@ -115,6 +115,8 @@ It can be useful to have a consistent short name for a facility, as used in the
 #define SLANG_RETURN_VOID_ON_FAIL(x) { SlangResult _res = (x); if (SLANG_FAILED(_res)) { SLANG_HANDLE_RESULT_FAIL(_res); return; } }
 //! Helper macro that will return false on failure.
 #define SLANG_RETURN_FALSE_ON_FAIL(x) { SlangResult _res = (x); if (SLANG_FAILED(_res)) { SLANG_HANDLE_RESULT_FAIL(_res); return false; } }
+//! Helper macro that will return nullptr on failure.
+#define SLANG_RETURN_NULL_ON_FAIL(x) { SlangResult _res = (x); if (SLANG_FAILED(_res)) { SLANG_HANDLE_RESULT_FAIL(_res); return nullptr; } }
 
 //! Helper macro that will assert if the return code from a call is failure, also returns the failure.
 #define SLANG_ASSERT_ON_FAIL(x) { SlangResult _res = (x); if (SLANG_FAILED(_res)) { assert(false); return _res; } }