summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/cpu-target.md17
-rw-r--r--source/core/slang-cpp-compiler.h3
-rw-r--r--source/core/slang-random-generator.cpp24
-rw-r--r--source/core/slang-random-generator.h8
-rw-r--r--source/core/slang-visual-studio-compiler-util.cpp9
-rw-r--r--source/slang/slang-compiler.cpp6
-rw-r--r--source/slang/slang-emit-cpp.cpp221
-rw-r--r--source/slang/slang-emit-cpp.h4
-rw-r--r--tests/compute/array-param.slang2
-rw-r--r--tools/gfx/render.h3
-rw-r--r--tools/render-test/cpu-compute-util.cpp45
-rw-r--r--tools/render-test/options.cpp13
-rw-r--r--tools/render-test/options.h4
-rw-r--r--tools/render-test/render-test-main.cpp6
-rw-r--r--tools/render-test/shader-input-layout.cpp161
-rw-r--r--tools/render-test/shader-input-layout.h3
-rw-r--r--tools/render-test/slang-support.cpp21
-rw-r--r--tools/render-test/slang-support.h2
18 files changed, 469 insertions, 83 deletions
diff --git a/docs/cpu-target.md b/docs/cpu-target.md
index d4ef6ddd8..ac1499218 100644
--- a/docs/cpu-target.md
+++ b/docs/cpu-target.md
@@ -112,6 +112,23 @@ When compiled into a shared library/dll - how is it invoked? The entry point is
void computeMain(ComputeVaryingInput* varyingInput, UniformEntryPointParams* uniformParams, UniformState* uniformState);
```
+
+If compiled with `SLANG_HOST_CALLABLE` the `ISlangSharedLibrary` will export a function named `computeMain` the same name as the entry point in the original source.
+
+ComputeVaryingInput is defined in the prelude as
+
+```
+struct ComputeVaryingInput
+{
+ uint3 groupID;
+ uint3 groupThreadID;
+};
+```
+
+Typically when invoking the kernel it is a question of updating the groupID/groupThreadID, to specify which 'thread' of the computation to execute. For the example above we have `[numthreads(4, 1, 1)]`. This means groupThreadID.x can vary from 0-3 and .y and .z must be 0. That groupID.x indicates which 'group of 4' to execute. So groupID.x = 1, with groupThreadID.x=0,1,2,3 runs the 4th, 5th, 6th and 7th 'thread'. Being able to invoke each thread in this way is flexible - in that any specific thread can specified and executed. It is not necessarily very efficient because there is the call overhead and a small amount of extra work that is performed inside the kernel.
+
+For improved performance there is a mechanism to execute a 'thread group' all in a single invocation. A function with the same signature will be exposed with the entry point name postfixed with `_Group` - in the example above the function would be called 'computeMain_Group'. When calling this function only the groupID need be specified, the groupThreadID is ignored. All of the threads within the group (as specified by `[numthreads]`) will be executed in a single call.
+
The UniformState and UniformEntryPointParams struct typically vary by shader. UniformState holds 'normal' bindings, whereas UniformEntryPointParams hold the uniform entry point parameters. Where specific bindings or parameters are located can be determined by reflection. The structures for the example above would be something like the following...
```
diff --git a/source/core/slang-cpp-compiler.h b/source/core/slang-cpp-compiler.h
index 22c17606a..f1592d240 100644
--- a/source/core/slang-cpp-compiler.h
+++ b/source/core/slang-cpp-compiler.h
@@ -95,7 +95,8 @@ public:
enum Enum : Flags
{
EnableExceptionHandling = 0x01,
- Verbose = 0x02,
+ Verbose = 0x02,
+ EnableSecurityChecks = 0x04,
};
};
diff --git a/source/core/slang-random-generator.cpp b/source/core/slang-random-generator.cpp
index 7e8476c30..ce43067aa 100644
--- a/source/core/slang-random-generator.cpp
+++ b/source/core/slang-random-generator.cpp
@@ -32,15 +32,33 @@ int64_t RandomGenerator::nextInt64()
return (int64_t(high) << 32) | low;
}
-int32_t RandomGenerator::nextInt32InRange(int32_t min, int32_t max)
+uint32_t RandomGenerator::nextUInt32InRange(uint32_t min, uint32_t max)
{
- int32_t diff = max - min;
+ // Make sure max is at least in
+ max = (max >= min) ? max : min;
+
+ // Make 64 bit so can be lazier than having to take care of 32 bit overflow/underflow issues
+ uint32_t diff = max - min;
if (diff <= 1)
{
return min;
}
+ return (nextUInt32() % diff) + min;
+}
- return (nextPositiveInt32() % diff) + min;
+
+int32_t RandomGenerator::nextInt32InRange(int32_t min, int32_t max)
+{
+ // Make sure max is at least in
+ max = (max >= min) ? max : min;
+
+ // Make 64 bit so can be lazier than having to take care of 32 bit overflow/underflow issues
+ uint32_t diff = uint32_t(int64_t(max) - int64_t(min));
+ if (diff <= 1)
+ {
+ return min;
+ }
+ return int32_t(int64_t(nextUInt32() % diff) + min);
}
int64_t RandomGenerator::nextInt64InRange(int64_t min, int64_t max)
diff --git a/source/core/slang-random-generator.h b/source/core/slang-random-generator.h
index 8b4d1759b..57f0e8630 100644
--- a/source/core/slang-random-generator.h
+++ b/source/core/slang-random-generator.h
@@ -30,6 +30,9 @@ class RandomGenerator: public RefObject
/// Get the next bool
virtual bool nextBool();
+ /// Next uint32_t
+ uint32_t nextUInt32() { return uint32_t(nextInt32()); }
+
/// Next Int32 which can only be positive
int32_t nextPositiveInt32() { return nextInt32() & 0x7fffffff; }
/// Next Int64 which can only be positive
@@ -38,9 +41,12 @@ class RandomGenerator: public RefObject
/// Returns value up to BUT NOT INCLUDING maxValue.
int32_t nextInt32UpTo(int32_t maxValue) { assert(maxValue > 0); return (maxValue <= 1) ? 0 : (nextPositiveInt32() % maxValue); }
- /// Returns value from min up to BUT NOT INCLUDING max
+ /// Returns value from min up to BUT NOT INCLUDING max.
int32_t nextInt32InRange(int32_t min, int32_t max);
+ /// Returns value from min up to BUT NOT INCLUDING max
+ uint32_t nextUInt32InRange(uint32_t min, uint32_t max);
+
/// Returns value up to BUT NOT INCLUDING maxValue
int64_t nextInt64UpTo(int64_t maxValue) { assert(maxValue > 0); return (maxValue <= 1) ? 0 : (nextPositiveInt64() % maxValue); }
diff --git a/source/core/slang-visual-studio-compiler-util.cpp b/source/core/slang-visual-studio-compiler-util.cpp
index 48ef108e4..3d0cfdc61 100644
--- a/source/core/slang-visual-studio-compiler-util.cpp
+++ b/source/core/slang-visual-studio-compiler-util.cpp
@@ -95,6 +95,15 @@ namespace Slang
// Doesn't appear to be a VS equivalent
}
+ if (options.flags & CompileOptions::Flag::EnableSecurityChecks)
+ {
+ cmdLine.addArg("/GS");
+ }
+ else
+ {
+ cmdLine.addArg("/GS-");
+ }
+
switch (options.debugInfoType)
{
default:
diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp
index 2d5557371..dbb900ab6 100644
--- a/source/slang/slang-compiler.cpp
+++ b/source/slang/slang-compiler.cpp
@@ -1357,11 +1357,15 @@ SlangResult dissassembleDXILUsingDXC(
}
}
- CPPCompiler::CompileOptions options;
+ typedef CPPCompiler::CompileOptions CompileOptions;
+ CompileOptions options;
// Set the source type
options.sourceType = (rawSourceLanguage == SourceLanguage::C) ? CPPCompiler::SourceType::C : CPPCompiler::SourceType::CPP;
+ // Disable exceptions and security checks
+ options.flags &= ~(CompileOptions::Flag::EnableExceptionHandling | CompileOptions::Flag::EnableSecurityChecks);
+
// Generate a path a temporary filename for output module
String modulePath;
SLANG_RETURN_ON_FAIL(File::generateTemporary(UnownedStringSlice::fromLiteral("slang-generated"), modulePath));
diff --git a/source/slang/slang-emit-cpp.cpp b/source/slang/slang-emit-cpp.cpp
index a5173549a..df6d1bee8 100644
--- a/source/slang/slang-emit-cpp.cpp
+++ b/source/slang/slang-emit-cpp.cpp
@@ -2463,6 +2463,103 @@ struct GlobalParamInfo
UInt size;
};
+void CPPSourceEmitter::_emitEntryPointDefinitionStart(IRFunc* func, IRGlobalParam* entryPointGlobalParams, const String& funcName)
+{
+ auto resultType = func->getResultType();
+
+ auto entryPointLayout = asEntryPoint(func);
+
+ // Emit the actual function
+ emitEntryPointAttributes(func, entryPointLayout);
+ emitType(resultType, funcName);
+
+ m_writer->emit("(ComputeVaryingInput* varyingInput, UniformEntryPointParams* params, UniformState* uniformState)\n{\n");
+ emitSemantics(func);
+
+ m_writer->indent();
+ // Initialize when constructing so that globals are zeroed
+ m_writer->emit("Context context = {};\n");
+ m_writer->emit("context.uniformState = uniformState;\n");
+ m_writer->emit("context.varyingInput = *varyingInput;\n");
+
+ if (entryPointGlobalParams)
+ {
+ auto varDecl = entryPointGlobalParams;
+ auto rawType = varDecl->getDataType();
+
+ auto varType = rawType;
+
+ m_writer->emit("context.");
+ m_writer->emit(getName(varDecl));
+ m_writer->emit(" = (");
+ emitType(varType);
+ m_writer->emit("*)params; \n");
+ }
+}
+
+void CPPSourceEmitter::_emitEntryPointDefinitionEnd(IRFunc* func)
+{
+ SLANG_UNUSED(func);
+ m_writer->dedent();
+ m_writer->emit("}\n");
+}
+
+// We want to order such that the largest range is the inner loop
+
+void CPPSourceEmitter::_emitEntryPointGroup(const UInt sizeAlongAxis[3], const String& funcName)
+{
+ struct AxisWithSize
+ {
+ typedef AxisWithSize ThisType;
+ bool operator<(const ThisType& rhs) const { return size < rhs.size; }
+
+ int axis;
+ UInt size;
+ };
+ List<AxisWithSize> axes;
+
+ for (int i = 0; i < 3; ++i)
+ {
+ if (sizeAlongAxis[i] > 1)
+ {
+ AxisWithSize axisWithSize;
+ axisWithSize.axis = i;
+ axisWithSize.size = sizeAlongAxis[i];
+ axes.add(axisWithSize);
+ }
+ }
+
+ axes.sort();
+
+ // Open all the loops
+ StringBuilder builder;
+ for (Index i = 0; i < axes.getCount(); ++i)
+ {
+ const auto& axis = axes[i];
+ builder.Clear();
+ const char elem[2] = { s_elemNames[axis.axis], 0 };
+ builder << "for (uint32_t " << elem << " = start." << elem << "; " << elem << " < start." << elem << " + " << axis.size << "; ++" << elem << ")\n{\n";
+ m_writer->emit(builder);
+ m_writer->indent();
+
+ builder.Clear();
+ builder << "context.dispatchThreadID." << elem << " = " << elem << ";\n";
+ m_writer->emit(builder);
+ }
+
+ // just call at inner loop point
+ m_writer->emit("context._");
+ m_writer->emit(funcName);
+ m_writer->emit("();\n");
+
+ // Close all the loops
+ for (Index i = Index(axes.getCount() - 1); i >= 0; --i)
+ {
+ m_writer->dedent();
+ m_writer->emit("}\n");
+ }
+}
+
void CPPSourceEmitter::emitModuleImpl(IRModule* module)
{
List<EmitAction> actions;
@@ -2600,77 +2697,93 @@ void CPPSourceEmitter::emitModuleImpl(IRModule* module)
auto entryPointLayout = asEntryPoint(func);
if (entryPointLayout)
{
- auto resultType = func->getResultType();
- auto name = getFuncName(func);
+ // https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/sv-dispatchthreadid
+ // SV_DispatchThreadID is the sum of SV_GroupID * numthreads and GroupThreadID.
- // Emit the actual function
- emitEntryPointAttributes(func, entryPointLayout);
- emitType(resultType, name);
+ static const UInt kAxisCount = 3;
+ UInt sizeAlongAxis[kAxisCount];
- m_writer->emit("(ComputeVaryingInput* varyingInput, UniformEntryPointParams* params, UniformState* uniformState)\n{\n");
- emitSemantics(func);
+ String funcName = getFuncName(func);
- m_writer->indent();
- // Initialize when constructing so that globals are zeroed
- m_writer->emit("Context context = {};\n");
- m_writer->emit("context.uniformState = uniformState;\n");
- m_writer->emit("context.varyingInput = *varyingInput;\n");
+ {
+ _emitEntryPointDefinitionStart(func, entryPointGlobalParams, funcName);
- if (entryPointGlobalParams)
- {
- auto varDecl = entryPointGlobalParams;
- auto rawType = varDecl->getDataType();
+ // Emit dispatchThreadID
+ if (entryPointLayout->profile.GetStage() == Stage::Compute)
+ {
+ // TODO: this is kind of gross because we are using a public
+ // reflection API function, rather than some kind of internal
+ // utility it forwards to...
+ spReflectionEntryPoint_getComputeThreadGroupSize((SlangReflectionEntryPoint*)entryPointLayout, kAxisCount, &sizeAlongAxis[0]);
- auto varType = rawType;
+ m_writer->emit("context.dispatchThreadID = {\n");
+ m_writer->indent();
- m_writer->emit("context.");
- m_writer->emit(getName(varDecl));
- m_writer->emit(" = (");
- emitType(varType);
- m_writer->emit("*)params; \n");
- }
-
- // Emit dispatchThreadID
- if (entryPointLayout->profile.GetStage() == Stage::Compute)
- {
- // https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/sv-dispatchthreadid
- // SV_DispatchThreadID is the sum of SV_GroupID * numthreads and GroupThreadID.
+ StringBuilder builder;
+ for (int i = 0; i < kAxisCount; ++i)
+ {
+ builder.Clear();
+ const char elem[2] = {s_elemNames[i], 0};
+ builder << "varyingInput->groupID." << elem << " * " << sizeAlongAxis[i] << " + varyingInput->groupThreadID." << elem;
+ if (i < kAxisCount - 1)
+ {
+ builder << ",";
+ }
+ builder << "\n";
+ m_writer->emit(builder);
+ }
- static const UInt kAxisCount = 3;
- UInt sizeAlongAxis[kAxisCount];
+ m_writer->dedent();
+ m_writer->emit("};\n");
+ }
- // TODO: this is kind of gross because we are using a public
- // reflection API function, rather than some kind of internal
- // utility it forwards to...
- spReflectionEntryPoint_getComputeThreadGroupSize((SlangReflectionEntryPoint*)entryPointLayout, kAxisCount, &sizeAlongAxis[0]);
+ m_writer->emit("context._");
+ m_writer->emit(funcName);
+ m_writer->emit("();\n");
- m_writer->emit("context.dispatchThreadID = {\n");
- m_writer->indent();
+ _emitEntryPointDefinitionEnd(func);
+ }
+ // Emit the group version which runs for all elements in a thread group
+ {
StringBuilder builder;
-
- for (int i = 0; i < kAxisCount; ++i)
+ builder << getFuncName(func);
+ builder << "_Group";
+
+ String groupFuncName = builder;
+
+ _emitEntryPointDefinitionStart(func, entryPointGlobalParams, groupFuncName);
+
+ // Emit dispatchThreadID
+ if (entryPointLayout->profile.GetStage() == Stage::Compute)
{
- builder.Clear();
- const char elem[2] = {s_elemNames[i], 0};
- builder << "varyingInput->groupID." << elem << " * " << sizeAlongAxis[i] << " + varyingInput->groupThreadID." << elem;
- if (i < kAxisCount - 1)
+ spReflectionEntryPoint_getComputeThreadGroupSize((SlangReflectionEntryPoint*)entryPointLayout, kAxisCount, &sizeAlongAxis[0]);
+
{
- builder << ",";
+ m_writer->emit("const uint3 start = {\n");
+ m_writer->indent();
+ for (int i = 0; i < kAxisCount; ++i)
+ {
+ builder.Clear();
+ const char elem[2] = { s_elemNames[i], 0 };
+ builder << "varyingInput->groupID." << elem << " * " << sizeAlongAxis[i];
+ if (i < kAxisCount - 1)
+ {
+ builder << ",";
+ }
+ builder << "\n";
+ m_writer->emit(builder);
+ }
+ m_writer->dedent();
+ m_writer->emit("};\n");
}
- builder << "\n";
- m_writer->emit(builder);
+ m_writer->emit("context.dispatchThreadID = start;\n");
+
+ _emitEntryPointGroup(sizeAlongAxis, funcName);
}
- m_writer->dedent();
- m_writer->emit("};\n");
+ _emitEntryPointDefinitionEnd(func);
}
-
- m_writer->emit("context._");
- m_writer->emit(name);
- m_writer->emit("();\n");
- m_writer->dedent();
- m_writer->emit("}\n");
}
}
}
diff --git a/source/slang/slang-emit-cpp.h b/source/slang/slang-emit-cpp.h
index 6c300320a..906086d71 100644
--- a/source/slang/slang-emit-cpp.h
+++ b/source/slang/slang-emit-cpp.h
@@ -257,6 +257,10 @@ protected:
SlangResult _calcTextureTypeName(IRTextureTypeBase* texType, StringBuilder& outName);
+ void _emitEntryPointDefinitionStart(IRFunc* func, IRGlobalParam* entryPointGlobalParams, const String& funcName);
+ void _emitEntryPointDefinitionEnd(IRFunc* func);
+ void _emitEntryPointGroup(const UInt sizeAlongAxis[3], const String& funcName);
+
Dictionary<SpecializedIntrinsic, StringSlicePool::Handle> m_intrinsicNameMap;
Dictionary<IRType*, StringSlicePool::Handle> m_typeNameMap;
diff --git a/tests/compute/array-param.slang b/tests/compute/array-param.slang
index 1f3ff9799..a5c6bdcca 100644
--- a/tests/compute/array-param.slang
+++ b/tests/compute/array-param.slang
@@ -1,4 +1,4 @@
-//TEST(compute):COMPARE_COMPUTE_EX:-cpu -compute
+//TEST(compute):COMPARE_COMPUTE_EX:-cpu -compute -compile-arg -O3
//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute
//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -dx12
//TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute
diff --git a/tools/gfx/render.h b/tools/gfx/render.h
index 42cf5fe60..30373b356 100644
--- a/tools/gfx/render.h
+++ b/tools/gfx/render.h
@@ -12,6 +12,7 @@
#include "../../source/core/slang-smart-pointer.h"
#include "../../source/core/slang-list.h"
#include "../../source/core/slang-dictionary.h"
+#include "../../source/core/slang-process-util.h"
#include "../../slang.h"
@@ -149,6 +150,8 @@ struct ShaderCompileRequest
Slang::List<Slang::String> entryPointGenericTypeArguments;
Slang::List<Slang::String> entryPointExistentialTypeArguments;
Slang::List<Slang::String> globalExistentialTypeArguments;
+
+ Slang::List<Slang::CommandLine::Arg> compileArgs;
};
/// Different formats of things like pixels or elements of vertices
diff --git a/tools/render-test/cpu-compute-util.cpp b/tools/render-test/cpu-compute-util.cpp
index 85a8fb1b0..4294ad539 100644
--- a/tools/render-test/cpu-compute-util.cpp
+++ b/tools/render-test/cpu-compute-util.cpp
@@ -316,6 +316,7 @@ static CPUComputeUtil::Resource* _newOneTexture2D(int elemCount)
slang::EntryPointReflection* entryPoint = nullptr;
Func func = nullptr;
+ Func groupFunc = nullptr;
{
auto entryPointCount = reflection->getEntryPointCount();
SLANG_ASSERT(entryPointCount == 1);
@@ -325,15 +326,19 @@ static CPUComputeUtil::Resource* _newOneTexture2D(int elemCount)
const char* entryPointName = entryPoint->getName();
func = (Func)sharedLibrary->findFuncByName(entryPointName);
- if (!func)
+ StringBuilder groupEntryPointName;
+ groupEntryPointName << entryPointName << "_Group";
+
+ groupFunc = (Func)sharedLibrary->findFuncByName(groupEntryPointName.getBuffer());
+
+ if (func == nullptr && groupFunc == nullptr)
{
return SLANG_FAIL;
}
}
- SlangUInt numThreadsPerAxis[3];
- entryPoint->getComputeThreadGroupSize(3, numThreadsPerAxis);
-
+ // If we have the group function, that's the faster way to execute all threads in group...
+ if (groupFunc)
{
UniformState* uniformState = (UniformState*)context.binding.m_rootBuffer.m_data;
CPPPrelude::UniformEntryPointParams* uniformEntryPointParams = (CPPPrelude::UniformEntryPointParams*)context.binding.m_entryPointBuffer.m_data;
@@ -341,17 +346,33 @@ static CPUComputeUtil::Resource* _newOneTexture2D(int elemCount)
CPPPrelude::ComputeVaryingInput varying;
varying.groupID = {};
- for (int z = 0; z < int(numThreadsPerAxis[2]); ++z)
+ groupFunc(&varying, uniformEntryPointParams, uniformState);
+ }
+ else
+ {
+ // We can also fire off each thread individually
+ SlangUInt numThreadsPerAxis[3];
+ entryPoint->getComputeThreadGroupSize(3, numThreadsPerAxis);
+
{
- varying.groupThreadID.z = z;
- for (int y = 0; y < int(numThreadsPerAxis[1]); ++y)
+ UniformState* uniformState = (UniformState*)context.binding.m_rootBuffer.m_data;
+ CPPPrelude::UniformEntryPointParams* uniformEntryPointParams = (CPPPrelude::UniformEntryPointParams*)context.binding.m_entryPointBuffer.m_data;
+
+ CPPPrelude::ComputeVaryingInput varying;
+ varying.groupID = {};
+
+ for (int z = 0; z < int(numThreadsPerAxis[2]); ++z)
{
- varying.groupThreadID.y = y;
- for (int x = 0; x < int(numThreadsPerAxis[0]); ++x)
+ varying.groupThreadID.z = z;
+ for (int y = 0; y < int(numThreadsPerAxis[1]); ++y)
{
- varying.groupThreadID.x = x;
+ varying.groupThreadID.y = y;
+ for (int x = 0; x < int(numThreadsPerAxis[0]); ++x)
+ {
+ varying.groupThreadID.x = x;
- func(&varying, uniformEntryPointParams, uniformState);
+ func(&varying, uniformEntryPointParams, uniformState);
+ }
}
}
}
@@ -360,6 +381,4 @@ static CPUComputeUtil::Resource* _newOneTexture2D(int elemCount)
return SLANG_OK;
}
-
-
} // renderer_test
diff --git a/tools/render-test/options.cpp b/tools/render-test/options.cpp
index a9e51b8e0..1cf0ffbe8 100644
--- a/tools/render-test/options.cpp
+++ b/tools/render-test/options.cpp
@@ -156,6 +156,19 @@ SlangResult parseOptions(int argc, const char*const* argv, Slang::WriterHelper s
{
gOptions.onlyStartup = true;
}
+ else if (strcmp(arg, "-compile-arg") == 0)
+ {
+ if (argCursor == argEnd)
+ {
+ stdError.print("expected argument for '%s' option\n", arg);
+ return SLANG_FAIL;
+ }
+
+ CommandLine::Arg arg;
+ arg.type = CommandLine::ArgType::Escaped;
+ arg.value = *argCursor++;
+ gOptions.compileArgs.add(arg);
+ }
else if (strcmp(arg, "-adapter") == 0)
{
if (argCursor == argEnd)
diff --git a/tools/render-test/options.h b/tools/render-test/options.h
index 0214c66e7..a57c94ed0 100644
--- a/tools/render-test/options.h
+++ b/tools/render-test/options.h
@@ -6,6 +6,8 @@
#include "../../slang-com-helper.h"
#include "../../source/core/slang-writer.h"
+#include "../../source/core/slang-process-util.h"
+
#include "render.h"
namespace renderer_test {
@@ -59,6 +61,8 @@ struct Options
Slang::List<Slang::String> renderFeatures; /// Required render features for this test to run
+ Slang::List<Slang::CommandLine::Arg> compileArgs;
+
Slang::String adapter; ///< The adapter to use either name or index
};
diff --git a/tools/render-test/render-test-main.cpp b/tools/render-test/render-test-main.cpp
index d2ef2a746..0e457f9e4 100644
--- a/tools/render-test/render-test-main.cpp
+++ b/tools/render-test/render-test-main.cpp
@@ -198,7 +198,7 @@ SlangResult RenderTestApp::initialize(SlangSession* session, Renderer* renderer,
Result RenderTestApp::_initializeShaders(SlangSession* session, Renderer* renderer, Options::ShaderProgramType shaderType, const ShaderCompilerUtil::Input& input)
{
ShaderCompilerUtil::OutputAndLayout output;
- SLANG_RETURN_ON_FAIL(ShaderCompilerUtil::compileWithLayout(session, gOptions.sourcePath, shaderType, input, output));
+ SLANG_RETURN_ON_FAIL(ShaderCompilerUtil::compileWithLayout(session, gOptions.sourcePath, gOptions.compileArgs, gOptions.shaderType, input, output));
m_shaderInputLayout = output.layout;
m_shaderProgram = renderer->createProgram(output.output.desc);
return m_shaderProgram ? SLANG_OK : SLANG_FAIL;
@@ -457,7 +457,7 @@ SLANG_TEST_TOOL_API SlangResult innerMain(Slang::StdWriters* stdWriters, SlangSe
}
ShaderCompilerUtil::OutputAndLayout compilationAndLayout;
- SLANG_RETURN_ON_FAIL(ShaderCompilerUtil::compileWithLayout(session, gOptions.sourcePath, gOptions.shaderType, input, compilationAndLayout));
+ SLANG_RETURN_ON_FAIL(ShaderCompilerUtil::compileWithLayout(session, gOptions.sourcePath, gOptions.compileArgs, gOptions.shaderType, input, compilationAndLayout));
CPUComputeUtil::Context context;
SLANG_RETURN_ON_FAIL(CPUComputeUtil::calcBindings(compilationAndLayout, context));
@@ -467,9 +467,7 @@ SLANG_TEST_TOOL_API SlangResult innerMain(Slang::StdWriters* stdWriters, SlangSe
return CPUComputeUtil::writeBindings(compilationAndLayout.layout, context.buffers, gOptions.outputPath);
}
- // Renderer is constructed (later) using the window
Slang::RefPtr<Renderer> renderer;
-
{
RendererUtil::CreateFunc createFunc = RendererUtil::getCreateFunc(gOptions.rendererType);
if (createFunc)
diff --git a/tools/render-test/shader-input-layout.cpp b/tools/render-test/shader-input-layout.cpp
index 7f75805e9..11c87c0d9 100644
--- a/tools/render-test/shader-input-layout.cpp
+++ b/tools/render-test/shader-input-layout.cpp
@@ -7,6 +7,36 @@ namespace renderer_test
{
using namespace Slang;
+#define SLANG_SCALAR_TYPES(x) \
+ x("int", INT32) \
+ x("uint", UINT32) \
+ x("float", FLOAT32)
+
+ struct TypeInfo
+ {
+ UnownedStringSlice name;
+ SlangScalarType type;
+ };
+
+#define SLANG_SCALAR_TYPE_INFO(name, value) { UnownedStringSlice::fromLiteral(name), SLANG_SCALAR_TYPE_##value },
+ static const TypeInfo g_scalarTypeInfos[] =
+ {
+ SLANG_SCALAR_TYPES(SLANG_SCALAR_TYPE_INFO)
+ };
+#undef SLANG_SCALAR_TYPES
+#undef SLANG_SCALAR_TYPE_INFO
+
+ static SlangScalarType _getScalarType(const UnownedStringSlice& slice)
+ {
+ for (const auto& info : g_scalarTypeInfos)
+ {
+ if (info.name == slice)
+ {
+ return info.type;
+ }
+ }
+ return SLANG_SCALAR_TYPE_NONE;
+ }
Index ShaderInputLayout::findEntryIndexByName(const String& name) const
{
@@ -56,7 +86,7 @@ namespace renderer_test
}
}
- void ShaderInputLayout::parse(const char * source)
+ void ShaderInputLayout::parse(RandomGenerator* rand, const char * source)
{
entries.clear();
globalGenericTypeArguments.clear();
@@ -225,9 +255,138 @@ namespace renderer_test
parser.Read("=");
entry.textureDesc.size = parser.ReadInt();
}
+ else if (word == "random")
+ {
+ parser.Read("(");
+ // Read the type
+ String type = parser.ReadWord();
+ SlangScalarType scalarType = _getScalarType(type.getUnownedSlice());
+ if (scalarType == SLANG_SCALAR_TYPE_NONE)
+ {
+ StringBuilder builder;
+ for (const auto& info : g_scalarTypeInfos)
+ {
+ if (builder.getLength() != 0)
+ {
+ builder << ", ";
+ }
+ builder << info.name;
+ }
+
+ throw TextFormatException("Expecting " + builder + " " + parser.NextToken().Position.Line);
+ }
+
+ parser.Read(",");
+ const int size = int(parser.ReadUInt());
+
+ switch (scalarType)
+ {
+ case SLANG_SCALAR_TYPE_INT32:
+ {
+ bool hasRange = false;
+
+ int32_t minValue = -0x7fffffff - 1;
+ int32_t maxValue = 0x7fffffff;
+
+ if (parser.LookAhead(","))
+ {
+ hasRange = true;
+ parser.ReadToken();
+ minValue = parser.ReadInt();
+
+ if (parser.LookAhead(","))
+ {
+ parser.ReadToken();
+ maxValue = parser.ReadInt();
+ }
+ }
+ SLANG_ASSERT(minValue <= maxValue);
+ maxValue = (maxValue >= minValue) ? maxValue : minValue;
+
+ // Generate the data
+ entry.bufferData.setCount(size);
+
+ int32_t* dst = (int32_t*)entry.bufferData.getBuffer();
+ for (int i = 0; i < size; ++i)
+ {
+ dst[i] = hasRange ? rand->nextInt32InRange(minValue, maxValue) : rand->nextInt32();
+ }
+ break;
+ }
+ case SLANG_SCALAR_TYPE_UINT32:
+ {
+ bool hasRange = false;
+ uint32_t minValue = 0;
+ uint32_t maxValue = 0xffffffff;
+
+ if (parser.LookAhead(","))
+ {
+ parser.ReadToken();
+ minValue = parser.ReadUInt();
+
+ hasRange = true;
+
+ if (parser.LookAhead(","))
+ {
+ parser.ReadToken();
+ maxValue = parser.ReadUInt();
+ }
+ }
+
+ SLANG_ASSERT(minValue <= maxValue);
+ maxValue = (maxValue >= minValue) ? maxValue : minValue;
+
+ // Generate the data
+ entry.bufferData.setCount(size);
+
+ uint32_t* dst = (uint32_t*)entry.bufferData.getBuffer();
+ for (int i = 0; i < size; ++i)
+ {
+ dst[i] = hasRange ? rand->nextUInt32InRange(minValue, maxValue) : rand->nextUInt32();
+ }
+
+ break;
+ }
+ case SLANG_SCALAR_TYPE_FLOAT32:
+ {
+ float minValue = -1.0f;
+ float maxValue = 1.0f;
+
+ if (parser.LookAhead(","))
+ {
+ parser.ReadToken();
+ minValue = parser.ReadFloat();
+
+ if (parser.LookAhead(","))
+ {
+ parser.ReadToken();
+ maxValue = parser.ReadFloat();
+ }
+ }
+
+ SLANG_ASSERT(minValue <= maxValue);
+ maxValue = (maxValue >= minValue) ? maxValue : minValue;
+
+ // Generate the data
+ entry.bufferData.setCount(size);
+
+ float* dst = (float*)entry.bufferData.getBuffer();
+ for (int i = 0; i < size; ++i)
+ {
+ dst[i] = (rand->nextUnitFloat32() * (maxValue - minValue)) + minValue;
+ }
+ break;
+ }
+ }
+
+ // Read the range
+
+ parser.Read(")");
+ }
else if (word == "data")
{
parser.Read("=");
+
parser.Read("[");
while (!parser.IsEnd() && !parser.LookAhead("]"))
{
diff --git a/tools/render-test/shader-input-layout.h b/tools/render-test/shader-input-layout.h
index 2a58bfd2c..009be7514 100644
--- a/tools/render-test/shader-input-layout.h
+++ b/tools/render-test/shader-input-layout.h
@@ -2,6 +2,7 @@
#define SLANG_TEST_SHADER_INPUT_LAYOUT_H
#include "core/slang-basic.h"
+#include "core/slang-random-generator.h"
#include "render.h"
@@ -88,7 +89,7 @@ public:
void updateForTarget(SlangCompileTarget target);
- void parse(const char* source);
+ void parse(Slang::RandomGenerator* rand, 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 df7e91df8..515481d4f 100644
--- a/tools/render-test/slang-support.cpp
+++ b/tools/render-test/slang-support.cpp
@@ -25,6 +25,17 @@ static const char computeEntryPointName[] = "computeMain";
out.request = slangRequest;
out.session = session;
+ // Parse all the extra args
+ if (request.compileArgs.getCount() > 0)
+ {
+ List<const char*> args;
+ for (const auto& arg : request.compileArgs)
+ {
+ args.add(arg.value.getBuffer());
+ }
+ SLANG_RETURN_ON_FAIL(spProcessCommandLineArguments(slangRequest, args.getBuffer(), int(args.getCount())));
+ }
+
spSetCodeGenTarget(slangRequest, input.target);
spSetTargetProfile(slangRequest, 0, spFindProfile(session, input.profile));
@@ -224,7 +235,7 @@ static const char computeEntryPointName[] = "computeMain";
return SLANG_OK;
}
-/* static */SlangResult ShaderCompilerUtil::compileWithLayout(SlangSession* session, const String& sourcePath, Options::ShaderProgramType shaderType, const ShaderCompilerUtil::Input& input, OutputAndLayout& output)
+/* static */SlangResult ShaderCompilerUtil::compileWithLayout(SlangSession* session, const String& sourcePath, const Slang::List<Slang::CommandLine::Arg>& compileArgs, Options::ShaderProgramType shaderType, const ShaderCompilerUtil::Input& input, OutputAndLayout& output)
{
List<char> sourceText;
SLANG_RETURN_ON_FAIL(readSource(sourcePath, sourceText));
@@ -245,8 +256,11 @@ static const char computeEntryPointName[] = "computeMain";
break;
}
+ // Deterministic random generator
+ RefPtr<RandomGenerator> rand = RandomGenerator::create(0x34234);
+
// Parse the layout
- layout.parse(sourceText.getBuffer());
+ layout.parse(rand, sourceText.getBuffer());
layout.updateForTarget(input.target);
// Setup SourceInfo
@@ -257,6 +271,9 @@ static const char computeEntryPointName[] = "computeMain";
sourceInfo.dataEnd = sourceText.getBuffer() + sourceText.getCount() - 1;
ShaderCompileRequest compileRequest;
+
+ compileRequest.compileArgs = compileArgs;
+
compileRequest.source = sourceInfo;
if (shaderType == Options::ShaderProgramType::Graphics || shaderType == Options::ShaderProgramType::GraphicsCompute)
{
diff --git a/tools/render-test/slang-support.h b/tools/render-test/slang-support.h
index 543ab3258..cd3223c87 100644
--- a/tools/render-test/slang-support.h
+++ b/tools/render-test/slang-support.h
@@ -69,7 +69,7 @@ struct ShaderCompilerUtil
Slang::String sourcePath;
};
- static SlangResult compileWithLayout(SlangSession* session, const Slang::String& sourcePath, Options::ShaderProgramType shaderType, const ShaderCompilerUtil::Input& input, OutputAndLayout& output);
+ static SlangResult compileWithLayout(SlangSession* session, const Slang::String& sourcePath, const Slang::List<Slang::CommandLine::Arg>& compileArgs, Options::ShaderProgramType shaderType, const ShaderCompilerUtil::Input& input, OutputAndLayout& output);
static SlangResult readSource(const Slang::String& inSourcePath, List<char>& outSourceText);