summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2019-08-19 14:08:57 -0400
committerGitHub <noreply@github.com>2019-08-19 14:08:57 -0400
commitdc6d0417b137c8ecdcb3b99b7624358bba7fefa8 (patch)
tree326fe7f93b08431685c6b01052c2eee18168776b
parentc4541e83b4a57d8317932bc4277ee6a2d45bb2f6 (diff)
WIP: Compute test running on CPU (#1023)
* * Simplify some of test code around CPPCompiler * Test using 'callable' with pass-through * Small cpu doc improvements * Improvements to Clang output parsing. * Remove temporary file (base filename) . * Improve handling of external errors - handle severity. * On error dumping out to 'actual' file for runCPPCompilerCompile. * Small fixes. Set the source language type correctly for pass thru. * Remove warning for test for clang backend c * Preliminary work around making render-test compute potentiall work with CPU. Made ShaderCompiler -> a stateless ShaderCompilerUtil. Means we don't require a Renderer interface to do shader compilation. * Refactor such that CPU test can take place in without Window or Renderer. * Hack to look for prelude in source file directory. Fix bug returning the SharedLibrary for HostCallable. * Compute test running on CPU. * Need the prelude currently in same directly as test. * Hack to remove warning - that then produces an error on appveyor build. Disable running render CPU test on non-windows. * Improve handling of disabling CPU tests on linux. * Added bit-cast.slang working on CPU.
-rw-r--r--source/core/slang-render-api-util.cpp8
-rw-r--r--source/core/slang-render-api-util.h2
-rw-r--r--source/slang/slang-compiler.cpp38
-rw-r--r--tests/compute/array-param.slang4
-rw-r--r--tests/compute/bit-cast.slang3
-rw-r--r--tests/compute/slang-cpp-prelude.h826
-rw-r--r--tests/cross-compile/slang-cpp-prelude.h5
-rw-r--r--tools/gfx/render.cpp2
-rw-r--r--tools/gfx/render.h2
-rw-r--r--tools/render-test/options.cpp1
-rw-r--r--tools/render-test/render-test-main.cpp643
-rw-r--r--tools/render-test/shader-input-layout.cpp30
-rw-r--r--tools/render-test/shader-input-layout.h7
-rw-r--r--tools/render-test/slang-support.cpp49
-rw-r--r--tools/render-test/slang-support.h55
-rw-r--r--tools/slang-test/options.h2
-rw-r--r--tools/slang-test/slang-test-main.cpp16
17 files changed, 1499 insertions, 194 deletions
diff --git a/source/core/slang-render-api-util.cpp b/source/core/slang-render-api-util.cpp
index d8bcaf396..a9339c14e 100644
--- a/source/core/slang-render-api-util.cpp
+++ b/source/core/slang-render-api-util.cpp
@@ -17,6 +17,7 @@ namespace Slang {
{ RenderApiType::Vulkan, "vk,vulkan", ""},
{ RenderApiType::D3D12, "dx12,d3d12", ""},
{ RenderApiType::D3D11, "dx11,d3d11", "hlsl,hlsl-rewrite,slang"},
+ { RenderApiType::CPU, "cpu", ""},
};
static int _calcAvailableApis()
@@ -265,7 +266,8 @@ static bool _canLoadSharedLibrary(const char* libName)
case RenderApiType::OpenGl: return _canLoadSharedLibrary("opengl32");
case RenderApiType::Vulkan: return _canLoadSharedLibrary("vulkan-1");
case RenderApiType::D3D11: return _canLoadSharedLibrary("d3d11");
- case RenderApiType::D3D12: return _canLoadSharedLibrary("d3d12");
+ case RenderApiType::D3D12: return _canLoadSharedLibrary("d3d12");
+ case RenderApiType::CPU: return true;
default: break;
}
#elif SLANG_UNIX_FAMILY
@@ -277,6 +279,10 @@ static bool _canLoadSharedLibrary(const char* libName)
{
return true;
}
+ case RenderApiType::CPU:
+ {
+ return true;
+ }
default: break;
}
#endif
diff --git a/source/core/slang-render-api-util.h b/source/core/slang-render-api-util.h
index fbdd3930c..48b599653 100644
--- a/source/core/slang-render-api-util.h
+++ b/source/core/slang-render-api-util.h
@@ -15,6 +15,7 @@ enum class RenderApiType
Vulkan,
D3D12,
D3D11,
+ CPU,
CountOf,
};
@@ -27,6 +28,7 @@ struct RenderApiFlag
Vulkan = 1 << int(RenderApiType::Vulkan),
D3D12 = 1 << int(RenderApiType::D3D12),
D3D11 = 1 << int(RenderApiType::D3D11),
+ CPU = 1 << int(RenderApiType::CPU),
AllOf = (1 << int(RenderApiType::CountOf)) - 1 ///< All bits set
};
};
diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp
index a88881b9d..75cd61bf9 100644
--- a/source/slang/slang-compiler.cpp
+++ b/source/slang/slang-compiler.cpp
@@ -561,6 +561,21 @@ namespace Slang
return translationUnit;
}
+ static TranslationUnitRequest* _getTranslationUnit(
+ EndToEndCompileRequest* endToEndReq,
+ Int entryPointIndex)
+ {
+ // If there isn't an end-to-end compile going on,
+ // there can be no pass-through.
+ //
+ if (!endToEndReq) return nullptr;
+
+ auto frontEndReq = endToEndReq->getFrontEndReq();
+ auto entryPointReq = frontEndReq->getEntryPointReq(entryPointIndex);
+ auto translationUnit = entryPointReq->getTranslationUnit();
+ return translationUnit;
+ }
+
static void _appendEscapedPath(const UnownedStringSlice& path, StringBuilder& outBuilder)
{
for (auto c : path)
@@ -1301,6 +1316,28 @@ SlangResult dissassembleDXILUsingDXC(
}
else
{
+ // TODO(JS): This is a hack for two reasons
+ // * That we just inject the source path for C/C++ include paths if we find the file
+ // * We should access the files through the ISlangFileSystem
+
+ translationUnit = _getTranslationUnit(endToEndReq, entryPointIndex);
+
+ const auto& sourceFiles = translationUnit->getSourceFiles();
+ if (sourceFiles.getCount() == 1)
+ {
+ const SourceFile* sourceFile = sourceFiles[0];
+ const PathInfo& pathInfo = sourceFile->getPathInfo();
+ if (pathInfo.type == PathInfo::Type::FoundPath || pathInfo.type == PathInfo::Type::Normal || pathInfo.type == PathInfo::Type::FromString)
+ {
+ String canonicalPath;
+ if (File::exists(pathInfo.foundPath) && SLANG_SUCCEEDED(Path::getCanonical(pathInfo.foundPath, canonicalPath)))
+ {
+ String sourceDir = Path::getParentDirectory(canonicalPath);
+ includePaths.add(sourceDir);
+ }
+ }
+ }
+
rawSource = emitCPPForEntryPoint(
slangRequest,
entryPoint,
@@ -1547,6 +1584,7 @@ SlangResult dissassembleDXILUsingDXC(
sharedLib->m_temporaryFileSet = productFileSet;
productFileSet.clear();
+ // Output the shared library
outSharedLib = sharedLib;
}
else
diff --git a/tests/compute/array-param.slang b/tests/compute/array-param.slang
index deead3aeb..1f3ff9799 100644
--- a/tests/compute/array-param.slang
+++ b/tests/compute/array-param.slang
@@ -1,10 +1,12 @@
+//TEST(compute):COMPARE_COMPUTE_EX:-cpu -compute
//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute
//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -dx12
//TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute
-//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):dxbinding(0),glbinding(0),out
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):dxbinding(0),glbinding(0),out,name outputBuffer
RWStructuredBuffer<int> outputBuffer;
+
void writeArray(inout float3 a[4])
{
a[0] = float3(1, 1, 1);
diff --git a/tests/compute/bit-cast.slang b/tests/compute/bit-cast.slang
index a6c4813f0..9859cc568 100644
--- a/tests/compute/bit-cast.slang
+++ b/tests/compute/bit-cast.slang
@@ -1,8 +1,9 @@
+//TEST(compute):COMPARE_COMPUTE_EX:-cpu -compute
//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute
//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -dx12
//TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute
-//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0], stride=4):dxbinding(0),glbinding(0),out
+//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0], stride=4):dxbinding(0),glbinding(0),out,name outputBuffer
RWStructuredBuffer<int> outputBuffer;
diff --git a/tests/compute/slang-cpp-prelude.h b/tests/compute/slang-cpp-prelude.h
new file mode 100644
index 000000000..f1d6919f0
--- /dev/null
+++ b/tests/compute/slang-cpp-prelude.h
@@ -0,0 +1,826 @@
+#ifndef SLANG_CPP_PRELUDE_H
+#define SLANG_CPP_PRELUDE_H
+
+/* --------------- START From slang.h ----------------- */
+
+#ifndef SLANG_COMPILER
+# define SLANG_COMPILER
+
+/*
+Compiler defines, see http://sourceforge.net/p/predef/wiki/Compilers/
+NOTE that SLANG_VC holds the compiler version - not just 1 or 0
+*/
+# if defined(_MSC_VER)
+# if _MSC_VER >= 1900
+# define SLANG_VC 14
+# elif _MSC_VER >= 1800
+# define SLANG_VC 12
+# elif _MSC_VER >= 1700
+# define SLANG_VC 11
+# elif _MSC_VER >= 1600
+# define SLANG_VC 10
+# elif _MSC_VER >= 1500
+# define SLANG_VC 9
+# else
+# error "unknown version of Visual C++ compiler"
+# endif
+# elif defined(__clang__)
+# define SLANG_CLANG 1
+# elif defined(__SNC__)
+# define SLANG_SNC 1
+# elif defined(__ghs__)
+# define SLANG_GHS 1
+# elif defined(__GNUC__) /* note: __clang__, __SNC__, or __ghs__ imply __GNUC__ */
+# define SLANG_GCC 1
+# else
+# error "unknown compiler"
+# endif
+/*
+Any compilers not detected by the above logic are now now explicitly zeroed out.
+*/
+# ifndef SLANG_VC
+# define SLANG_VC 0
+# endif
+# ifndef SLANG_CLANG
+# define SLANG_CLANG 0
+# endif
+# ifndef SLANG_SNC
+# define SLANG_SNC 0
+# endif
+# ifndef SLANG_GHS
+# define SLANG_GHS 0
+# endif
+# ifndef SLANG_GCC
+# define SLANG_GCC 0
+# endif
+#endif /* SLANG_COMPILER */
+
+/*
+The following section attempts to detect the target platform being compiled for.
+
+If an application defines `SLANG_PLATFORM` before including this header,
+they take responsibility for setting any compiler-dependent macros
+used later in the file.
+
+Most applications should not need to touch this section.
+*/
+#ifndef SLANG_PLATFORM
+# define SLANG_PLATFORM
+/**
+Operating system defines, see http://sourceforge.net/p/predef/wiki/OperatingSystems/
+*/
+# if defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_PARTITION_APP
+# define SLANG_WINRT 1 /* Windows Runtime, either on Windows RT or Windows 8 */
+# elif defined(XBOXONE)
+# define SLANG_XBOXONE 1
+# elif defined(_WIN64) /* note: XBOXONE implies _WIN64 */
+# define SLANG_WIN64 1
+# elif defined(_M_PPC)
+# define SLANG_X360 1
+# elif defined(_WIN32) /* note: _M_PPC implies _WIN32 */
+# define SLANG_WIN32 1
+# elif defined(__ANDROID__)
+# define SLANG_ANDROID 1
+# elif defined(__linux__) || defined(__CYGWIN__) /* note: __ANDROID__ implies __linux__ */
+# define SLANG_LINUX 1
+# elif defined(__APPLE__) && (defined(__arm__) || defined(__arm64__))
+# define SLANG_IOS 1
+# elif defined(__APPLE__)
+# define SLANG_OSX 1
+# elif defined(__CELLOS_LV2__)
+# define SLANG_PS3 1
+# elif defined(__ORBIS__)
+# define SLANG_PS4 1
+# elif defined(__SNC__) && defined(__arm__)
+# define SLANG_PSP2 1
+# elif defined(__ghs__)
+# define SLANG_WIIU 1
+# else
+# error "unknown target platform"
+# endif
+/*
+Any platforms not detected by the above logic are now now explicitly zeroed out.
+*/
+# ifndef SLANG_WINRT
+# define SLANG_WINRT 0
+# endif
+# ifndef SLANG_XBOXONE
+# define SLANG_XBOXONE 0
+# endif
+# ifndef SLANG_WIN64
+# define SLANG_WIN64 0
+# endif
+# ifndef SLANG_X360
+# define SLANG_X360 0
+# endif
+# ifndef SLANG_WIN32
+# define SLANG_WIN32 0
+# endif
+# ifndef SLANG_ANDROID
+# define SLANG_ANDROID 0
+# endif
+# ifndef SLANG_LINUX
+# define SLANG_LINUX 0
+# endif
+# ifndef SLANG_IOS
+# define SLANG_IOS 0
+# endif
+# ifndef SLANG_OSX
+# define SLANG_OSX 0
+# endif
+# ifndef SLANG_PS3
+# define SLANG_PS3 0
+# endif
+# ifndef SLANG_PS4
+# define SLANG_PS4 0
+# endif
+# ifndef SLANG_PSP2
+# define SLANG_PSP2 0
+# endif
+# ifndef SLANG_WIIU
+# define SLANG_WIIU 0
+# endif
+#endif /* SLANG_PLATFORM */
+
+/* Shorthands for "families" of compilers/platforms */
+#define SLANG_GCC_FAMILY (SLANG_CLANG || SLANG_SNC || SLANG_GHS || SLANG_GCC)
+#define SLANG_WINDOWS_FAMILY (SLANG_WINRT || SLANG_WIN32 || SLANG_WIN64)
+#define SLANG_MICROSOFT_FAMILY (SLANG_XBOXONE || SLANG_X360 || SLANG_WINDOWS_FAMILY)
+#define SLANG_LINUX_FAMILY (SLANG_LINUX || SLANG_ANDROID)
+#define SLANG_APPLE_FAMILY (SLANG_IOS || SLANG_OSX) /* equivalent to #if __APPLE__ */
+#define SLANG_UNIX_FAMILY (SLANG_LINUX_FAMILY || SLANG_APPLE_FAMILY) /* shortcut for unix/posix platforms */
+
+/* Macro for declaring if a method is no throw. Should be set before the return parameter. */
+#ifndef SLANG_NO_THROW
+# if SLANG_WINDOWS_FAMILY && !defined(SLANG_DISABLE_EXCEPTIONS)
+# define SLANG_NO_THROW __declspec(nothrow)
+# endif
+#endif
+#ifndef SLANG_NO_THROW
+# define SLANG_NO_THROW
+#endif
+
+/* The `SLANG_STDCALL` and `SLANG_MCALL` defines are used to set the calling
+convention for interface methods.
+*/
+#ifndef SLANG_STDCALL
+# if SLANG_MICROSOFT_FAMILY
+# define SLANG_STDCALL __stdcall
+# else
+# define SLANG_STDCALL
+# endif
+#endif
+#ifndef SLANG_MCALL
+# define SLANG_MCALL SLANG_STDCALL
+#endif
+
+
+#if !defined(SLANG_STATIC) && !defined(SLANG_STATIC)
+ #define SLANG_DYNAMIC
+#endif
+
+#if defined(_MSC_VER)
+# define SLANG_DLL_EXPORT __declspec(dllexport)
+#else
+# define SLANG_DLL_EXPORT __attribute__((__visibility__("default")))
+#endif
+
+#if defined(SLANG_DYNAMIC)
+# if defined(_MSC_VER)
+# ifdef SLANG_DYNAMIC_EXPORT
+# define SLANG_API SLANG_DLL_EXPORT
+# else
+# define SLANG_API __declspec(dllimport)
+# endif
+# else
+ // TODO: need to consider compiler capabilities
+//# ifdef SLANG_DYNAMIC_EXPORT
+# define SLANG_API SLANG_DLL_EXPORT
+//# endif
+# endif
+#endif
+
+#ifndef SLANG_API
+# define SLANG_API
+#endif
+
+// GCC Specific
+#if SLANG_GCC_FAMILY
+// This doesn't work on clang - because the typedef is seen as multiply defined, use the line numbered version defined later
+# if !defined(__clang__) && (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) || defined(__ORBIS__))
+# define SLANG_COMPILE_TIME_ASSERT(exp) typedef char SlangCompileTimeAssert_Dummy[(exp) ? 1 : -1] __attribute__((unused))
+# endif
+
+# define SLANG_NO_INLINE __attribute__((noinline))
+# define SLANG_FORCE_INLINE inline __attribute__((always_inline))
+# define SLANG_BREAKPOINT(id) __builtin_trap();
+# define SLANG_ALIGN_OF(T) __alignof__(T)
+
+// Use this macro instead of offsetof, because gcc produces warning if offsetof is used on a
+// non POD type, even though it produces the correct result
+# define SLANG_OFFSET_OF(T, ELEMENT) (size_t(&((T*)1)->ELEMENT) - 1)
+#endif // SLANG_GCC_FAMILY
+
+// Microsoft VC specific
+#if SLANG_MICROSOFT_FAMILY
+# define SLANG_NO_INLINE __declspec(noinline)
+# define SLANG_FORCE_INLINE __forceinline
+# define SLANG_BREAKPOINT(id) __debugbreak();
+# define SLANG_ALIGN_OF(T) __alignof(T)
+
+# define SLANG_INT64(x) (x##i64)
+# define SLANG_UINT64(x) (x##ui64)
+#endif // SLANG_MICROSOFT_FAMILY
+
+#ifndef SLANG_FORCE_INLINE
+# define SLANG_FORCE_INLINE inline
+#endif
+#ifndef SLANG_NO_INLINE
+# define SLANG_NO_INLINE
+#endif
+
+#ifndef SLANG_COMPILE_TIME_ASSERT
+# define SLANG_COMPILE_TIME_ASSERT(exp) typedef char SLANG_CONCAT(SlangCompileTimeAssert,__LINE__)[(exp) ? 1 : -1]
+#endif
+
+#ifndef SLANG_OFFSET_OF
+# define SLANG_OFFSET_OF(X, Y) offsetof(X, Y)
+#endif
+
+#ifndef SLANG_BREAKPOINT
+// Make it crash with a write to 0!
+# define SLANG_BREAKPOINT(id) (*((int*)0) = int(id));
+#endif
+
+// Use for getting the amount of members of a standard C array.
+#define SLANG_COUNT_OF(x) (sizeof(x)/sizeof(x[0]))
+/// SLANG_INLINE exists to have a way to inline consistent with SLANG_ALWAYS_INLINE
+#define SLANG_INLINE inline
+
+// Other defines
+#define SLANG_STRINGIZE_HELPER(X) #X
+#define SLANG_STRINGIZE(X) SLANG_STRINGIZE_HELPER(X)
+
+#define SLANG_CONCAT_HELPER(X, Y) X##Y
+#define SLANG_CONCAT(X, Y) SLANG_CONCAT_HELPER(X, Y)
+
+#ifndef SLANG_UNUSED
+# define SLANG_UNUSED(v) (void)v;
+#endif
+
+// Used for doing constant literals
+#ifndef SLANG_INT64
+# define SLANG_INT64(x) (x##ll)
+#endif
+#ifndef SLANG_UINT64
+# define SLANG_UINT64(x) (x##ull)
+#endif
+
+
+#ifdef __cplusplus
+# define SLANG_EXTERN_C extern "C"
+#else
+# define SLANG_EXTERN_C
+#endif
+
+#ifdef __cplusplus
+// C++ specific macros
+// Clang
+#if SLANG_CLANG
+# if (__clang_major__*10 + __clang_minor__) >= 33
+# define SLANG_HAS_MOVE_SEMANTICS 1
+# define SLANG_HAS_ENUM_CLASS 1
+# define SLANG_OVERRIDE override
+# endif
+// Gcc
+#elif SLANG_GCC_FAMILY
+// Check for C++11
+# if (__cplusplus >= 201103L)
+# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 405
+# define SLANG_HAS_MOVE_SEMANTICS 1
+# endif
+# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 406
+# define SLANG_HAS_ENUM_CLASS 1
+# endif
+# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 407
+# define SLANG_OVERRIDE override
+# endif
+# endif
+# endif // SLANG_GCC_FAMILY
+
+// Visual Studio
+
+# if SLANG_VC
+// C4481: nonstandard extension used: override specifier 'override'
+# if _MSC_VER < 1700
+# pragma warning(disable : 4481)
+# endif
+# define SLANG_OVERRIDE override
+# if _MSC_VER >= 1600
+# define SLANG_HAS_MOVE_SEMANTICS 1
+# endif
+# if _MSC_VER >= 1700
+# define SLANG_HAS_ENUM_CLASS 1
+# endif
+
+# endif // SLANG_VC
+
+// Set non set
+# ifndef SLANG_OVERRIDE
+# define SLANG_OVERRIDE
+# endif
+# ifndef SLANG_HAS_ENUM_CLASS
+# define SLANG_HAS_ENUM_CLASS 0
+# endif
+# ifndef SLANG_HAS_MOVE_SEMANTICS
+# define SLANG_HAS_MOVE_SEMANTICS 0
+# endif
+
+#endif // __cplusplus
+
+/* Macros for detecting processor */
+#if defined(_M_ARM) || defined(__ARM_EABI__)
+// This is special case for nVidia tegra
+# define SLANG_PROCESSOR_ARM 1
+#elif defined(__i386__) || defined(_M_IX86)
+# define SLANG_PROCESSOR_X86 1
+#elif defined(_M_AMD64) || defined(_M_X64) || defined(__amd64) || defined(__x86_64)
+# define SLANG_PROCESSOR_X86_64 1
+#elif defined(_PPC_) || defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC)
+# if defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__) || defined(__64BIT__) || defined(_LP64) || defined(__LP64__)
+# define SLANG_PROCESSOR_POWER_PC_64 1
+# else
+# define SLANG_PROCESSOR_POWER_PC 1
+# endif
+#elif defined(__arm__)
+# define SLANG_PROCESSOR_ARM 1
+#elif defined(__aarch64__)
+# define SLANG_PROCESSOR_ARM_64 1
+#endif
+
+#ifndef SLANG_PROCESSOR_ARM
+# define SLANG_PROCESSOR_ARM 0
+#endif
+
+#ifndef SLANG_PROCESSOR_ARM_64
+# define SLANG_PROCESSOR_ARM_64 0
+#endif
+
+#ifndef SLANG_PROCESSOR_X86
+# define SLANG_PROCESSOR_X86 0
+#endif
+
+#ifndef SLANG_PROCESSOR_X86_64
+# define SLANG_PROCESSOR_X86_64 0
+#endif
+
+#ifndef SLANG_PROCESSOR_POWER_PC
+# define SLANG_PROCESSOR_POWER_PC 0
+#endif
+
+#ifndef SLANG_PROCESSOR_POWER_PC_64
+# define SLANG_PROCESSOR_POWER_PC_64 0
+#endif
+
+// Processor families
+
+#define SLANG_PROCESSOR_FAMILY_X86 (SLANG_PROCESSOR_X86_64 | SLANG_PROCESSOR_X86)
+#define SLANG_PROCESSOR_FAMILY_ARM (SLANG_PROCESSOR_ARM | SLANG_PROCESSOR_ARM_64)
+#define SLANG_PROCESSOR_FAMILY_POWER_PC (SLANG_PROCESSOR_POWER_PC_64 | SLANG_PROCESSOR_POWER_PC)
+
+// Pointer size
+#define SLANG_PTR_IS_64 (SLANG_PROCESSOR_ARM_64 | SLANG_PROCESSOR_X86_64 | SLANG_PROCESSOR_POWER_PC_64)
+#define SLANG_PTR_IS_32 (SLANG_PTR_IS_64 ^ 1)
+
+// Processor features
+#if SLANG_PROCESSOR_FAMILY_X86
+# define SLANG_LITTLE_ENDIAN 1
+# define SLANG_UNALIGNED_ACCESS 1
+#elif SLANG_PROCESSOR_FAMILY_ARM
+# if defined(__ARMEB__)
+# define SLANG_BIG_ENDIAN 1
+# else
+# define SLANG_LITTLE_ENDIAN 1
+# endif
+#elif SLANG_PROCESSOR_FAMILY_POWER_PC
+# define SLANG_BIG_ENDIAN 1
+#endif
+
+#ifndef SLANG_LITTLE_ENDIAN
+# define SLANG_LITTLE_ENDIAN 0
+#endif
+
+#ifndef SLANG_BIG_ENDIAN
+# define SLANG_BIG_ENDIAN 0
+#endif
+
+#ifndef SLANG_UNALIGNED_ACCESS
+# define SLANG_UNALIGNED_ACCESS 0
+#endif
+
+// One endianess must be set
+#if ((SLANG_BIG_ENDIAN | SLANG_LITTLE_ENDIAN) == 0)
+# error "Couldn't determine endianess"
+#endif
+
+#ifndef SLANG_NO_INTTYPES
+#include <inttypes.h>
+#endif // ! SLANG_NO_INTTYPES
+
+#ifndef SLANG_NO_STDDEF
+#include <stddef.h>
+#endif // ! SLANG_NO_STDDEF
+
+/* --------------- END From slang.h ----------------- */
+
+// TODO(JS): Hack! Output C++ code from slang can copy unitialized variables.
+#if SLANG_VC
+# pragma warning(disable : 4700)
+#endif
+
+#include <math.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#ifndef SLANG_PRELUDE_PI
+# define SLANG_PRELUDE_PI 3.14159265358979323846
+#endif
+
+#if defined(_MSC_VER)
+# define SLANG_PRELUDE_SHARED_LIB_EXPORT __declspec(dllexport)
+#else
+# define SLANG_PRELUDE_SHARED_LIB_EXPORT __attribute__((__visibility__("default")))
+//# define SLANG_PRELUDE_SHARED_LIB_EXPORT __attribute__ ((dllexport)) __attribute__((__visibility__("default")))
+#endif
+
+#ifdef __cplusplus
+# define SLANG_PRELUDE_EXTERN_C extern "C"
+#else
+# define SLANG_PRELUDE_EXTERN_C
+#endif
+
+#define SLANG_PRELUDE_EXPORT SLANG_PRELUDE_EXTERN_C SLANG_PRELUDE_SHARED_LIB_EXPORT
+
+#ifdef SLANG_PRELUDE_NAMESPACE
+namespace SLANG_PRELUDE_NAMESPACE {
+#endif
+
+
+template <typename T, size_t SIZE>
+struct FixedArray
+{
+ const T& operator[](size_t index) const { assert(index < SIZE); return m_data[index]; }
+ T& operator[](size_t index) { assert(index < SIZE); return m_data[index]; }
+
+ T m_data[SIZE];
+};
+
+
+// Hmm... I guess a constant buffer should be unwrapped to be just a struct passed in
+/* template <typename T>
+struct ConstantBuffer
+{
+}; */
+
+template <typename T, int COUNT>
+struct Vector;
+
+template <typename T>
+struct Vector<T, 1>
+{
+ T x;
+};
+
+template <typename T>
+struct Vector<T, 2>
+{
+ T x, y;
+};
+
+template <typename T>
+struct Vector<T, 3>
+{
+ T x, y, z;
+};
+
+template <typename T>
+struct Vector<T, 4>
+{
+ T x, y, z, w;
+};
+
+
+typedef Vector<float, 2> float2;
+typedef Vector<float, 3> float3;
+typedef Vector<float, 4> float4;
+
+typedef Vector<int32_t, 2> int2;
+typedef Vector<int32_t, 3> int3;
+typedef Vector<int32_t, 4> int4;
+
+typedef Vector<uint32_t, 2> uint2;
+typedef Vector<uint32_t, 3> uint3;
+typedef Vector<uint32_t, 4> uint4;
+
+template <typename T, int ROWS, int COLS>
+struct Matrix
+{
+ Vector<T, COLS> rows[ROWS];
+};
+
+// ----------------------------- ResourceType -----------------------------------------
+
+// https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/sm5-object-structuredbuffer-getdimensions
+// Missing Load(_In_ int Location, _Out_ uint Status);
+
+template <typename T>
+struct RWStructuredBuffer
+{
+ T& operator[](size_t index) const { assert(index < count); return data[index]; }
+ const T& Load(size_t index) const { assert(index < count); return data[index]; }
+ void GetDimensions(uint32_t& outNumStructs, uint32_t& outStride) { outNumStructs = uint32_t(count); outStride = uint32_t(sizeof(T)); }
+
+ T* data;
+ size_t count;
+};
+
+template <typename T>
+struct StructuredBuffer
+{
+ const T& operator[](size_t index) const { assert(index < count); return data[index]; }
+ const T& Load(size_t index) const { assert(index < count); return data[index]; }
+ void GetDimensions(uint32_t& outNumStructs, uint32_t& outStride) { outNumStructs = uint32_t(count); outStride = uint32_t(sizeof(T)); }
+
+ T* data;
+ size_t count;
+};
+
+// Missing Load(_In_ int Location, _Out_ uint Status);
+struct ByteAddressBuffer
+{
+ void GetDimensions(uint32_t& outDim) const { outDim = uint32_t(sizeInBytes); }
+ uint32_t Load(size_t index) const
+ {
+ assert(index + 4 <= sizeInBytes && (index & 3) == 0);
+ return data[index >> 2];
+ }
+ uint2 Load2(size_t index) const
+ {
+ assert(index + 8 <= sizeInBytes && (index & 3) == 0);
+ const size_t dataIdx = index >> 2;
+ return uint2{data[dataIdx], data[dataIdx + 1]};
+ }
+ uint3 Load3(size_t index) const
+ {
+ assert(index + 12 <= sizeInBytes && (index & 3) == 0);
+ const size_t dataIdx = index >> 2;
+ return uint3{data[dataIdx], data[dataIdx + 1], data[dataIdx + 2]};
+ }
+ uint4 Load4(size_t index) const
+ {
+ assert(index + 16 <= sizeInBytes && (index & 3) == 0);
+ const size_t dataIdx = index >> 2;
+ return uint4{data[dataIdx], data[dataIdx + 1], data[dataIdx + 2], data[dataIdx + 3]};
+ }
+
+ const uint32_t* data;
+ size_t sizeInBytes; //< Must be multiple of 4
+};
+
+// https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/sm5-object-rwbyteaddressbuffer
+// Missing support for Atomic operations
+// Missing support for Load with status
+struct RWByteAddressBuffer
+{
+ void GetDimensions(uint32_t& outDim) const { outDim = uint32_t(sizeInBytes); }
+
+ uint32_t Load(size_t index) const
+ {
+ assert(index + 4 <= sizeInBytes && (index & 3) == 0);
+ return data[index >> 2];
+ }
+ uint2 Load2(size_t index) const
+ {
+ assert(index + 8 <= sizeInBytes && (index & 3) == 0);
+ const size_t dataIdx = index >> 2;
+ return uint2{data[dataIdx], data[dataIdx + 1]};
+ }
+ uint3 Load3(size_t index) const
+ {
+ assert(index + 12 <= sizeInBytes && (index & 3) == 0);
+ const size_t dataIdx = index >> 2;
+ return uint3{data[dataIdx], data[dataIdx + 1], data[dataIdx + 2]};
+ }
+ uint4 Load4(size_t index) const
+ {
+ assert(index + 16 <= sizeInBytes && (index & 3) == 0);
+ const size_t dataIdx = index >> 2;
+ return uint4{data[dataIdx], data[dataIdx + 1], data[dataIdx + 2], data[dataIdx + 3]};
+ }
+
+ void Store(size_t index, uint32_t v) const
+ {
+ assert(index + 4 <= sizeInBytes && (index & 3) == 0);
+ data[index >> 2] = v;
+ }
+ void Store2(size_t index, uint2 v) const
+ {
+ assert(index + 8 <= sizeInBytes && (index & 3) == 0);
+ const size_t dataIdx = index >> 2;
+ data[dataIdx + 0] = v.x;
+ data[dataIdx + 1] = v.y;
+ }
+ void Store3(size_t index, uint3 v) const
+ {
+ assert(index + 12 <= sizeInBytes && (index & 3) == 0);
+ const size_t dataIdx = index >> 2;
+ data[dataIdx + 0] = v.x;
+ data[dataIdx + 1] = v.y;
+ data[dataIdx + 2] = v.z;
+ }
+ void Store4(size_t index, uint4 v) const
+ {
+ assert(index + 16 <= sizeInBytes && (index & 3) == 0);
+ const size_t dataIdx = index >> 2;
+ data[dataIdx + 0] = v.x;
+ data[dataIdx + 1] = v.y;
+ data[dataIdx + 2] = v.z;
+ data[dataIdx + 3] = v.w;
+ }
+
+ uint32_t* data;
+ size_t sizeInBytes; //< Must be multiple of 4
+};
+
+struct ISamplerState;
+struct ISamplerComparisonState;
+
+struct SamplerState
+{
+ ISamplerState* state;
+};
+
+struct SamplerComparisonState
+{
+ ISamplerComparisonState* state;
+};
+
+// Texture
+
+struct ITexture2D
+{
+ virtual void Load(const int3& v, void* out) = 0;
+ virtual void Sample(SamplerState samplerState, const float2& loc, void* out) = 0;
+};
+
+template <typename T>
+struct Texture2D
+{
+ T Load(const int3& v) const { T out; texture->Load(v, &out); return out; }
+ T Sample(SamplerState samplerState, const float2& v) const { T out; texture->Sample(samplerState, v, &out); return out; }
+
+ ITexture2D* texture;
+};
+
+/* Varing input for Compute */
+
+struct ComputeVaryingInput
+{
+ uint3 groupID;
+ uint3 groupThreadID;
+};
+
+// ----------------------------- F32 -----------------------------------------
+
+union Union32
+{
+ uint32_t u;
+ int32_t i;
+ float f;
+};
+
+// Helpers
+SLANG_FORCE_INLINE float F32_calcSafeRadians(float radians)
+{
+ float a = radians * (1.0f / float(SLANG_PRELUDE_PI));
+ a = (a < 0.0f) ? (::ceilf(a) - a) : (a - ::floorf(a));
+ return (a * float(SLANG_PRELUDE_PI));
+}
+
+// Unary
+SLANG_FORCE_INLINE float F32_ceil(float f) { return ::ceilf(f); }
+SLANG_FORCE_INLINE float F32_floor(float f) { return ::floorf(f); }
+SLANG_FORCE_INLINE float F32_sin(float f) { return ::sinf(F32_calcSafeRadians(f)); }
+SLANG_FORCE_INLINE float F32_cos(float f) { return ::cosf(F32_calcSafeRadians(f)); }
+SLANG_FORCE_INLINE float F32_tan(float f) { return ::tanf(f); }
+SLANG_FORCE_INLINE float F32_asin(float f) { return ::asinf(f); }
+SLANG_FORCE_INLINE float F32_acos(float f) { return ::acosf(f); }
+SLANG_FORCE_INLINE float F32_atan(float f) { return ::atanf(f); }
+SLANG_FORCE_INLINE float F32_log2(float f) { return ::log2f(f); }
+SLANG_FORCE_INLINE float F32_exp2(float f) { return ::exp2f(f); }
+SLANG_FORCE_INLINE float F32_exp(float f) { return ::expf(f); }
+SLANG_FORCE_INLINE float F32_abs(float f) { return ::fabsf(f); }
+SLANG_FORCE_INLINE float F32_trunc(float f) { return ::truncf(f); }
+SLANG_FORCE_INLINE float F32_sqrt(float f) { return ::sqrtf(f); }
+SLANG_FORCE_INLINE float F32_rsqrt(float f) { return 1.0f / F32_sqrt(f); }
+SLANG_FORCE_INLINE float F32_rcp(float f) { return 1.0f / f; }
+SLANG_FORCE_INLINE float F32_sign(float f) { return ( f == 0.0f) ? f : (( f < 0.0f) ? -1.0f : 1.0f); }
+SLANG_FORCE_INLINE float F32_saturate(float f) { return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f; }
+SLANG_FORCE_INLINE float F32_frac(float f) { return f - F32_floor(f); }
+SLANG_FORCE_INLINE float F32_radians(float f) { return f * 0.01745329222f; }
+
+// Binary
+SLANG_FORCE_INLINE float F32_min(float a, float b) { return a < b ? a : b; }
+SLANG_FORCE_INLINE float F32_max(float a, float b) { return a > b ? a : b; }
+SLANG_FORCE_INLINE float F32_pow(float a, float b) { return ::powf(a, b); }
+SLANG_FORCE_INLINE float F32_fmod(float a, float b) { return ::fmodf(a, b); }
+SLANG_FORCE_INLINE float F32_step(float a, float b) { return float(a >= b); }
+SLANG_FORCE_INLINE float F32_atan2(float a, float b) { return float(atan2(a, b)); }
+
+// Ternary
+SLANG_FORCE_INLINE float F32_smoothstep(float min, float max, float x) { return x < min ? min : ((x > max) ? max : x / (max - min)); }
+SLANG_FORCE_INLINE float F32_lerp(float x, float y, float s) { return x + s * (y - x); }
+SLANG_FORCE_INLINE float F32_clamp(float x, float min, float max) { return ( x < min) ? min : ((x > max) ? max : x); }
+SLANG_FORCE_INLINE void F32_sincos(float f, float& outSin, float& outCos) { outSin = F32_sin(f); outCos = F32_cos(f); }
+
+SLANG_FORCE_INLINE uint32_t F32_asuint(float f) { Union32 u; u.f = f; return u.u; }
+SLANG_FORCE_INLINE int32_t F32_asint(float f) { Union32 u; u.f = f; return u.i; }
+
+// ----------------------------- F64 -----------------------------------------
+
+SLANG_FORCE_INLINE double F64_calcSafeRadians(double radians)
+{
+ double a = radians * (1.0 / SLANG_PRELUDE_PI);
+ a = (a < 0.0) ? (::ceil(a) - a) : (a - ::floor(a));
+ return (a * SLANG_PRELUDE_PI);
+}
+
+// Unary
+SLANG_FORCE_INLINE double F64_ceil(double f) { return ::ceil(f); }
+SLANG_FORCE_INLINE double F64_floor(double f) { return ::floor(f); }
+SLANG_FORCE_INLINE double F64_sin(double f) { return ::sin(F64_calcSafeRadians(f)); }
+SLANG_FORCE_INLINE double F64_cos(double f) { return ::cos(F64_calcSafeRadians(f)); }
+SLANG_FORCE_INLINE double F64_tan(double f) { return ::tan(f); }
+SLANG_FORCE_INLINE double F64_asin(double f) { return ::asin(f); }
+SLANG_FORCE_INLINE double F64_acos(double f) { return ::acos(f); }
+SLANG_FORCE_INLINE double F64_atan(double f) { return ::atan(f); }
+SLANG_FORCE_INLINE double F64_log2(double f) { return ::log2(f); }
+SLANG_FORCE_INLINE double F64_exp2(double f) { return ::exp2(f); }
+SLANG_FORCE_INLINE double F64_exp(double f) { return ::exp(f); }
+SLANG_FORCE_INLINE double F64_abs(double f) { return ::fabs(f); }
+SLANG_FORCE_INLINE double F64_trunc(double f) { return ::trunc(f); }
+SLANG_FORCE_INLINE double F64_sqrt(double f) { return ::sqrt(f); }
+SLANG_FORCE_INLINE double F64_rsqrt(double f) { return 1.0 / F64_sqrt(f); }
+SLANG_FORCE_INLINE double F64_rcp(double f) { return 1.0 / f; }
+SLANG_FORCE_INLINE double F64_sign(double f) { return (f == 0.0) ? f : ((f < 0.0) ? -1.0 : 1.0); }
+SLANG_FORCE_INLINE double F64_saturate(double f) { return (f < 0.0) ? 0.0 : (f > 1.0) ? 1.0 : f; }
+SLANG_FORCE_INLINE double F64_frac(double f) { return f - F64_floor(f); }
+SLANG_FORCE_INLINE double F64_radians(double f) { return f * 0.01745329222; }
+
+// Binary
+SLANG_FORCE_INLINE double F64_min(double a, double b) { return a < b ? a : b; }
+SLANG_FORCE_INLINE double F64_max(double a, double b) { return a > b ? a : b; }
+SLANG_FORCE_INLINE double F64_pow(double a, double b) { return ::pow(a, b); }
+SLANG_FORCE_INLINE double F64_fmod(double a, double b) { return ::fmod(a, b); }
+SLANG_FORCE_INLINE double F64_step(double a, double b) { return double(a >= b); }
+SLANG_FORCE_INLINE double F64_atan2(double a, double b) { return atan2(a, b); }
+
+// Ternary
+SLANG_FORCE_INLINE double F64_smoothstep(double min, double max, double x) { return x < min ? min : ((x > max) ? max : x / (max - min)); }
+SLANG_FORCE_INLINE double F64_lerp(double x, double y, double s) { return x + s * (y - x); }
+SLANG_FORCE_INLINE double F64_clamp(double x, double min, double max) { return (x < min) ? min : ((x > max) ? max : x); }
+SLANG_FORCE_INLINE void F64_sincos(double f, double& outSin, double& outCos) { outSin = F64_sin(f); outCos = F64_cos(f); }
+
+// TODO!
+//uint32_t F64_asuint(float f);
+//int32_t F64_asint(float f);
+
+// ----------------------------- I32 -----------------------------------------
+
+SLANG_FORCE_INLINE int32_t I32_abs(int32_t f) { return (f < 0) ? -f : f; }
+
+SLANG_FORCE_INLINE int32_t I32_min(int32_t a, int32_t b) { return a < b ? a : b; }
+SLANG_FORCE_INLINE int32_t I32_max(int32_t a, int32_t b) { return a > b ? a : b; }
+
+SLANG_FORCE_INLINE int32_t I32_clamp(int32_t x, int32_t min, int32_t max) { return ( x < min) ? min : ((x > max) ? max : x); }
+
+SLANG_FORCE_INLINE float I32_asfloat(int32_t x) { Union32 u; u.i = x; return u.f; }
+SLANG_FORCE_INLINE uint32_t I32_asuint(int32_t x) { return uint32_t(x); }
+
+// ----------------------------- U32 -----------------------------------------
+
+SLANG_FORCE_INLINE uint32_t U32_abs(uint32_t f) { return f; }
+
+SLANG_FORCE_INLINE uint32_t U32_min(uint32_t a, uint32_t b) { return a < b ? a : b; }
+SLANG_FORCE_INLINE uint32_t U32_max(uint32_t a, uint32_t b) { return a > b ? a : b; }
+
+SLANG_FORCE_INLINE uint32_t U32_clamp(uint32_t x, uint32_t min, uint32_t max) { return ( x < min) ? min : ((x > max) ? max : x); }
+
+SLANG_FORCE_INLINE float U32_asfloat(uint32_t x) { Union32 u; u.u = x; return u.f; }
+SLANG_FORCE_INLINE uint32_t U32_asint(int32_t x) { return uint32_t(x); }
+
+#ifdef SLANG_PRELUDE_NAMESPACE
+}
+#endif
+
+#endif
diff --git a/tests/cross-compile/slang-cpp-prelude.h b/tests/cross-compile/slang-cpp-prelude.h
index 612e04a0b..f32504920 100644
--- a/tests/cross-compile/slang-cpp-prelude.h
+++ b/tests/cross-compile/slang-cpp-prelude.h
@@ -433,6 +433,11 @@ convention for interface methods.
/* --------------- END From slang.h ----------------- */
+// TODO(JS): Hack! Output C++ code from slang can copy unitialized variables.
+#if SLANG_VC
+# pragma warning(disable : 4700)
+#endif
+
#include <math.h>
#include <assert.h>
#include <stdlib.h>
diff --git a/tools/gfx/render.cpp b/tools/gfx/render.cpp
index e618c8f8c..44bb4fb04 100644
--- a/tools/gfx/render.cpp
+++ b/tools/gfx/render.cpp
@@ -69,6 +69,7 @@ const Resource::DescBase& Resource::getDescBase() const
BindingStyle::DirectX, // DirectX12,
BindingStyle::OpenGl, // OpenGl,
BindingStyle::Vulkan, // Vulkan
+ BindingStyle::CPU, // CPU
};
/* static */void RendererUtil::compileTimeAsserts()
@@ -398,6 +399,7 @@ ProjectionStyle RendererUtil::getProjectionStyle(RendererType type)
case RendererType::OpenGl: return UnownedStringSlice::fromLiteral("OpenGL");
case RendererType::Vulkan: return UnownedStringSlice::fromLiteral("Vulkan");
case RendererType::Unknown: return UnownedStringSlice::fromLiteral("Unknown");
+ case RendererType::CPU: return UnownedStringSlice::fromLiteral("CPU");
default: return UnownedStringSlice::fromLiteral("?!?");
}
}
diff --git a/tools/gfx/render.h b/tools/gfx/render.h
index 247932bd5..4a8458e96 100644
--- a/tools/gfx/render.h
+++ b/tools/gfx/render.h
@@ -66,6 +66,7 @@ enum class RendererType
DirectX12,
OpenGl,
Vulkan,
+ CPU,
CountOf,
};
@@ -85,6 +86,7 @@ enum class BindingStyle
DirectX,
OpenGl,
Vulkan,
+ CPU,
CountOf,
};
diff --git a/tools/render-test/options.cpp b/tools/render-test/options.cpp
index 9423b5b6e..f8c2c1d12 100644
--- a/tools/render-test/options.cpp
+++ b/tools/render-test/options.cpp
@@ -28,6 +28,7 @@ static gfx::RendererType _toRenderType(Slang::RenderApiType apiType)
case RenderApiType::D3D12: return gfx::RendererType::DirectX12;
case RenderApiType::OpenGl: return gfx::RendererType::OpenGl;
case RenderApiType::Vulkan: return gfx::RendererType::Vulkan;
+ case RenderApiType::CPU: return gfx::RendererType::CPU;
default: return gfx::RendererType::Unknown;
}
}
diff --git a/tools/render-test/render-test-main.cpp b/tools/render-test/render-test-main.cpp
index f82e03ad5..91230b9d0 100644
--- a/tools/render-test/render-test-main.cpp
+++ b/tools/render-test/render-test-main.cpp
@@ -17,7 +17,12 @@
#include <stdio.h>
#include <stdlib.h>
+// TODO(JS): We need to put the prelude into a better place
+#define SLANG_PRELUDE_NAMESPACE CPPPrelude
+#include "../../tests/cross-compile/slang-cpp-prelude.h"
+
#include "../../source/core/slang-test-tool-util.h"
+#include "../../source/core/slang-memory-arena.h"
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
@@ -200,7 +205,7 @@ class RenderTestApp
// At initialization time, we are going to load and compile our Slang shader
// code, and then create the API objects we need for rendering.
- Result initialize(Renderer* renderer, ShaderCompiler* shaderCompiler);
+ Result initialize(SlangSession* session, Renderer* renderer, Options::ShaderProgramType shaderType, const ShaderCompilerUtil::Input& input);
void runCompute();
void renderFrame();
void finalize();
@@ -213,7 +218,7 @@ class RenderTestApp
protected:
/// Called in initialize
- Result initializeShaders(ShaderCompiler* shaderCompiler);
+ Result _initializeShaders(SlangSession* session, Renderer* renderer, Options::ShaderProgramType shaderType, const ShaderCompilerUtil::Input& input);
// variables for state to be used for rendering...
uintptr_t m_constantBufferSize, m_computeResultBufferSize;
@@ -236,49 +241,432 @@ static const char vertexEntryPointName[] = "vertexMain";
static const char fragmentEntryPointName[] = "fragmentMain";
static const char computeEntryPointName[] = "computeMain";
-SlangResult RenderTestApp::initialize(Renderer* renderer, ShaderCompiler* shaderCompiler)
+static SlangResult _readSource(const String& inSourcePath, List<char>& outSourceText)
{
- SLANG_RETURN_ON_FAIL(initializeShaders(shaderCompiler));
+ // Read in the source code
+ FILE* sourceFile = fopen(inSourcePath.getBuffer(), "rb");
+ if (!sourceFile)
+ {
+ fprintf(stderr, "error: failed to open '%s' for reading\n", inSourcePath.getBuffer());
+ return SLANG_FAIL;
+ }
+ fseek(sourceFile, 0, SEEK_END);
+ size_t sourceSize = ftell(sourceFile);
+ fseek(sourceFile, 0, SEEK_SET);
- m_numAddedConstantBuffers = 0;
- m_renderer = renderer;
+ outSourceText.setCount(sourceSize + 1);
+ fread(outSourceText.getBuffer(), sourceSize, 1, sourceFile);
+ fclose(sourceFile);
+ outSourceText[sourceSize] = 0;
- // TODO(tfoley): use each API's reflection interface to query the constant-buffer size needed
+ return SLANG_OK;
+}
+
+struct CompileOutput
+{
+ ShaderCompilerUtil::Output compileOutput;
+ ShaderInputLayout layout;
+};
+
+static SlangResult _compile(SlangSession* session, const String& sourcePath, Options::ShaderProgramType shaderType, const ShaderCompilerUtil::Input& input, CompileOutput& output)
+{
+ List<char> sourceText;
+ SLANG_RETURN_ON_FAIL(_readSource(sourcePath, sourceText));
+
+ auto& layout = output.layout;
+
+ // Default the amount of renderTargets based on shader type
+ switch (shaderType)
{
- m_constantBufferSize = 16 * sizeof(float);
+ default:
+ layout.numRenderTargets = 1;
+ break;
+
+ case Options::ShaderProgramType::Compute:
+ layout.numRenderTargets = 0;
+ break;
+ }
- BufferResource::Desc constantBufferDesc;
- constantBufferDesc.init(m_constantBufferSize);
- constantBufferDesc.cpuAccessFlags = Resource::AccessFlag::Write;
+ // Parse the layout
+ layout.parse(sourceText.getBuffer());
- m_constantBuffer = renderer->createBufferResource(Resource::Usage::ConstantBuffer, constantBufferDesc);
- if (!m_constantBuffer)
- return SLANG_FAIL;
+ // Setup SourceInfo
+ ShaderCompileRequest::SourceInfo sourceInfo;
+ sourceInfo.path = sourcePath.getBuffer();
+ sourceInfo.dataBegin = sourceText.getBuffer();
+ // Subtract 1 because it's zero terminated
+ sourceInfo.dataEnd = sourceText.getBuffer() + sourceText.getCount() - 1;
+
+ ShaderCompileRequest compileRequest;
+ compileRequest.source = sourceInfo;
+ if (shaderType == Options::ShaderProgramType::Graphics || shaderType == Options::ShaderProgramType::GraphicsCompute)
+ {
+ compileRequest.vertexShader.source = sourceInfo;
+ compileRequest.vertexShader.name = vertexEntryPointName;
+ compileRequest.fragmentShader.source = sourceInfo;
+ compileRequest.fragmentShader.name = fragmentEntryPointName;
+ }
+ else
+ {
+ compileRequest.computeShader.source = sourceInfo;
+ compileRequest.computeShader.name = computeEntryPointName;
}
+ compileRequest.globalGenericTypeArguments = layout.globalGenericTypeArguments;
+ compileRequest.entryPointGenericTypeArguments = layout.entryPointGenericTypeArguments;
+ compileRequest.globalExistentialTypeArguments = layout.globalExistentialTypeArguments;
+ compileRequest.entryPointExistentialTypeArguments = layout.entryPointExistentialTypeArguments;
+
+ return ShaderCompilerUtil::compileProgram(session, input, compileRequest, output.compileOutput);
+}
+
+static SlangResult _handleResource(slang::TypeReflection* type, ShaderInputLayoutEntry& src, void* dst)
+{
+ auto shape = type->getResourceShape();
+ auto access = type->getResourceAccess();
+ switch (shape & SLANG_RESOURCE_BASE_SHAPE_MASK)
{
- //! Hack -> if doing a graphics test, add an extra binding for our dynamic constant buffer
- //
- // TODO: Should probably be more sophisticated than this - with 'dynamic' constant buffer/s binding always being specified
- // in the test file
- RefPtr<BufferResource> addedConstantBuffer;
- switch(gOptions.shaderType)
- {
default:
+ assert(!"unhandled case");
break;
+ case SLANG_TEXTURE_1D:
+ case SLANG_TEXTURE_2D:
+ case SLANG_TEXTURE_3D:
+ case SLANG_TEXTURE_CUBE:
+ case SLANG_TEXTURE_BUFFER:
+ {
+ return SLANG_FAIL;
+ }
+ case SLANG_STRUCTURED_BUFFER:
+ {
+ // TODO(JS): I guess this is questionable - because sizeof(unsigned int) != sizeof(uint32_t) necessarily
+ CPPPrelude::StructuredBuffer<uint32_t>& dstBuf = *(CPPPrelude::StructuredBuffer<uint32_t>*)dst;
+ dstBuf.data = src.bufferData.getBuffer();
+ dstBuf.count = src.bufferData.getCount();
+ break;
+ }
+ case SLANG_BYTE_ADDRESS_BUFFER:
+ {
+ CPPPrelude::ByteAddressBuffer& dstBuf = *(CPPPrelude::ByteAddressBuffer*)dst;
+ dstBuf.data = src.bufferData.getBuffer();
+ dstBuf.sizeInBytes = src.bufferData.getCount() * sizeof(unsigned int);
- case Options::ShaderProgramType::Graphics:
- case Options::ShaderProgramType::GraphicsCompute:
- addedConstantBuffer = m_constantBuffer;
- m_numAddedConstantBuffers++;
break;
}
+ }
+ if (shape & SLANG_TEXTURE_ARRAY_FLAG)
+ {
+
+ }
+ if (shape & SLANG_TEXTURE_MULTISAMPLE_FLAG)
+ {
+
+ }
+
+ if (access != SLANG_RESOURCE_ACCESS_READ)
+ {
+ switch (access)
+ {
+ default:
+ assert(!"unhandled case");
+ break;
+
+ case SLANG_RESOURCE_ACCESS_READ:
+ break;
+
+ case SLANG_RESOURCE_ACCESS_READ_WRITE: break;
+ case SLANG_RESOURCE_ACCESS_RASTER_ORDERED: break;
+ case SLANG_RESOURCE_ACCESS_APPEND: break;
+ case SLANG_RESOURCE_ACCESS_CONSUME: break;
+ }
+
+ }
+ return SLANG_OK;
+}
- BindingStateImpl* bindingState = nullptr;
- SLANG_RETURN_ON_FAIL(ShaderRendererUtil::createBindingState(m_shaderInputLayout, m_renderer, addedConstantBuffer, &bindingState));
- m_bindingState = bindingState;
+static SlangResult _writeBindings(const ShaderInputLayout& layout, const String& fileName)
+{
+ FILE * f = fopen(fileName.getBuffer(), "wb");
+ if (!f)
+ {
+ return SLANG_FAIL;
}
+ for (auto entry : layout.entries)
+ {
+ if (entry.isOutput)
+ {
+ auto ptr = entry.bufferData.getBuffer();
+ const int size = int(entry.bufferData.getCount());
+ for (int i = 0; i < size; ++i)
+ {
+ fprintf(f, "%X\n", ptr[i]);
+ }
+ }
+ }
+ fclose(f);
+ return SLANG_OK;
+}
+
+static SlangResult _doCPUCompute(SlangSession* session, const String& sourcePath, Options::ShaderProgramType shaderType, const ShaderCompilerUtil::Input& input)
+{
+ CompileOutput output;
+ SLANG_RETURN_ON_FAIL(_compile(session, sourcePath, shaderType, input, output));
+
+ ComPtr<ISlangSharedLibrary> sharedLibrary;
+ SLANG_RETURN_ON_FAIL(spGetEntryPointHostCallable(output.compileOutput.request, 0, 0, sharedLibrary.writeRef()));
+
+ // Use reflection to find the entry point name
+ auto request = output.compileOutput.request;
+
+ struct UniformState;
+ typedef void(*Func)(CPPPrelude::ComputeVaryingInput* varyingInput, UniformState* uniformState);
+
+ auto reflection = (slang::ShaderReflection*) spGetReflection(request);
+
+ slang::EntryPointReflection* entryPoint = nullptr;
+ Func func = nullptr;
+ {
+
+ auto entryPointCount = reflection->getEntryPointCount();
+ SLANG_ASSERT(entryPointCount == 1);
+
+ entryPoint = reflection->getEntryPointByIndex(0);
+
+ const char* entryPointName = entryPoint->getName();
+ func = (Func) sharedLibrary->findFuncByName(entryPointName);
+
+ if (!func)
+ {
+ return SLANG_FAIL;
+ }
+ }
+ // Okay we need to find all of the bindings and match up to those in the layout
+
+ ShaderInputLayout& layout = output.layout;
+
+ // For general storage
+ MemoryArena arena;
+ arena.init(1024);
+ List<void*> uniformState;
+
+ {
+ int parameterCount = reflection->getParameterCount();
+
+ for (int i = 0; i < parameterCount; ++i)
+ {
+ auto parameter = reflection->getParameterByIndex(i);
+
+ const char* paramName = parameter->getName();
+
+ const Index entryIndex = layout.findEntryIndexByName(paramName);
+ if (entryIndex < 0)
+ {
+ auto& outStream = StdWriters::getOut();
+
+ int numNamed = 0;
+ for (const auto& entry : layout.entries)
+ {
+ numNamed += int(entry.name.getLength() > 0);
+ }
+
+ if (layout.entries.getCount() > 0 && numNamed == 0)
+ {
+ outStream.print("No 'name' specified for resources in '%s'\n", sourcePath.getBuffer());
+ }
+ else
+ {
+ outStream.print("Unable to find entry in '%s' for '%s' (for CPU name must be specified) \n", sourcePath.getBuffer(), paramName);
+ }
+ return SLANG_FAIL;
+ }
+
+ auto stage = parameter->getStage();
+
+ auto typeLayout = parameter->getTypeLayout();
+ auto categoryCount = parameter->getCategoryCount();
+
+ SLANG_ASSERT(categoryCount == 1);
+
+ // Only dealing one category per item right now
+ auto category = parameter->getCategoryByIndex(0);
+
+ auto offset = parameter->getOffset(category);
+ auto space = parameter->getBindingSpace(category);
+ auto count = typeLayout->getSize(category);
+
+ size_t end = offset + count;
+ if (uniformState.getCount() * sizeof(void*) < end)
+ {
+ uniformState.setCount(end / sizeof(void*));
+ }
+
+ void* dstEntry = ((uint8_t*)uniformState.getBuffer()) + offset;
+ auto& srcEntry = layout.entries[entryIndex];
+
+ switch (typeLayout->getKind())
+ {
+ default:
+ break;
+
+ case slang::TypeReflection::Kind::Array:
+ {
+ auto arrayTypeLayout = typeLayout;
+ auto elementTypeLayout = arrayTypeLayout->getElementTypeLayout();
+ auto elementCount = int(arrayTypeLayout->getElementCount());
+
+ if (arrayTypeLayout->getSize(SLANG_PARAMETER_CATEGORY_UNIFORM) != 0)
+ {
+ int elementStride = int(arrayTypeLayout->getElementStride(SLANG_PARAMETER_CATEGORY_UNIFORM));
+ SLANG_UNUSED(elementStride);
+ }
+ SLANG_UNUSED(elementTypeLayout);
+ SLANG_UNUSED(elementCount);
+ break;
+ }
+ case slang::TypeReflection::Kind::Struct:
+ {
+ auto structTypeLayout = typeLayout;
+ auto name = structTypeLayout->getName();
+ SLANG_UNUSED(name);
+
+ auto fieldCount = structTypeLayout->getFieldCount();
+ for (uint32_t ff = 0; ff < fieldCount; ++ff)
+ {
+ auto field = structTypeLayout->getFieldByIndex(ff);
+ SLANG_UNUSED(field);
+ }
+ auto type = structTypeLayout->getType();
+ SLANG_UNUSED(type);
+ break;
+ }
+ case slang::TypeReflection::Kind::ConstantBuffer:
+ {
+ auto elementTypeLayout = typeLayout->getElementTypeLayout();
+ SLANG_UNUSED(elementTypeLayout);
+ break;
+ }
+ case slang::TypeReflection::Kind::ParameterBlock:
+ {
+ auto elementTypeLayout = typeLayout->getElementTypeLayout();
+ SLANG_UNUSED(elementTypeLayout);
+ break;
+ }
+ case slang::TypeReflection::Kind::TextureBuffer:
+ {
+ auto elementTypeLayout = typeLayout->getElementTypeLayout();
+ SLANG_UNUSED(elementTypeLayout);
+ break;
+ }
+ case slang::TypeReflection::Kind::ShaderStorageBuffer:
+ {
+ auto elementTypeLayout = typeLayout->getElementTypeLayout();
+ SLANG_UNUSED(elementTypeLayout);
+ break;
+ }
+ case slang::TypeReflection::Kind::GenericTypeParameter:
+ {
+ const char* name = typeLayout->getName();
+ SLANG_UNUSED(name);
+ break;
+ }
+ case slang::TypeReflection::Kind::Interface:
+ {
+ const char* name = typeLayout->getName();
+ SLANG_UNUSED(name);
+ break;
+ }
+ case slang::TypeReflection::Kind::Resource:
+ {
+ // Some resource types (notably structured buffers)
+ // encode layout information for their result/element
+ // type, but others don't. We need to check for
+ // the relevant cases here.
+ //
+ auto type = typeLayout->getType();
+ auto shape = type->getResourceShape();
+
+ if ((shape & SLANG_RESOURCE_BASE_SHAPE_MASK) == SLANG_STRUCTURED_BUFFER)
+ {
+ _handleResource(typeLayout->getType(), srcEntry, dstEntry);
+
+ }
+ else
+ {
+ //emitReflectionTypeInfoJSON(writer, typeLayout->getType());
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ SlangUInt numThreadsPerAxis[3];
+ entryPoint->getComputeThreadGroupSize(3, numThreadsPerAxis);
+
+ {
+ CPPPrelude::ComputeVaryingInput varying;
+ varying.groupID = {};
+
+ for (int z = 0; z < numThreadsPerAxis[2]; ++z)
+ {
+ varying.groupThreadID.z = z;
+ for (int y = 0; y < numThreadsPerAxis[1]; ++y)
+ {
+ varying.groupThreadID.y = y;
+ for (int x = 0; x < numThreadsPerAxis[0]; ++x)
+ {
+ varying.groupThreadID.x = x;
+
+ func(&varying, (UniformState*)uniformState.getBuffer());
+ }
+ }
+ }
+ }
+
+ // Dump everything out that was write (we wrote in place!)
+ return _writeBindings(layout, gOptions.outputPath);
+}
+
+SlangResult RenderTestApp::initialize(SlangSession* session, Renderer* renderer, Options::ShaderProgramType shaderType, const ShaderCompilerUtil::Input& input)
+{
+ SLANG_RETURN_ON_FAIL(_initializeShaders(session, renderer, shaderType, input));
+
+ m_numAddedConstantBuffers = 0;
+ m_renderer = renderer;
+
+ // TODO(tfoley): use each API's reflection interface to query the constant-buffer size needed
+ m_constantBufferSize = 16 * sizeof(float);
+
+ BufferResource::Desc constantBufferDesc;
+ constantBufferDesc.init(m_constantBufferSize);
+ constantBufferDesc.cpuAccessFlags = Resource::AccessFlag::Write;
+
+ m_constantBuffer = renderer->createBufferResource(Resource::Usage::ConstantBuffer, constantBufferDesc);
+ if (!m_constantBuffer)
+ return SLANG_FAIL;
+
+ //! Hack -> if doing a graphics test, add an extra binding for our dynamic constant buffer
+ //
+ // TODO: Should probably be more sophisticated than this - with 'dynamic' constant buffer/s binding always being specified
+ // in the test file
+ RefPtr<BufferResource> addedConstantBuffer;
+ switch(shaderType)
+ {
+ default:
+ break;
+
+ case Options::ShaderProgramType::Graphics:
+ case Options::ShaderProgramType::GraphicsCompute:
+ addedConstantBuffer = m_constantBuffer;
+ m_numAddedConstantBuffers++;
+ break;
+ }
+
+ BindingStateImpl* bindingState = nullptr;
+ SLANG_RETURN_ON_FAIL(ShaderRendererUtil::createBindingState(m_shaderInputLayout, m_renderer, addedConstantBuffer, &bindingState));
+ m_bindingState = bindingState;
+
// Do other initialization that doesn't depend on the source language.
// Input Assembler (IA)
@@ -301,7 +689,7 @@ SlangResult RenderTestApp::initialize(Renderer* renderer, ShaderCompiler* shader
return SLANG_FAIL;
{
- switch(gOptions.shaderType)
+ switch(shaderType)
{
default:
assert(!"unexpected test shader type");
@@ -336,63 +724,12 @@ SlangResult RenderTestApp::initialize(Renderer* renderer, ShaderCompiler* shader
return m_pipelineState ? SLANG_OK : SLANG_FAIL;
}
-Result RenderTestApp::initializeShaders(ShaderCompiler* shaderCompiler)
+Result RenderTestApp::_initializeShaders(SlangSession* session, Renderer* renderer, Options::ShaderProgramType shaderType, const ShaderCompilerUtil::Input& input)
{
- // Read in the source code
- char const* sourcePath = gOptions.sourcePath;
- FILE* sourceFile = fopen(sourcePath, "rb");
- if (!sourceFile)
- {
- fprintf(stderr, "error: failed to open '%s' for reading\n", sourcePath);
- return SLANG_FAIL;
- }
- fseek(sourceFile, 0, SEEK_END);
- size_t sourceSize = ftell(sourceFile);
- fseek(sourceFile, 0, SEEK_SET);
-
- List<char> sourceText;
- sourceText.setCount(sourceSize + 1);
- fread(sourceText.getBuffer(), sourceSize, 1, sourceFile);
- fclose(sourceFile);
- sourceText[sourceSize] = 0;
-
- switch( gOptions.shaderType )
- {
- default:
- m_shaderInputLayout.numRenderTargets = 1;
- break;
-
- case Options::ShaderProgramType::Compute:
- m_shaderInputLayout.numRenderTargets = 0;
- break;
- }
- m_shaderInputLayout.Parse(sourceText.getBuffer());
-
- ShaderCompileRequest::SourceInfo sourceInfo;
- sourceInfo.path = sourcePath;
- sourceInfo.dataBegin = sourceText.getBuffer();
- sourceInfo.dataEnd = sourceText.getBuffer() + sourceSize;
-
- ShaderCompileRequest compileRequest;
- compileRequest.source = sourceInfo;
- if (gOptions.shaderType == Options::ShaderProgramType::Graphics || gOptions.shaderType == Options::ShaderProgramType::GraphicsCompute)
- {
- compileRequest.vertexShader.source = sourceInfo;
- compileRequest.vertexShader.name = vertexEntryPointName;
- compileRequest.fragmentShader.source = sourceInfo;
- compileRequest.fragmentShader.name = fragmentEntryPointName;
- }
- else
- {
- compileRequest.computeShader.source = sourceInfo;
- compileRequest.computeShader.name = computeEntryPointName;
- }
- compileRequest.globalGenericTypeArguments = m_shaderInputLayout.globalGenericTypeArguments;
- compileRequest.entryPointGenericTypeArguments = m_shaderInputLayout.entryPointGenericTypeArguments;
- compileRequest.globalExistentialTypeArguments = m_shaderInputLayout.globalExistentialTypeArguments;
- compileRequest.entryPointExistentialTypeArguments = m_shaderInputLayout.entryPointExistentialTypeArguments;
- m_shaderProgram = shaderCompiler->compileProgram(compileRequest);
-
+ CompileOutput output;
+ SLANG_RETURN_ON_FAIL(_compile(session, gOptions.sourcePath, shaderType, input, output));
+ m_shaderInputLayout = output.layout;
+ m_shaderProgram = renderer->createProgram(output.compileOutput.desc);
return m_shaderProgram ? SLANG_OK : SLANG_FAIL;
}
@@ -501,61 +838,90 @@ SLANG_TEST_TOOL_API SlangResult innerMain(Slang::StdWriters* stdWriters, SlangSe
// Parse command-line options
SLANG_RETURN_ON_FAIL(parseOptions(argcIn, argvIn, StdWriters::getError()));
- RefPtr<renderer_test::Window> window(new renderer_test::Window);
- SLANG_RETURN_ON_FAIL(window->initialize(gWindowWidth, gWindowHeight));
Slang::RefPtr<Renderer> renderer;
+ ShaderCompilerUtil::Input input;
+
+ input.profile = "";
+ input.target = SLANG_TARGET_NONE;
+ input.args = &gOptions.slangArgs[0];
+ input.argCount = gOptions.slangArgCount;
+
SlangSourceLanguage nativeLanguage = SLANG_SOURCE_LANGUAGE_UNKNOWN;
- SlangCompileTarget slangTarget = SLANG_TARGET_NONE;
- SlangPassThrough slangPassThrough = SLANG_PASS_THROUGH_NONE;
+ SlangPassThrough slangPassThrough = SLANG_PASS_THROUGH_NONE;
char const* profileName = "";
switch (gOptions.rendererType)
{
case RendererType::DirectX11:
renderer = createD3D11Renderer();
- slangTarget = SLANG_DXBC;
+ input.target = SLANG_DXBC;
+ input.profile = "sm_5_0";
nativeLanguage = SLANG_SOURCE_LANGUAGE_HLSL;
slangPassThrough = SLANG_PASS_THROUGH_FXC;
- profileName = "sm_5_0";
+
break;
case RendererType::DirectX12:
renderer = createD3D12Renderer();
- slangTarget = SLANG_DXBC;
+ input.target = SLANG_DXBC;
+ input.profile = "sm_5_0";
nativeLanguage = SLANG_SOURCE_LANGUAGE_HLSL;
slangPassThrough = SLANG_PASS_THROUGH_FXC;
- profileName = "sm_5_0";
+
if( gOptions.useDXIL )
{
- slangTarget = SLANG_DXIL;
+ input.target = SLANG_DXIL;
+ input.profile = "sm_6_0";
slangPassThrough = SLANG_PASS_THROUGH_DXC;
- profileName = "sm_6_0";
}
break;
case RendererType::OpenGl:
renderer = createGLRenderer();
- slangTarget = SLANG_GLSL;
+ input.target = SLANG_GLSL;
+ input.profile = "glsl_430";
nativeLanguage = SLANG_SOURCE_LANGUAGE_GLSL;
slangPassThrough = SLANG_PASS_THROUGH_GLSLANG;
- profileName = "glsl_430";
break;
case RendererType::Vulkan:
renderer = createVKRenderer();
- slangTarget = SLANG_SPIRV;
+ input.target = SLANG_SPIRV;
+ input.profile = "glsl_430";
nativeLanguage = SLANG_SOURCE_LANGUAGE_GLSL;
slangPassThrough = SLANG_PASS_THROUGH_GLSLANG;
- profileName = "glsl_430";
break;
-
+ case RendererType::CPU:
+ input.target = SLANG_HOST_CALLABLE;
+ input.profile = "";
+ nativeLanguage = SLANG_SOURCE_LANGUAGE_CPP;
+ slangPassThrough = SLANG_PASS_THROUGH_GENERIC_C_CPP;
+ break;
default:
fprintf(stderr, "error: unexpected\n");
return SLANG_FAIL;
}
-
+ switch (gOptions.inputLanguageID)
+ {
+ case Options::InputLanguageID::Slang:
+ input.sourceLanguage = SLANG_SOURCE_LANGUAGE_SLANG;
+ input.passThrough = SLANG_PASS_THROUGH_NONE;
+ break;
+
+ case Options::InputLanguageID::Native:
+ input.sourceLanguage = nativeLanguage;
+ input.passThrough = slangPassThrough;
+ break;
+
+ default:
+ break;
+ }
+
+ // Use the profile name set on options if set
+ input.profile = gOptions.profileName ? gOptions.profileName : input.profile;
+
StringBuilder rendererName;
rendererName << "[" << RendererUtil::toText(gOptions.rendererType) << "] ";
if (gOptions.adapter.getLength())
@@ -563,22 +929,18 @@ SLANG_TEST_TOOL_API SlangResult innerMain(Slang::StdWriters* stdWriters, SlangSe
rendererName << "'" << gOptions.adapter << "'";
}
+ RefPtr<renderer_test::Window> window;
- if (!renderer)
+ if (renderer)
{
- if (!gOptions.onlyStartup)
- {
- fprintf(stderr, "Unable to create renderer %s\n", rendererName.getBuffer());
- }
- return SLANG_FAIL;
- }
+ Renderer::Desc desc;
+ desc.width = gWindowWidth;
+ desc.height = gWindowHeight;
+ desc.adapter = gOptions.adapter;
- Renderer::Desc desc;
- desc.width = gWindowWidth;
- desc.height = gWindowHeight;
- desc.adapter = gOptions.adapter;
+ window = new renderer_test::Window;
+ SLANG_RETURN_ON_FAIL(window->initialize(gWindowWidth, gWindowHeight));
- {
SlangResult res = renderer->initialize(desc, (HWND)window->getHandle());
if (SLANG_FAILED(res))
{
@@ -588,15 +950,7 @@ SLANG_TEST_TOOL_API SlangResult innerMain(Slang::StdWriters* stdWriters, SlangSe
}
return res;
}
- }
-
- // If the only test is we can startup, then we are done
- if (gOptions.onlyStartup)
- {
- return SLANG_OK;
- }
- {
for (const auto& feature : gOptions.renderFeatures)
{
// If doesn't have required feature... we have to give up
@@ -606,36 +960,33 @@ SLANG_TEST_TOOL_API SlangResult innerMain(Slang::StdWriters* stdWriters, SlangSe
}
}
}
+ else
+ {
+ if (gOptions.rendererType != RendererType::CPU)
+ {
+ if (!gOptions.onlyStartup)
+ {
+ fprintf(stderr, "Unable to create renderer %s\n", rendererName.getBuffer());
+ }
+ return SLANG_FAIL;
+ }
+ }
- // Use the profile name set on options if set
- profileName = gOptions.profileName ? gOptions.profileName : profileName;
-
- ShaderCompiler shaderCompiler;
- shaderCompiler.renderer = renderer;
- shaderCompiler.target = slangTarget;
- shaderCompiler.profile = profileName;
- shaderCompiler.slangSession = session;
-
- switch (gOptions.inputLanguageID)
- {
- case Options::InputLanguageID::Slang:
- shaderCompiler.sourceLanguage = SLANG_SOURCE_LANGUAGE_SLANG;
- shaderCompiler.passThrough = SLANG_PASS_THROUGH_NONE;
- break;
-
- case Options::InputLanguageID::Native:
- shaderCompiler.sourceLanguage = nativeLanguage;
- shaderCompiler.passThrough = slangPassThrough;
- break;
+ // If the only test is we can startup, then we are done
+ if (gOptions.onlyStartup)
+ {
+ return SLANG_OK;
+ }
- default:
- break;
- }
+ if (!renderer)
+ {
+ SLANG_RETURN_ON_FAIL(_doCPUCompute(session, gOptions.sourcePath, gOptions.shaderType, input));
+ return SLANG_OK;
+ }
{
RenderTestApp app;
-
- SLANG_RETURN_ON_FAIL(app.initialize(renderer, &shaderCompiler));
+ SLANG_RETURN_ON_FAIL(app.initialize(session, renderer, gOptions.shaderType, input));
window->show();
diff --git a/tools/render-test/shader-input-layout.cpp b/tools/render-test/shader-input-layout.cpp
index 8205c979e..e555ee6ca 100644
--- a/tools/render-test/shader-input-layout.cpp
+++ b/tools/render-test/shader-input-layout.cpp
@@ -6,7 +6,23 @@
namespace renderer_test
{
using namespace Slang;
- void ShaderInputLayout::Parse(const char * source)
+
+
+ Index ShaderInputLayout::findEntryIndexByName(const String& name) const
+ {
+ const Index count = Index(entries.getCount());
+ for (Index i = 0; i < count; ++i)
+ {
+ const auto& entry = entries[i];
+ if (entry.name == name)
+ {
+ return Index(i);
+ }
+ }
+ return -1;
+ }
+
+ void ShaderInputLayout::parse(const char * source)
{
entries.clear();
globalGenericTypeArguments.clear();
@@ -267,6 +283,18 @@ namespace renderer_test
parser.ReadToken();
entry.isOutput = true;
}
+ else if (parser.LookAhead("name"))
+ {
+ parser.ReadToken();
+ Token nameToken = parser.ReadToken();
+
+ if (nameToken.Type != TokenType::Identifier)
+ {
+ throw TextFormatException("Invalid input syntax at line " + parser.NextToken().Position.Line);
+ }
+ entry.name = nameToken.Content;
+ }
+
if (parser.LookAhead(","))
parser.Read(",");
}
diff --git a/tools/render-test/shader-input-layout.h b/tools/render-test/shader-input-layout.h
index d5a1b6fd5..0f11c4ad7 100644
--- a/tools/render-test/shader-input-layout.h
+++ b/tools/render-test/shader-input-layout.h
@@ -61,6 +61,8 @@ public:
bool isOutput = false;
int hlslBinding = -1;
Slang::List<int> glslBinding;
+
+ Slang::String name; ///< Optional name. Useful for binding through reflection.
};
struct TextureData
@@ -80,7 +82,10 @@ public:
Slang::List<Slang::String> globalExistentialTypeArguments;
Slang::List<Slang::String> entryPointExistentialTypeArguments;
int numRenderTargets = 1;
- void Parse(const char * source);
+
+ Slang::Index findEntryIndexByName(const Slang::String& name) const;
+
+ void parse(const char * source);
};
void generateTextureDataRGB8(TextureData& output, const InputTextureDesc& desc);
diff --git a/tools/render-test/slang-support.cpp b/tools/render-test/slang-support.cpp
index 77f1436b1..230f78453 100644
--- a/tools/render-test/slang-support.cpp
+++ b/tools/render-test/slang-support.cpp
@@ -11,19 +11,21 @@
namespace renderer_test {
-RefPtr<ShaderProgram> ShaderCompiler::compileProgram(
- ShaderCompileRequest const& request)
+/* static */ SlangResult ShaderCompilerUtil::compileProgram(SlangSession* session, const Input& input, const ShaderCompileRequest& request, Output& out)
{
- SlangCompileRequest* slangRequest = spCreateCompileRequest(slangSession);
+ out.reset();
- spSetCodeGenTarget(slangRequest, target);
- spSetTargetProfile(slangRequest, 0,
- spFindProfile(slangSession, profile));
+ SlangCompileRequest* slangRequest = spCreateCompileRequest(session);
+ out.request = slangRequest;
+ out.session = session;
+
+ spSetCodeGenTarget(slangRequest, input.target);
+ spSetTargetProfile(slangRequest, 0, spFindProfile(session, input.profile));
// Define a macro so that shader code in a test can detect what language we
// are nominally working with.
char const* langDefine = nullptr;
- switch (sourceLanguage)
+ switch (input.sourceLanguage)
{
case SLANG_SOURCE_LANGUAGE_GLSL:
spAddPreprocessorDefine(slangRequest, "__GLSL__", "1");
@@ -41,14 +43,14 @@ RefPtr<ShaderProgram> ShaderCompiler::compileProgram(
break;
}
- if (passThrough != SLANG_PASS_THROUGH_NONE)
+ if (input.passThrough != SLANG_PASS_THROUGH_NONE)
{
- spSetPassThrough(slangRequest, passThrough);
+ spSetPassThrough(slangRequest, input.passThrough);
}
// Process any additional command-line options specified for Slang using
// the `-xslang <arg>` option to `render-test`.
- SLANG_RETURN_NULL_ON_FAIL(spProcessCommandLineArguments(slangRequest, &gOptions.slangArgs[0], gOptions.slangArgCount));
+ SLANG_RETURN_ON_FAIL(spProcessCommandLineArguments(slangRequest, input.args, input.argCount));
int computeTranslationUnit = 0;
int vertexTranslationUnit = 0;
@@ -57,6 +59,8 @@ RefPtr<ShaderProgram> ShaderCompiler::compileProgram(
char const* fragmentEntryPointName = request.fragmentShader.name;
char const* computeEntryPointName = request.computeShader.name;
+ const auto sourceLanguage = input.sourceLanguage;
+
if (sourceLanguage == SLANG_SOURCE_LANGUAGE_GLSL)
{
// GLSL presents unique challenges because, frankly, it got the whole
@@ -91,8 +95,6 @@ RefPtr<ShaderProgram> ShaderCompiler::compileProgram(
}
- RefPtr<ShaderProgram> shaderProgram;
-
Slang::List<const char*> rawGlobalTypeNames;
for (auto typeName : request.globalGenericTypeArguments)
rawGlobalTypeNames.add(typeName.getBuffer());
@@ -146,12 +148,7 @@ RefPtr<ShaderProgram> ShaderCompiler::compileProgram(
kernelDesc.codeBegin = code;
kernelDesc.codeEnd = code + codeSize;
- ShaderProgram::Desc desc;
- desc.pipelineType = PipelineType::Compute;
- desc.kernels = &kernelDesc;
- desc.kernelCount = 1;
-
- shaderProgram = renderer->createProgram(desc);
+ out.set(PipelineType::Compute, &kernelDesc, 1);
}
}
else
@@ -189,21 +186,11 @@ RefPtr<ShaderProgram> ShaderCompiler::compileProgram(
kernelDescs[1].codeBegin = fragmentCode;
kernelDescs[1].codeEnd = fragmentCode + fragmentCodeSize;
- ShaderProgram::Desc desc;
- desc.pipelineType = PipelineType::Graphics;
- desc.kernels = &kernelDescs[0];
- desc.kernelCount = kDescCount;
-
- shaderProgram = renderer->createProgram(desc);
+ out.set(PipelineType::Graphics, kernelDescs, kDescCount);
}
}
- // We clean up the Slang compilation context and result *after*
- // we have run the downstream compiler, because Slang
- // owns the memory allocation for the generated text, and will
- // free it when we destroy the compilation result.
- spDestroyCompileRequest(slangRequest);
-
- return shaderProgram;
+
+ return SLANG_OK;
}
} // renderer_test
diff --git a/tools/render-test/slang-support.h b/tools/render-test/slang-support.h
index a9b8c8871..662098546 100644
--- a/tools/render-test/slang-support.h
+++ b/tools/render-test/slang-support.h
@@ -9,17 +9,52 @@
namespace renderer_test {
-struct ShaderCompiler
+struct ShaderCompilerUtil
{
- RefPtr<Renderer> renderer;
- SlangCompileTarget target;
- SlangSourceLanguage sourceLanguage;
- SlangPassThrough passThrough;
- char const* profile;
- SlangSession* slangSession;
-
- RefPtr<ShaderProgram> compileProgram(
- ShaderCompileRequest const& request);
+ struct Input
+ {
+ SlangCompileTarget target;
+ SlangSourceLanguage sourceLanguage;
+ SlangPassThrough passThrough;
+ char const* profile;
+ const char** args;
+ int argCount;
+ };
+
+ struct Output
+ {
+ void set(PipelineType pipelineType, const ShaderProgram::KernelDesc* inKernelDescs, int kernelDescCount)
+ {
+ kernelDescs.clear();
+ kernelDescs.addRange(inKernelDescs, kernelDescCount);
+ desc.pipelineType = pipelineType;
+ desc.kernels = kernelDescs.getBuffer();
+ desc.kernelCount = kernelDescCount;
+ }
+ void reset()
+ {
+ kernelDescs.clear();
+ if (request && session)
+ {
+ spDestroyCompileRequest(request);
+ }
+ session = nullptr;
+ request = nullptr;
+ }
+ ~Output()
+ {
+ if (request && session)
+ {
+ spDestroyCompileRequest(request);
+ }
+ }
+ List<ShaderProgram::KernelDesc> kernelDescs;
+ ShaderProgram::Desc desc;
+ SlangCompileRequest* request = nullptr;
+ SlangSession* session = nullptr;
+ };
+
+ static SlangResult compileProgram(SlangSession* session, const Input& input, const ShaderCompileRequest& request, Output& out);
};
diff --git a/tools/slang-test/options.h b/tools/slang-test/options.h
index c78952625..a210a7558 100644
--- a/tools/slang-test/options.h
+++ b/tools/slang-test/options.h
@@ -84,7 +84,7 @@ struct Options
// By default we potentially synthesize test for all
// TODO: Vulkan is disabled by default for now as the majority as vulkan synthesized tests
// OpenGL is disabled for now
- Slang::RenderApiFlags synthesizedTestApis = Slang::RenderApiFlag::AllOf & ~(Slang::RenderApiFlag::Vulkan | Slang::RenderApiFlag::OpenGl);
+ Slang::RenderApiFlags synthesizedTestApis = Slang::RenderApiFlag::AllOf & ~(Slang::RenderApiFlag::Vulkan | Slang::RenderApiFlag::OpenGl | Slang::RenderApiFlag::CPU);
// The adapter to use. If empty will match first found adapter.
Slang::String adapter;
diff --git a/tools/slang-test/slang-test-main.cpp b/tools/slang-test/slang-test-main.cpp
index 4a830fd92..63e2456d9 100644
--- a/tools/slang-test/slang-test-main.cpp
+++ b/tools/slang-test/slang-test-main.cpp
@@ -690,6 +690,11 @@ static SlangResult _extractRenderTestRequirements(const CommandLine& cmdLine, Te
nativeLanguage = SLANG_SOURCE_LANGUAGE_GLSL;
passThru = SLANG_PASS_THROUGH_GLSLANG;
break;
+ case RenderApiType::CPU:
+ target = SLANG_HOST_CALLABLE;
+ nativeLanguage = SLANG_SOURCE_LANGUAGE_CPP;
+ passThru = SLANG_PASS_THROUGH_GENERIC_C_CPP;
+ break;
}
SlangSourceLanguage sourceLanguage = nativeLanguage;
@@ -780,6 +785,15 @@ static RenderApiFlags _getAvailableRenderApiFlags(TestContext* context)
{
const RenderApiType apiType = RenderApiType(i);
+ if (apiType == RenderApiType::CPU)
+ {
+ // TODO(JS): Only enable CPU on Windows for now
+#if SLANG_WINDOWS_FAMILY
+ availableRenderApiFlags |= RenderApiFlags(1) << int(apiType);
+#endif
+ continue;
+ }
+
// See if it's possible the api is available
if (RenderApiUtil::calcHasApi(apiType))
{
@@ -2656,7 +2670,7 @@ void runTestsOnFile(
const RenderApiFlags availableRenderApiFlags = apiUsedFlags ? _getAvailableRenderApiFlags(context) : 0;
// If synthesized tests are wanted look into adding them
- if (context->options.synthesizedTestApis && availableRenderApiFlags)
+ if (context->options.synthesizedTestApis && availableRenderApiFlags)
{
List<TestDetails> synthesizedTests;