diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2019-08-19 14:08:57 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-08-19 14:08:57 -0400 |
| commit | dc6d0417b137c8ecdcb3b99b7624358bba7fefa8 (patch) | |
| tree | 326fe7f93b08431685c6b01052c2eee18168776b | |
| parent | c4541e83b4a57d8317932bc4277ee6a2d45bb2f6 (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.cpp | 8 | ||||
| -rw-r--r-- | source/core/slang-render-api-util.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-compiler.cpp | 38 | ||||
| -rw-r--r-- | tests/compute/array-param.slang | 4 | ||||
| -rw-r--r-- | tests/compute/bit-cast.slang | 3 | ||||
| -rw-r--r-- | tests/compute/slang-cpp-prelude.h | 826 | ||||
| -rw-r--r-- | tests/cross-compile/slang-cpp-prelude.h | 5 | ||||
| -rw-r--r-- | tools/gfx/render.cpp | 2 | ||||
| -rw-r--r-- | tools/gfx/render.h | 2 | ||||
| -rw-r--r-- | tools/render-test/options.cpp | 1 | ||||
| -rw-r--r-- | tools/render-test/render-test-main.cpp | 643 | ||||
| -rw-r--r-- | tools/render-test/shader-input-layout.cpp | 30 | ||||
| -rw-r--r-- | tools/render-test/shader-input-layout.h | 7 | ||||
| -rw-r--r-- | tools/render-test/slang-support.cpp | 49 | ||||
| -rw-r--r-- | tools/render-test/slang-support.h | 55 | ||||
| -rw-r--r-- | tools/slang-test/options.h | 2 | ||||
| -rw-r--r-- | tools/slang-test/slang-test-main.cpp | 16 |
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; |
