summaryrefslogtreecommitdiffstats
path: root/tools/render-test
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2019-09-09 13:54:31 -0400
committerGitHub <noreply@github.com>2019-09-09 13:54:31 -0400
commit047daae9300c8a94d28383cf992ce00e3ad2da1e (patch)
tree520025463f6493b31d859a812af8a1384a23f715 /tools/render-test
parent4fc07614d6407e49a0c34e7483d410153c0b269a (diff)
CPU compute testing on non windows targets (#1045)
* WIP: Refactor of CPUCompute and stand alone cpu-render-test * Fix compilation on CygWin. * Make CPU compute tests run on non windows targets. * Check that C/C++ compiler is available for CPU compute. * Fix some tabbing issues. * Add -fPIC on gfx * Use dxcompiler_47.dll from slang-binaries on windows. * make https for git module slang-binaries * Fix comment in premake5.lua around d3dcompiler_47.dll * Add resources to the CPUComputeUtil::Context to keep in scope. * Fixes problem compiling on cygwin where dx12 is included in build of gfx lib.
Diffstat (limited to 'tools/render-test')
-rw-r--r--tools/render-test/cpu-compute-util.cpp365
-rw-r--r--tools/render-test/cpu-compute-util.h40
-rw-r--r--tools/render-test/cpu-memory-binding.cpp1
-rw-r--r--tools/render-test/cpu-render-test-main.cpp99
-rw-r--r--tools/render-test/options.cpp2
-rw-r--r--tools/render-test/render-test-main.cpp453
-rw-r--r--tools/render-test/render-test-tool.vcxproj2
-rw-r--r--tools/render-test/render-test-tool.vcxproj.filters6
-rw-r--r--tools/render-test/shader-input-layout.cpp34
-rw-r--r--tools/render-test/slang-support.cpp89
-rw-r--r--tools/render-test/slang-support.h19
11 files changed, 651 insertions, 459 deletions
diff --git a/tools/render-test/cpu-compute-util.cpp b/tools/render-test/cpu-compute-util.cpp
new file mode 100644
index 000000000..85a8fb1b0
--- /dev/null
+++ b/tools/render-test/cpu-compute-util.cpp
@@ -0,0 +1,365 @@
+#define _CRT_SECURE_NO_WARNINGS 1
+
+#include "cpu-compute-util.h"
+
+#include "../../slang-com-helper.h"
+
+#include "../../source/core/slang-std-writers.h"
+#include "../../source/core/slang-token-reader.h"
+
+#define SLANG_PRELUDE_NAMESPACE CPPPrelude
+#include "../../prelude/slang-cpp-types.h"
+
+namespace renderer_test {
+using namespace Slang;
+
+/* static */SlangResult CPUComputeUtil::writeBindings(const ShaderInputLayout& layout, const List<CPUMemoryBinding::Buffer>& buffers, const String& fileName)
+{
+ FILE * f = fopen(fileName.getBuffer(), "wb");
+ if (!f)
+ {
+ return SLANG_FAIL;
+ }
+
+ const auto& entries = layout.entries;
+
+ for (int i = 0; i < entries.getCount(); ++i)
+ {
+ const auto& entry = entries[i];
+ if (entry.isOutput)
+ {
+ const auto& buffer = buffers[i];
+
+ unsigned int* ptr = (unsigned int*)buffer.m_data;
+
+ const int size = int(entry.bufferData.getCount());
+ // Must be the same size or less than allocated buffer
+ SLANG_ASSERT(size * sizeof(unsigned int) <= buffer.m_sizeInBytes);
+
+ for (int i = 0; i < size; ++i)
+ {
+ unsigned int v = ptr[i];
+
+ fprintf(f, "%X\n", v);
+ }
+ }
+ }
+ fclose(f);
+ return SLANG_OK;
+}
+
+
+template <int COUNT>
+struct OneTexture2D : public CPUComputeUtil::Resource, public CPPPrelude::ITexture2D
+{
+ void setOne(void* out)
+ {
+ float* dst = (float*)out;
+ for (int i = 0; i < COUNT; ++i)
+ {
+ dst[i] = 1.0f;
+ }
+ }
+
+ virtual void Load(const CPPPrelude::int3& v, void* out) SLANG_OVERRIDE
+ {
+ setOne(out);
+ }
+ virtual void Sample(CPPPrelude::SamplerState samplerState, const CPPPrelude::float2& loc, void* out) SLANG_OVERRIDE
+ {
+ setOne(out);
+ }
+ virtual void SampleLevel(CPPPrelude::SamplerState samplerState, const CPPPrelude::float2& loc, float level, void* out) SLANG_OVERRIDE
+ {
+ setOne(out);
+ }
+
+ OneTexture2D()
+ {
+ m_interface = static_cast<CPPPrelude::ITexture2D*>(this);
+ }
+};
+
+static CPUComputeUtil::Resource* _newOneTexture2D(int elemCount)
+{
+ switch (elemCount)
+ {
+ case 1: return new OneTexture2D<1>();
+ case 2: return new OneTexture2D<2>();
+ case 3: return new OneTexture2D<3>();
+ case 4: return new OneTexture2D<4>();
+ default: return nullptr;
+ }
+}
+
+/* static */SlangResult CPUComputeUtil::calcBindings(const ShaderCompilerUtil::OutputAndLayout& compilationAndLayout, Context& outContext)
+{
+ auto request = compilationAndLayout.output.request;
+ auto reflection = (slang::ShaderReflection*) spGetReflection(request);
+
+ const auto& sourcePath = compilationAndLayout.sourcePath;
+
+ auto& binding = outContext.binding;
+
+ binding.init(reflection, 0);
+
+ auto& buffers = outContext.buffers;
+ buffers.clear();
+
+ // Okay we need to find all of the bindings and match up to those in the layout
+ const ShaderInputLayout& layout = compilationAndLayout.layout;
+
+ {
+ auto outStream = StdWriters::getOut();
+ auto& entries = layout.entries;
+ buffers.setCount(entries.getCount());
+
+ for (int entryIndex = 0; entryIndex < entries.getCount(); ++entryIndex)
+ {
+ auto& entry = entries[entryIndex];
+
+ if (entry.name.getLength() == 0)
+ {
+ outStream.print("No 'name' specified for resources in '%s'\n", sourcePath.getBuffer());
+ return SLANG_FAIL;
+ }
+
+ // We will parse the 'name' as may be path to a resource
+ TokenReader parser(entry.name);
+
+ CPUMemoryBinding::Location location;
+
+ {
+ Token nameToken = parser.ReadToken();
+ if (nameToken.Type != TokenType::Identifier)
+ {
+ outStream.print("Invalid input syntax at line %d", int(parser.NextToken().Position.Line));
+ return SLANG_FAIL;
+ }
+ location = binding.find(nameToken.Content.getBuffer());
+ if (location.isInvalid())
+ {
+ outStream.print("Unable to find entry in '%s' for '%s' (for CPU name must be specified) \n", sourcePath.getBuffer(), entry.name.getBuffer());
+ return SLANG_FAIL;
+ }
+ }
+
+ while (!parser.IsEnd())
+ {
+ Token token = parser.NextToken(0);
+
+ if (token.Type == TokenType::LBracket)
+ {
+ parser.ReadToken();
+ int index = parser.ReadInt();
+ SLANG_ASSERT(index >= 0);
+
+ location = location.toIndex(index);
+ if (location.isInvalid())
+ {
+ outStream.print("Unable to find entry in '%d' in '%s'\n", index, entry.name.getBuffer());
+ return SLANG_FAIL;
+ }
+ parser.ReadMatchingToken(TokenType::RBracket);
+ }
+ else if (token.Type == TokenType::Dot)
+ {
+ parser.ReadToken();
+ Token identifierToken = parser.ReadMatchingToken(TokenType::Identifier);
+
+ location = location.toField(identifierToken.Content.getBuffer());
+ if (location.isInvalid())
+ {
+ outStream.print("Unable to find field '%s' in '%s'\n", identifierToken.Content.getBuffer(), entry.name.getBuffer());
+ return SLANG_FAIL;
+ }
+ }
+ else if (token.Type == TokenType::Comma)
+ {
+ // Break out
+ break;
+ }
+ else
+ {
+ throw TextFormatException("Invalid input syntax at line " + parser.NextToken().Position.Line);
+ }
+ }
+
+ auto& srcEntry = layout.entries[entryIndex];
+
+ auto typeLayout = location.getTypeLayout();
+ const auto kind = typeLayout->getKind();
+ switch (kind)
+ {
+ case slang::TypeReflection::Kind::Vector:
+ case slang::TypeReflection::Kind::Matrix:
+ case slang::TypeReflection::Kind::Array:
+ case slang::TypeReflection::Kind::Scalar:
+ case slang::TypeReflection::Kind::Struct:
+ {
+ SLANG_RETURN_ON_FAIL(binding.setInplace(location, srcEntry.bufferData.getBuffer(), srcEntry.bufferData.getCount() * sizeof(unsigned int)));
+ break;
+ }
+ default:
+ break;
+ case slang::TypeReflection::Kind::ConstantBuffer:
+ {
+ SLANG_RETURN_ON_FAIL(binding.setBufferContents(location, srcEntry.bufferData.getBuffer(), srcEntry.bufferData.getCount() * sizeof(unsigned int)));
+ 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:
+ {
+ auto type = typeLayout->getType();
+ auto shape = type->getResourceShape();
+
+ //auto access = type->getResourceAccess();
+
+ switch (shape & SLANG_RESOURCE_BASE_SHAPE_MASK)
+ {
+ default:
+ assert(!"unhandled case");
+ break;
+ case SLANG_TEXTURE_2D:
+ {
+ slang::TypeReflection* typeReflection = location.getTypeLayout()->getResourceResultType();
+
+ int count = 1;
+ if (typeReflection->getKind() == slang::TypeReflection::Kind::Vector)
+ {
+ count = int(typeReflection->getElementCount());
+ }
+
+ RefPtr<Resource> resource = _newOneTexture2D(count);
+ outContext.m_resources.add(resource);
+
+ SLANG_RETURN_ON_FAIL(binding.setObject(location, resource->getInterface()));
+ break;
+ }
+ case SLANG_TEXTURE_1D:
+ case SLANG_TEXTURE_3D:
+ case SLANG_TEXTURE_CUBE:
+ case SLANG_TEXTURE_BUFFER:
+ {
+ // Just set to null for now
+ SLANG_RETURN_ON_FAIL(binding.setObject(location, nullptr));
+ break;
+ }
+ case SLANG_BYTE_ADDRESS_BUFFER:
+ case SLANG_STRUCTURED_BUFFER:
+ {
+ CPUMemoryBinding::Buffer buffer;
+ SLANG_RETURN_ON_FAIL(binding.setNewBuffer(location, srcEntry.bufferData.getBuffer(), srcEntry.bufferData.getCount() * sizeof(unsigned int), buffer));
+ buffers[entryIndex] = buffer;
+ break;
+ }
+ }
+ if (shape & SLANG_TEXTURE_ARRAY_FLAG)
+ {
+
+ }
+ if (shape & SLANG_TEXTURE_MULTISAMPLE_FLAG)
+ {
+
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ return SLANG_OK;
+}
+
+/* static */SlangResult CPUComputeUtil::execute(const ShaderCompilerUtil::OutputAndLayout& compilationAndLayout, Context& context)
+{
+ auto request = compilationAndLayout.output.request;
+ auto reflection = (slang::ShaderReflection*) spGetReflection(request);
+
+ ComPtr<ISlangSharedLibrary> sharedLibrary;
+ SLANG_RETURN_ON_FAIL(spGetEntryPointHostCallable(request, 0, 0, sharedLibrary.writeRef()));
+
+ // Use reflection to find the entry point name
+
+ struct UniformState;
+ typedef void(*Func)(CPPPrelude::ComputeVaryingInput* varyingInput, CPPPrelude::UniformEntryPointParams* uniformEntryPointParams, UniformState* uniformState);
+
+ 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;
+ }
+ }
+
+ SlangUInt numThreadsPerAxis[3];
+ entryPoint->getComputeThreadGroupSize(3, numThreadsPerAxis);
+
+ {
+ 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.z = z;
+ for (int y = 0; y < int(numThreadsPerAxis[1]); ++y)
+ {
+ varying.groupThreadID.y = y;
+ for (int x = 0; x < int(numThreadsPerAxis[0]); ++x)
+ {
+ varying.groupThreadID.x = x;
+
+ func(&varying, uniformEntryPointParams, uniformState);
+ }
+ }
+ }
+ }
+
+ return SLANG_OK;
+}
+
+
+
+} // renderer_test
diff --git a/tools/render-test/cpu-compute-util.h b/tools/render-test/cpu-compute-util.h
new file mode 100644
index 000000000..cbc4e6e58
--- /dev/null
+++ b/tools/render-test/cpu-compute-util.h
@@ -0,0 +1,40 @@
+#ifndef CPU_COMPUTE_UTIL_H
+#define CPU_COMPUTE_UTIL_H
+
+#include "cpu-memory-binding.h"
+#include "slang-support.h"
+#include "options.h"
+
+#include "../../source/core/slang-smart-pointer.h"
+
+namespace renderer_test {
+
+struct CPUComputeUtil
+{
+ struct Resource : public RefObject
+ {
+ void* getInterface() const { return m_interface; }
+ void* m_interface;
+ };
+
+ struct Context
+ {
+ /// Holds the binding information
+ CPUMemoryBinding binding;
+ /// Buffers are held in same order as entries in layout (useful for dumping out bindings)
+ List<CPUMemoryBinding::Buffer> buffers;
+ /// Holds the resources created (in calcBindings)
+ List<RefPtr<Resource> > m_resources;
+ };
+
+ static SlangResult calcBindings(const ShaderCompilerUtil::OutputAndLayout& compilationAndLayout, Context& outContext);
+
+ static SlangResult execute(const ShaderCompilerUtil::OutputAndLayout& compilationAndLayout, Context& outContext);
+
+ static SlangResult writeBindings(const ShaderInputLayout& layout, const List<CPUMemoryBinding::Buffer>& buffers, const Slang::String& fileName);
+};
+
+
+} // renderer_test
+
+#endif //CPU_MEMORY_BINDING_H
diff --git a/tools/render-test/cpu-memory-binding.cpp b/tools/render-test/cpu-memory-binding.cpp
index 7760c5919..612c2fc57 100644
--- a/tools/render-test/cpu-memory-binding.cpp
+++ b/tools/render-test/cpu-memory-binding.cpp
@@ -46,6 +46,7 @@ SlangResult CPUMemoryBinding::init(slang::ShaderReflection* reflection, int entr
{
m_reflection = reflection;
m_rootBuffer = Buffer();
+ m_entryPointBuffer = Buffer();
m_allBuffers.clear();
m_arena.deallocateAll();
diff --git a/tools/render-test/cpu-render-test-main.cpp b/tools/render-test/cpu-render-test-main.cpp
new file mode 100644
index 000000000..d754f9359
--- /dev/null
+++ b/tools/render-test/cpu-render-test-main.cpp
@@ -0,0 +1,99 @@
+// cpu-render-test-main.cpp
+
+#include "options.h"
+
+#include "slang-support.h"
+
+#include "../source/core/slang-io.h"
+
+#include "shader-input-layout.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "../../source/core/slang-test-tool-util.h"
+
+#include "cpu-compute-util.h"
+
+SLANG_TEST_TOOL_API SlangResult innerMain(Slang::StdWriters* stdWriters, SlangSession* session, int argcIn, const char*const* argvIn)
+{
+ using namespace renderer_test;
+ using namespace Slang;
+
+ StdWriters::setSingleton(stdWriters);
+
+ // Parse command-line options
+ SLANG_RETURN_ON_FAIL(parseOptions(argcIn, argvIn, StdWriters::getError()));
+
+ // Declare window pointer before renderer, such that window is released after renderer
+ RefPtr<renderer_test::Window> window;
+ // Renderer is constructed (later) using the window
+ 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;
+ SlangPassThrough slangPassThrough = SLANG_PASS_THROUGH_NONE;
+ char const* profileName = "";
+ switch (gOptions.rendererType)
+ {
+ 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;
+
+ {
+ ShaderCompilerUtil::OutputAndLayout compilationAndLayout;
+ SLANG_RETURN_ON_FAIL(ShaderCompilerUtil::compileWithLayout(session, gOptions.sourcePath, gOptions.shaderType, input, compilationAndLayout));
+
+ CPUComputeUtil::Context context;
+ SLANG_RETURN_ON_FAIL(CPUComputeUtil::calcBindings(compilationAndLayout, context));
+ SLANG_RETURN_ON_FAIL(CPUComputeUtil::execute(compilationAndLayout, context));
+
+ // Dump everything out that was written
+ return CPUComputeUtil::writeBindings(compilationAndLayout.layout, context.buffers, gOptions.outputPath);
+ }
+}
+
+int main(int argc, char** argv)
+{
+ using namespace Slang;
+ SlangSession* session = spCreateSession(nullptr);
+
+ TestToolUtil::setSessionDefaultPrelude(argv[0], session);
+ auto stdWriters = StdWriters::initDefaultSingleton();
+ SlangResult res = innerMain(stdWriters, session, argc, argv);
+ spDestroySession(session);
+
+ return (int)TestToolUtil::getReturnCode(res);
+}
+
diff --git a/tools/render-test/options.cpp b/tools/render-test/options.cpp
index f8c2c1d12..a9e51b8e0 100644
--- a/tools/render-test/options.cpp
+++ b/tools/render-test/options.cpp
@@ -15,7 +15,7 @@
namespace renderer_test {
using namespace Slang;
-static const Options gDefaultOptions;
+static const Options gDefaultOptions = Options();
Options gOptions;
diff --git a/tools/render-test/render-test-main.cpp b/tools/render-test/render-test-main.cpp
index 440ba9c82..5b9621142 100644
--- a/tools/render-test/render-test-main.cpp
+++ b/tools/render-test/render-test-main.cpp
@@ -21,13 +21,9 @@
#include <stdio.h>
#include <stdlib.h>
-#define SLANG_PRELUDE_NAMESPACE CPPPrelude
-#include "../../prelude/slang-cpp-types.h"
-
#include "../../source/core/slang-test-tool-util.h"
-#include "../../source/core/slang-memory-arena.h"
-#include "cpu-memory-binding.h"
+#include "cpu-compute-util.h"
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
@@ -241,436 +237,6 @@ class RenderTestApp
int m_numAddedConstantBuffers; ///< Constant buffers can be added to the binding directly. Will be added at the end.
};
-// Entry point name to use for vertex/fragment shader
-static const char vertexEntryPointName[] = "vertexMain";
-static const char fragmentEntryPointName[] = "fragmentMain";
-static const char computeEntryPointName[] = "computeMain";
-
-static SlangResult _readSource(const String& inSourcePath, List<char>& outSourceText)
-{
- // 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);
-
- outSourceText.setCount(sourceSize + 1);
- fread(outSourceText.getBuffer(), sourceSize, 1, sourceFile);
- fclose(sourceFile);
- outSourceText[sourceSize] = 0;
-
- 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)
- {
- default:
- layout.numRenderTargets = 1;
- break;
-
- case Options::ShaderProgramType::Compute:
- layout.numRenderTargets = 0;
- break;
- }
-
- // Parse the layout
- layout.parse(sourceText.getBuffer());
- layout.updateForTarget(input.target);
-
- // 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 _writeBindings(const ShaderInputLayout& layout, const List<CPUMemoryBinding::Buffer>& buffers, const String& fileName)
-{
- FILE * f = fopen(fileName.getBuffer(), "wb");
- if (!f)
- {
- return SLANG_FAIL;
- }
-
- const auto& entries = layout.entries;
-
- for (int i = 0; i < entries.getCount(); ++i)
- {
- const auto& entry = entries[i];
- if (entry.isOutput)
- {
- const auto& buffer = buffers[i];
-
- unsigned int* ptr = (unsigned int*)buffer.m_data;
-
- const int size = int(entry.bufferData.getCount());
- // Must be the same size or less thatn allocated buffer
- SLANG_ASSERT(size * sizeof(unsigned int) <= buffer.m_sizeInBytes);
-
- for (int i = 0; i < size; ++i)
- {
- unsigned int v = ptr[i];
-
- fprintf(f, "%X\n", v);
- }
- }
- }
- fclose(f);
- return SLANG_OK;
-}
-
-struct CPUResource: public RefObject
-{
- void* getInterface() const { return m_interface; }
- void* m_interface;
-};
-
-template <int COUNT>
-struct OneTexture2D: public CPUResource, public CPPPrelude::ITexture2D
-{
- void setOne(void* out)
- {
- float* dst = (float*)out;
- for (int i = 0; i < COUNT; ++i)
- {
- dst[i] = 1.0f;
- }
- }
-
- virtual void Load(const CPPPrelude::int3& v, void* out) SLANG_OVERRIDE
- {
- setOne(out);
- }
- virtual void Sample(CPPPrelude::SamplerState samplerState, const CPPPrelude::float2& loc, void* out) SLANG_OVERRIDE
- {
- setOne(out);
- }
- virtual void SampleLevel(CPPPrelude::SamplerState samplerState, const CPPPrelude::float2& loc, float level, void* out) SLANG_OVERRIDE
- {
- setOne(out);
- }
-
- OneTexture2D()
- {
- m_interface = static_cast<CPPPrelude::ITexture2D*>(this);
- }
-};
-
-static CPUResource* _newOneTexture2D(int elemCount)
-{
- switch (elemCount)
- {
- case 1: return new OneTexture2D<1>();
- case 2: return new OneTexture2D<2>();
- case 3: return new OneTexture2D<3>();
- case 4: return new OneTexture2D<4>();
- default: return nullptr;
- }
-}
-
-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, CPPPrelude::UniformEntryPointParams* params, 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;
- }
- }
-
- CPUMemoryBinding binding;
- SLANG_RETURN_ON_FAIL(binding.init(reflection, 0));
-
- List<CPUMemoryBinding::Buffer> buffers;
-
- // Okay we need to find all of the bindings and match up to those in the layout
- ShaderInputLayout& layout = output.layout;
-
- List<RefPtr<CPUResource> > resources;
-
- {
- auto& outStream = StdWriters::getOut();
- auto& entries = layout.entries;
- buffers.setCount(entries.getCount());
-
- for (int entryIndex = 0; entryIndex < entries.getCount(); ++entryIndex)
- {
- auto& entry = entries[entryIndex];
-
- if (entry.name.getLength() == 0)
- {
- outStream.print("No 'name' specified for resources in '%s'\n", sourcePath.getBuffer());
- return SLANG_FAIL;
- }
-
- // We will parse the 'name' as may be path to a resource
- TokenReader parser(entry.name);
-
- CPUMemoryBinding::Location location;
-
- {
- Token nameToken = parser.ReadToken();
- if (nameToken.Type != TokenType::Identifier)
- {
- outStream.print("Invalid input syntax at line %d", int(parser.NextToken().Position.Line));
- return SLANG_FAIL;
- }
- location = binding.find(nameToken.Content.getBuffer());
- if (location.isInvalid())
- {
- outStream.print("Unable to find entry in '%s' for '%s' (for CPU name must be specified) \n", sourcePath.getBuffer(), entry.name.getBuffer());
- return SLANG_FAIL;
- }
- }
-
- while (!parser.IsEnd())
- {
- Token token = parser.NextToken(0);
-
- if (token.Type == TokenType::LBracket)
- {
- parser.ReadToken();
- int index = parser.ReadInt();
- SLANG_ASSERT(index >= 0);
-
- location = location.toIndex(index);
- if (location.isInvalid())
- {
- outStream.print("Unable to find entry in '%d' in '%s'\n", index, entry.name.getBuffer());
- return SLANG_FAIL;
- }
- parser.ReadMatchingToken(TokenType::RBracket);
- }
- else if (token.Type == TokenType::Dot)
- {
- parser.ReadToken();
- Token identifierToken = parser.ReadMatchingToken(TokenType::Identifier);
-
- location = location.toField(identifierToken.Content.getBuffer());
- if (location.isInvalid())
- {
- outStream.print("Unable to find field '%s' in '%s'\n", identifierToken.Content.getBuffer(), entry.name.getBuffer());
- return SLANG_FAIL;
- }
- }
- else if (token.Type == TokenType::Comma)
- {
- // Break out
- break;
- }
- else
- {
- throw TextFormatException("Invalid input syntax at line " + parser.NextToken().Position.Line);
- }
- }
-
- auto& srcEntry = layout.entries[entryIndex];
-
- auto typeLayout = location.getTypeLayout();
- const auto kind = typeLayout->getKind();
- switch (kind)
- {
- case slang::TypeReflection::Kind::Vector:
- case slang::TypeReflection::Kind::Matrix:
- case slang::TypeReflection::Kind::Array:
- case slang::TypeReflection::Kind::Scalar:
- case slang::TypeReflection::Kind::Struct:
- {
- SLANG_RETURN_ON_FAIL(binding.setInplace(location, srcEntry.bufferData.getBuffer(), srcEntry.bufferData.getCount() * sizeof(unsigned int)));
- break;
- }
- default:
- break;
- case slang::TypeReflection::Kind::ConstantBuffer:
- {
- SLANG_RETURN_ON_FAIL(binding.setBufferContents(location, srcEntry.bufferData.getBuffer(),srcEntry.bufferData.getCount() * sizeof(unsigned int) ));
- 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:
- {
- auto type = typeLayout->getType();
- auto shape = type->getResourceShape();
-
- //auto access = type->getResourceAccess();
-
- switch (shape & SLANG_RESOURCE_BASE_SHAPE_MASK)
- {
- default:
- assert(!"unhandled case");
- break;
- case SLANG_TEXTURE_2D:
- {
- slang::TypeReflection* typeReflection = location.getTypeLayout()->getResourceResultType();
-
- int count = 1;
- if (typeReflection->getKind() == slang::TypeReflection::Kind::Vector)
- {
- count = int(typeReflection->getElementCount());
- }
-
- RefPtr<CPUResource> resource = _newOneTexture2D(count);
- resources.add(resource);
-
- SLANG_RETURN_ON_FAIL(binding.setObject(location, resource->getInterface()));
- break;
- }
- case SLANG_TEXTURE_1D:
- case SLANG_TEXTURE_3D:
- case SLANG_TEXTURE_CUBE:
- case SLANG_TEXTURE_BUFFER:
- {
- // Just set to null for now
- SLANG_RETURN_ON_FAIL(binding.setObject(location, nullptr));
- break;
- }
- case SLANG_BYTE_ADDRESS_BUFFER:
- case SLANG_STRUCTURED_BUFFER:
- {
- CPUMemoryBinding::Buffer buffer;
- SLANG_RETURN_ON_FAIL(binding.setNewBuffer(location, srcEntry.bufferData.getBuffer(), srcEntry.bufferData.getCount() * sizeof(unsigned int), buffer ));
- buffers[entryIndex] = buffer;
- break;
- }
- }
- if (shape & SLANG_TEXTURE_ARRAY_FLAG)
- {
-
- }
- if (shape & SLANG_TEXTURE_MULTISAMPLE_FLAG)
- {
-
- }
-
- break;
- }
- }
- }
- }
-
- SlangUInt numThreadsPerAxis[3];
- entryPoint->getComputeThreadGroupSize(3, numThreadsPerAxis);
-
- {
- UniformState* uniformState = (UniformState*)binding.m_rootBuffer.m_data;
- CPPPrelude::UniformEntryPointParams* params = (CPPPrelude::UniformEntryPointParams*)binding.m_entryPointBuffer.m_data;
-
- CPPPrelude::ComputeVaryingInput varying;
- varying.groupID = {};
-
- for (int z = 0; z < int(numThreadsPerAxis[2]); ++z)
- {
- varying.groupThreadID.z = z;
- for (int y = 0; y < int(numThreadsPerAxis[1]); ++y)
- {
- varying.groupThreadID.y = y;
- for (int x = 0; x < int(numThreadsPerAxis[0]); ++x)
- {
- varying.groupThreadID.x = x;
-
- func(&varying, params, uniformState);
- }
- }
- }
- }
-
- // Dump everything out that was write (we wrote in place!)
- return _writeBindings(layout, buffers, 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));
@@ -769,10 +335,10 @@ SlangResult RenderTestApp::initialize(SlangSession* session, Renderer* renderer,
Result RenderTestApp::_initializeShaders(SlangSession* session, Renderer* renderer, Options::ShaderProgramType shaderType, const ShaderCompilerUtil::Input& input)
{
- CompileOutput output;
- SLANG_RETURN_ON_FAIL(_compile(session, gOptions.sourcePath, shaderType, input, output));
+ ShaderCompilerUtil::OutputAndLayout output;
+ SLANG_RETURN_ON_FAIL(ShaderCompilerUtil::compileWithLayout(session, gOptions.sourcePath, shaderType, input, output));
m_shaderInputLayout = output.layout;
- m_shaderProgram = renderer->createProgram(output.compileOutput.desc);
+ m_shaderProgram = renderer->createProgram(output.output.desc);
return m_shaderProgram ? SLANG_OK : SLANG_FAIL;
}
@@ -1024,8 +590,15 @@ SLANG_TEST_TOOL_API SlangResult innerMain(Slang::StdWriters* stdWriters, SlangSe
if (!renderer)
{
- SLANG_RETURN_ON_FAIL(_doCPUCompute(session, gOptions.sourcePath, gOptions.shaderType, input));
- return SLANG_OK;
+ ShaderCompilerUtil::OutputAndLayout compilationAndLayout;
+ SLANG_RETURN_ON_FAIL(ShaderCompilerUtil::compileWithLayout(session, gOptions.sourcePath, gOptions.shaderType, input, compilationAndLayout));
+
+ CPUComputeUtil::Context context;
+ SLANG_RETURN_ON_FAIL(CPUComputeUtil::calcBindings(compilationAndLayout, context));
+ SLANG_RETURN_ON_FAIL(CPUComputeUtil::execute(compilationAndLayout, context));
+
+ // Dump everything out that was written
+ return CPUComputeUtil::writeBindings(compilationAndLayout.layout, context.buffers, gOptions.outputPath);
}
{
diff --git a/tools/render-test/render-test-tool.vcxproj b/tools/render-test/render-test-tool.vcxproj
index 0399d67e0..3e0c0ae56 100644
--- a/tools/render-test/render-test-tool.vcxproj
+++ b/tools/render-test/render-test-tool.vcxproj
@@ -179,6 +179,7 @@
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
+ <ClInclude Include="cpu-compute-util.h" />
<ClInclude Include="cpu-memory-binding.h" />
<ClInclude Include="options.h" />
<ClInclude Include="png-serialize-util.h" />
@@ -187,6 +188,7 @@
<ClInclude Include="slang-support.h" />
</ItemGroup>
<ItemGroup>
+ <ClCompile Include="cpu-compute-util.cpp" />
<ClCompile Include="cpu-memory-binding.cpp" />
<ClCompile Include="options.cpp" />
<ClCompile Include="png-serialize-util.cpp" />
diff --git a/tools/render-test/render-test-tool.vcxproj.filters b/tools/render-test/render-test-tool.vcxproj.filters
index 43767fc8d..769d53aed 100644
--- a/tools/render-test/render-test-tool.vcxproj.filters
+++ b/tools/render-test/render-test-tool.vcxproj.filters
@@ -9,6 +9,9 @@
</Filter>
</ItemGroup>
<ItemGroup>
+ <ClInclude Include="cpu-compute-util.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="cpu-memory-binding.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -29,6 +32,9 @@
</ClInclude>
</ItemGroup>
<ItemGroup>
+ <ClCompile Include="cpu-compute-util.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="cpu-memory-binding.cpp">
<Filter>Source Files</Filter>
</ClCompile>
diff --git a/tools/render-test/shader-input-layout.cpp b/tools/render-test/shader-input-layout.cpp
index 810e31c2c..7f75805e9 100644
--- a/tools/render-test/shader-input-layout.cpp
+++ b/tools/render-test/shader-input-layout.cpp
@@ -440,6 +440,23 @@ namespace renderer_test
}
}
+ template <typename F>
+ void _iteratePixels(int dimension, int size, unsigned int * buffer, F f)
+ {
+ if (dimension == 1)
+ for (int i = 0; i < size; i++)
+ buffer[i] = f(i, 0, 0);
+ else if (dimension == 2)
+ for (int i = 0; i < size; i++)
+ for (int j = 0; j < size; j++)
+ buffer[i*size + j] = f(j, i, 0);
+ else if (dimension == 3)
+ for (int i = 0; i < size; i++)
+ for (int j = 0; j < size; j++)
+ for (int k = 0; k < size; k++)
+ buffer[i*size*size + j * size + k] = f(k, j, i);
+ };
+
void generateTextureDataRGB8(TextureData& output, const InputTextureDesc& inputDesc)
{
int arrLen = inputDesc.arrayLength;
@@ -453,21 +470,6 @@ namespace renderer_test
output.textureSize = inputDesc.size;
output.mipLevels = Math::Log2Floor(output.textureSize) + 1;
output.dataBuffer.setCount(output.mipLevels * output.arraySize);
- auto iteratePixels = [&](int dimension, int size, unsigned int * buffer, auto f)
- {
- if (dimension == 1)
- for (int i = 0; i < size; i++)
- buffer[i] = f(i, 0, 0);
- else if (dimension == 2)
- for (int i = 0; i < size; i++)
- for (int j = 0; j < size; j++)
- buffer[i*size + j] = f(j, i, 0);
- else if (dimension == 3)
- for (int i = 0; i < size; i++)
- for (int j = 0; j < size; j++)
- for (int k = 0; k < size; k++)
- buffer[i*size*size + j*size + k] = f(k, j, i);
- };
int slice = 0;
for (int i = 0; i < arraySize; i++)
@@ -482,7 +484,7 @@ namespace renderer_test
bufferLen *= size*size;
dataBuffer[slice].setCount(bufferLen);
- iteratePixels(inputDesc.dimension, size, dataBuffer[slice].getBuffer(), [&](int x, int y, int z) -> unsigned int
+ _iteratePixels(inputDesc.dimension, size, dataBuffer[slice].getBuffer(), [&](int x, int y, int z) -> unsigned int
{
if (inputDesc.content == InputTextureContent::Zero)
{
diff --git a/tools/render-test/slang-support.cpp b/tools/render-test/slang-support.cpp
index 230f78453..df7e91df8 100644
--- a/tools/render-test/slang-support.cpp
+++ b/tools/render-test/slang-support.cpp
@@ -10,6 +10,12 @@
#include <stdio.h>
namespace renderer_test {
+using namespace Slang;
+
+// Entry point name to use for vertex/fragment shader
+static const char vertexEntryPointName[] = "vertexMain";
+static const char fragmentEntryPointName[] = "fragmentMain";
+static const char computeEntryPointName[] = "computeMain";
/* static */ SlangResult ShaderCompilerUtil::compileProgram(SlangSession* session, const Input& input, const ShaderCompileRequest& request, Output& out)
{
@@ -138,7 +144,9 @@ namespace renderer_test {
{
fprintf(stderr, "%s", diagnostics);
}
- if (SLANG_SUCCEEDED(res))
+
+ SLANG_RETURN_ON_FAIL(res);
+
{
size_t codeSize = 0;
char const* code = (char const*) spGetEntryPointCode(slangRequest, computeEntryPoint, &codeSize);
@@ -166,7 +174,9 @@ namespace renderer_test {
// OutputDebugStringA(diagnostics);
fprintf(stderr, "%s", diagnostics);
}
- if (SLANG_SUCCEEDED(res))
+
+ SLANG_RETURN_ON_FAIL(res);
+
{
size_t vertexCodeSize = 0;
char const* vertexCode = (char const*) spGetEntryPointCode(slangRequest, vertexEntryPoint, &vertexCodeSize);
@@ -193,4 +203,79 @@ namespace renderer_test {
return SLANG_OK;
}
+/* static */SlangResult ShaderCompilerUtil::readSource(const String& inSourcePath, List<char>& outSourceText)
+{
+ // 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);
+
+ outSourceText.setCount(sourceSize + 1);
+ fread(outSourceText.getBuffer(), sourceSize, 1, sourceFile);
+ fclose(sourceFile);
+ outSourceText[sourceSize] = 0;
+
+ return SLANG_OK;
+}
+
+/* static */SlangResult ShaderCompilerUtil::compileWithLayout(SlangSession* session, const String& sourcePath, Options::ShaderProgramType shaderType, const ShaderCompilerUtil::Input& input, OutputAndLayout& output)
+{
+ List<char> sourceText;
+ SLANG_RETURN_ON_FAIL(readSource(sourcePath, sourceText));
+
+ output.sourcePath = sourcePath;
+
+ auto& layout = output.layout;
+
+ // Default the amount of renderTargets based on shader type
+ switch (shaderType)
+ {
+ default:
+ layout.numRenderTargets = 1;
+ break;
+
+ case Options::ShaderProgramType::Compute:
+ layout.numRenderTargets = 0;
+ break;
+ }
+
+ // Parse the layout
+ layout.parse(sourceText.getBuffer());
+ layout.updateForTarget(input.target);
+
+ // 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.output);
+}
+
} // renderer_test
diff --git a/tools/render-test/slang-support.h b/tools/render-test/slang-support.h
index 662098546..543ab3258 100644
--- a/tools/render-test/slang-support.h
+++ b/tools/render-test/slang-support.h
@@ -6,6 +6,7 @@
#include <slang.h>
#include "shader-input-layout.h"
+#include "options.h"
namespace renderer_test {
@@ -33,6 +34,12 @@ struct ShaderCompilerUtil
}
void reset()
{
+ {
+ desc.pipelineType = PipelineType::Unknown;
+ desc.kernels = nullptr;
+ desc.kernelCount = 0;
+ }
+
kernelDescs.clear();
if (request && session)
{
@@ -52,8 +59,20 @@ struct ShaderCompilerUtil
ShaderProgram::Desc desc;
SlangCompileRequest* request = nullptr;
SlangSession* session = nullptr;
+
};
+ struct OutputAndLayout
+ {
+ Output output;
+ ShaderInputLayout layout;
+ Slang::String sourcePath;
+ };
+
+ static SlangResult compileWithLayout(SlangSession* session, const Slang::String& sourcePath, Options::ShaderProgramType shaderType, const ShaderCompilerUtil::Input& input, OutputAndLayout& output);
+
+ static SlangResult readSource(const Slang::String& inSourcePath, List<char>& outSourceText);
+
static SlangResult compileProgram(SlangSession* session, const Input& input, const ShaderCompileRequest& request, Output& out);
};