summaryrefslogtreecommitdiffstats
path: root/tools/render-test
diff options
context:
space:
mode:
Diffstat (limited to 'tools/render-test')
-rw-r--r--tools/render-test/main.cpp53
-rw-r--r--tools/render-test/options.cpp28
-rw-r--r--tools/render-test/options.h23
-rw-r--r--tools/render-test/render-d3d11.cpp6
-rw-r--r--tools/render-test/render-d3d12.cpp337
-rw-r--r--tools/render-test/render-d3d12.h10
-rw-r--r--tools/render-test/render-gl.cpp6
-rw-r--r--tools/render-test/render-test.vcxproj18
-rw-r--r--tools/render-test/render-test.vcxproj.filters12
-rw-r--r--tools/render-test/render-vk.cpp1033
-rw-r--r--tools/render-test/render-vk.h10
-rw-r--r--tools/render-test/render.h9
-rw-r--r--tools/render-test/slang-support.cpp29
13 files changed, 1513 insertions, 61 deletions
diff --git a/tools/render-test/main.cpp b/tools/render-test/main.cpp
index 51a96436f..3255f4b9b 100644
--- a/tools/render-test/main.cpp
+++ b/tools/render-test/main.cpp
@@ -4,6 +4,7 @@
#include "render.h"
#include "render-d3d11.h"
#include "render-gl.h"
+#include "render-vk.h"
#include "slang-support.h"
#include "shader-input-layout.h"
#include <stdio.h>
@@ -98,7 +99,8 @@ Error initializeShaders(
ShaderCompileRequest::SourceInfo sourceInfo;
sourceInfo.path = sourcePath;
- sourceInfo.text = sourceText;
+ sourceInfo.dataBegin = sourceText;
+ sourceInfo.dataEnd = sourceText + sourceSize;
ShaderCompileRequest compileRequest;
compileRequest.source = sourceInfo;
@@ -322,18 +324,28 @@ int main(
Renderer* renderer = nullptr;
- switch( gOptions.mode )
+ SlangSourceLanguage nativeLanguage = SLANG_SOURCE_LANGUAGE_UNKNOWN;
+ SlangCompileTarget slangTarget = SLANG_TARGET_NONE;
+ switch( gOptions.rendererID )
{
- case Mode::Slang:
- case Mode::HLSL:
- case Mode::HLSLRewrite:
+ case RendererID::D3D11:
renderer = createD3D11Renderer();
+ slangTarget = SLANG_HLSL;
+ nativeLanguage = SLANG_SOURCE_LANGUAGE_HLSL;
break;
- case Mode::GLSL:
- case Mode::GLSLRewrite:
- case Mode::GLSLCrossCompile:
+ // TODO: `RendererID::D3D12`
+
+ case RendererID::GL:
renderer = createGLRenderer();
+ slangTarget = SLANG_GLSL;
+ nativeLanguage = SLANG_SOURCE_LANGUAGE_GLSL;
+ break;
+
+ case RendererID::VK:
+ renderer = createVKRenderer();
+ slangTarget = SLANG_SPIRV;
+ nativeLanguage = SLANG_SOURCE_LANGUAGE_GLSL;
break;
default:
@@ -345,22 +357,14 @@ int main(
renderer->initialize(windowHandle);
auto shaderCompiler = renderer->getShaderCompiler();
- switch( gOptions.mode )
+ switch( gOptions.inputLanguageID )
{
- case Mode::Slang:
- shaderCompiler = createSlangShaderCompiler(shaderCompiler, SLANG_SOURCE_LANGUAGE_SLANG, SLANG_HLSL);
- break;
-
- case Mode::HLSLRewrite:
- shaderCompiler = createSlangShaderCompiler(shaderCompiler, SLANG_SOURCE_LANGUAGE_HLSL, SLANG_HLSL);
- break;
-
- case Mode::GLSLRewrite:
- shaderCompiler = createSlangShaderCompiler(shaderCompiler, SLANG_SOURCE_LANGUAGE_GLSL, SLANG_GLSL);
+ case InputLanguageID::Slang:
+ shaderCompiler = createSlangShaderCompiler(shaderCompiler, SLANG_SOURCE_LANGUAGE_SLANG, slangTarget);
break;
- case Mode::GLSLCrossCompile:
- shaderCompiler = createSlangShaderCompiler(shaderCompiler, SLANG_SOURCE_LANGUAGE_SLANG, SLANG_GLSL);
+ case InputLanguageID::NativeRewrite:
+ shaderCompiler = createSlangShaderCompiler(shaderCompiler, nativeLanguage, slangTarget);
break;
default:
@@ -397,9 +401,6 @@ int main(
{
// Whenver we don't have Windows events to process,
// we render a frame.
- static const float kClearColor[] = { 0.25, 0.25, 0.25, 1.0 };
- renderer->setClearColor(kClearColor);
- renderer->clearFrame();
if (gOptions.shaderType == ShaderProgramType::Compute)
{
@@ -407,6 +408,10 @@ int main(
}
else
{
+ static const float kClearColor[] = { 0.25, 0.25, 0.25, 1.0 };
+ renderer->setClearColor(kClearColor);
+ renderer->clearFrame();
+
renderFrameInner(renderer);
}
// If we are in a mode where output is requested, we need to snapshot the back buffer here
diff --git a/tools/render-test/options.cpp b/tools/render-test/options.cpp
index 629016155..45a94e137 100644
--- a/tools/render-test/options.cpp
+++ b/tools/render-test/options.cpp
@@ -54,27 +54,33 @@ void parseOptions(int* argc, char** argv)
}
else if( strcmp(arg, "-hlsl") == 0 )
{
- gOptions.mode = Mode::HLSL;
+ gOptions.rendererID = RendererID::D3D11;
+ gOptions.inputLanguageID = InputLanguageID::Native;
}
else if( strcmp(arg, "-glsl") == 0 )
{
- gOptions.mode = Mode::GLSL;
+ gOptions.rendererID = RendererID::GL;
+ gOptions.inputLanguageID = InputLanguageID::Native;
}
else if( strcmp(arg, "-hlsl-rewrite") == 0 )
{
- gOptions.mode = Mode::HLSLRewrite;
+ gOptions.rendererID = RendererID::D3D11;
+ gOptions.inputLanguageID = InputLanguageID::NativeRewrite;
}
else if( strcmp(arg, "-glsl-rewrite") == 0 )
{
- gOptions.mode = Mode::GLSLRewrite;
+ gOptions.rendererID = RendererID::GL;
+ gOptions.inputLanguageID = InputLanguageID::NativeRewrite;
}
else if( strcmp(arg, "-slang") == 0 )
{
- gOptions.mode = Mode::Slang;
+ gOptions.rendererID = RendererID::D3D11;
+ gOptions.inputLanguageID = InputLanguageID::Slang;
}
else if( strcmp(arg, "-glsl-cross") == 0 )
{
- gOptions.mode = Mode::GLSLCrossCompile;
+ gOptions.rendererID = RendererID::GL;
+ gOptions.inputLanguageID = InputLanguageID::Slang;
}
else if( strcmp(arg, "-xslang") == 0 )
{
@@ -104,6 +110,16 @@ void parseOptions(int* argc, char** argv)
{
gOptions.shaderType = ShaderProgramType::GraphicsCompute;
}
+ else if (strcmp(arg, "-vk") == 0
+ || strcmp(arg, "-vulkan") == 0)
+ {
+ gOptions.rendererID = RendererID::VK;
+ }
+ else if (strcmp(arg, "-d3d12") == 0
+ || strcmp(arg, "-dx12") == 0)
+ {
+ gOptions.rendererID = RendererID::D3D12;
+ }
else
{
fprintf(stderr, "unknown option '%s'\n", arg);
diff --git a/tools/render-test/options.h b/tools/render-test/options.h
index 2c48c4ceb..b48295878 100644
--- a/tools/render-test/options.h
+++ b/tools/render-test/options.h
@@ -8,21 +8,24 @@ namespace renderer_test {
typedef intptr_t Int;
typedef uintptr_t UInt;
-enum class Mode
+enum class RendererID
+{
+ D3D11,
+ D3D12,
+ GL,
+ VK,
+};
+
+enum class InputLanguageID
{
// Slang being used as an HLSL-ish compiler
Slang,
// Raw HLSL or GLSL input, bypassing Slang
- HLSL,
- GLSL,
+ Native,
// Raw HLSL or GLSL input, passed through the Slang rewriter
- HLSLRewrite,
- GLSLRewrite,
-
- // Slang/HLSL input -> GLSL output
- GLSLCrossCompile,
+ NativeRewrite
};
enum
@@ -44,7 +47,9 @@ struct Options
char const* sourcePath = nullptr;
char const* outputPath = nullptr;
ShaderProgramType shaderType = ShaderProgramType::Graphics;
- Mode mode = Mode::Slang;
+
+ RendererID rendererID;
+ InputLanguageID inputLanguageID = InputLanguageID::Slang;
char const* slangArgs[kMaxSlangArgs];
int slangArgCount = 0;
diff --git a/tools/render-test/render-d3d11.cpp b/tools/render-test/render-d3d11.cpp
index 7d5c79b19..690e6299f 100644
--- a/tools/render-test/render-d3d11.cpp
+++ b/tools/render-test/render-d3d11.cpp
@@ -719,7 +719,7 @@ public:
{
if (request.computeShader.name)
{
- auto dxComputeShaderBlob = compileHLSLShader(request.computeShader.source.path, request.computeShader.source.text, request.computeShader.name, request.computeShader.profile);
+ auto dxComputeShaderBlob = compileHLSLShader(request.computeShader.source.path, request.computeShader.source.dataBegin, request.computeShader.name, request.computeShader.profile);
if (!dxComputeShaderBlob)
return nullptr;
@@ -737,10 +737,10 @@ public:
}
else
{
- auto dxVertexShaderBlob = compileHLSLShader(request.vertexShader.source.path, request.vertexShader.source.text, request.vertexShader.name, request.vertexShader.profile);
+ auto dxVertexShaderBlob = compileHLSLShader(request.vertexShader.source.path, request.vertexShader.source.dataBegin, request.vertexShader.name, request.vertexShader.profile);
if (!dxVertexShaderBlob) return nullptr;
- auto dxFragmentShaderBlob = compileHLSLShader(request.fragmentShader.source.path, request.fragmentShader.source.text, request.fragmentShader.name, request.fragmentShader.profile);
+ auto dxFragmentShaderBlob = compileHLSLShader(request.fragmentShader.source.path, request.fragmentShader.source.dataBegin, request.fragmentShader.name, request.fragmentShader.profile);
if (!dxFragmentShaderBlob) return nullptr;
ID3D11VertexShader* dxVertexShader;
diff --git a/tools/render-test/render-d3d12.cpp b/tools/render-test/render-d3d12.cpp
new file mode 100644
index 000000000..2308c601a
--- /dev/null
+++ b/tools/render-test/render-d3d12.cpp
@@ -0,0 +1,337 @@
+// render-d3d12.cpp
+#include "render-d3d12.h"
+
+#include "options.h"
+#include "render.h"
+
+// In order to use the Slang API, we need to include its header
+
+#include <slang.h>
+
+// We will be rendering with Direct3D 12, so we need to include
+// the Windows and D3D12 headers
+
+#define WIN32_LEAN_AND_MEAN
+#define NOMINMAX
+#include <Windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#undef NOMINMAX
+
+#include <dxgi1_4.h>
+#include <d3d12.h>
+#include <d3dcompiler.h>
+
+// We will use the C standard library just for printing error messages.
+#include <stdio.h>
+
+#ifdef _MSC_VER
+#include <stddef.h>
+#if (_MSC_VER < 1900)
+#define snprintf sprintf_s
+#endif
+#endif
+//
+using namespace Slang;
+
+#define ENABLE_DEBUG_LAYER 1
+
+namespace renderer_test {
+
+// The Slang compiler currently generates HLSL source, so we'll need a utility
+// routine (defined later) to translate that into D3D11 shader bytecode.
+ID3DBlob* compileHLSLShader(
+ char const* sourcePath,
+ char const* source,
+ char const* entryPointName,
+ char const* dxProfileName);
+
+static char const* vertexProfileName = "vs_4_0";
+static char const* fragmentProfileName = "ps_4_0";
+
+//
+
+class D3D12Renderer : public Renderer, public ShaderCompiler
+{
+public:
+ IDXGISwapChain* dxSwapChain = NULL;
+
+ ID3D12Device* dxDevice = NULL;
+
+ virtual PROC loadProc(
+ HMODULE module,
+ char const* name)
+ {
+ PROC proc = GetProcAddress(module, name);
+ if( !proc )
+ {
+ fprintf(stderr,
+ "error: failed load symbol '%s'\n", name);
+ exit(1);
+ }
+ return proc;
+ }
+
+ void checkResult(HRESULT result)
+ {
+ assert(SUCCEEDED(result));
+ }
+
+ virtual void initialize(void* inWindowHandle) override
+ {
+ auto windowHandle = (HWND) inWindowHandle;
+ // Rather than statically link against D3D, we load it dynamically.
+
+ HMODULE d3d12 = LoadLibraryA("d3d12.dll");
+ if(!d3d12)
+ {
+ fprintf(stderr, "error: failed load 'd3d12.dll'\n");
+ exit(1);
+ }
+
+#define LOAD_PROC(TYPE, NAME) \
+ TYPE NAME##_ = (TYPE) loadProc(d3d12, #NAME)
+
+
+ UINT dxgiFactoryFlags = 0;
+
+#if ENABLE_DEBUG_LAYER
+ LOAD_PROC(PFN_D3D12_GET_DEBUG_INTERFACE, D3D12GetDebugInterface);
+
+ ID3D12Debug* debugController;
+ if(SUCCEEDED(D3D12GetDebugInterface_(IID_PPV_ARGS(&debugController))))
+ {
+ debugController->EnableDebugLayer();
+ dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
+ }
+#endif
+
+ typedef HRESULT (WINAPI *PFN_DXGI_CREATE_FACTORY_2)(UINT Flags, REFIID riid, _COM_Outptr_ void **ppFactory);
+
+
+ LOAD_PROC(PFN_DXGI_CREATE_FACTORY_2, CreateDXGIFactory2);
+
+ IDXGIFactory4* dxgiFactory;
+ checkResult(CreateDXGIFactory2_(dxgiFactoryFlags, IID_PPV_ARGS(&dxgiFactory)));
+
+ D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_11_0;
+
+ // Search for an adapter that meets our requirements
+ IDXGIAdapter* adapter = nullptr;
+
+ LOAD_PROC(PFN_D3D12_CREATE_DEVICE, D3D12CreateDevice);
+
+ UINT adapterCounter = 0;
+ for(;;)
+ {
+ UINT adapterIndex = adapterCounter++;
+ IDXGIAdapter1* candidateAdapter = nullptr;
+ if(dxgiFactory->EnumAdapters1(adapterIndex, &candidateAdapter) == DXGI_ERROR_NOT_FOUND)
+ break;
+
+ DXGI_ADAPTER_DESC1 desc;
+ candidateAdapter->GetDesc1(&desc);
+
+ if( desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE )
+ {
+ // TODO: may want to allow software driver as fallback
+ }
+ else if( SUCCEEDED(D3D12CreateDevice_(
+ candidateAdapter, featureLevel, IID_PPV_ARGS(&dxDevice))) )
+ {
+ // We found one!
+ adapter = candidateAdapter;
+ break;
+ }
+
+ candidateAdapter->Release();
+ }
+
+ if(!adapter)
+ {
+ return;
+ }
+
+ // Command Queue
+
+ D3D12_COMMAND_QUEUE_DESC queueDesc = {};
+ queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
+
+ ID3D12CommandQueue* commandQueue;
+ checkResult(dxDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&commandQueue)));
+
+ // Swap Chain
+
+
+ UINT frameCount = 2; // TODO: configure
+
+ DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
+ swapChainDesc.BufferCount = frameCount;
+ swapChainDesc.Width = gWindowWidth;
+ swapChainDesc.Height = gWindowHeight;
+ swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+ swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
+ swapChainDesc.SampleDesc.Count = 1;
+
+ IDXGISwapChain1* swapChain;
+ checkResult(dxgiFactory->CreateSwapChainForHwnd(
+ commandQueue,
+ windowHandle,
+ &swapChainDesc,
+ nullptr,
+ nullptr,
+ &swapChain));
+
+ // Is this needed?
+ dxgiFactory->MakeWindowAssociation(
+ windowHandle, DXGI_MWA_NO_ALT_ENTER);
+
+ IDXGISwapChain3* swapChainEx;
+ swapChain->QueryInterface(IID_PPV_ARGS(&swapChainEx));
+
+ UINT frameIndex = swapChainEx->GetCurrentBackBufferIndex();
+
+ // Descriptor heaps
+
+ D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {};
+ rtvHeapDesc.NumDescriptors = frameCount;
+ rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
+
+ ID3D12DescriptorHeap* rtvHeap;
+ checkResult(dxDevice->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&rtvHeap)));
+
+ UINT rtvDescriptorSize = dxDevice->GetDescriptorHandleIncrementSize(
+ D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
+
+ D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap->GetCPUDescriptorHandleForHeapStart();
+
+ // Create per-frame RTVs
+ ID3D12Resource* backBufferResources[2];
+ for( UINT ff = 0; ff < frameCount; ++ff )
+ {
+ checkResult(swapChainEx->GetBuffer(ff, IID_PPV_ARGS(&backBufferResources[ff])));
+ dxDevice->CreateRenderTargetView(
+ backBufferResources[ff],
+ nullptr,
+ rtvHandle);
+ rtvHandle.ptr += rtvDescriptorSize;
+ }
+
+ ID3D12CommandAllocator* commandAllocator;
+ checkResult(dxDevice->CreateCommandAllocator(
+ D3D12_COMMAND_LIST_TYPE_DIRECT,
+ IID_PPV_ARGS(&commandAllocator)));
+ }
+
+ float clearColor[4] = { 0, 0, 0, 0 };
+ virtual void setClearColor(float const* color) override
+ {
+ memcpy(clearColor, color, sizeof(clearColor));
+ }
+
+ virtual void clearFrame() override
+ {
+ }
+
+ virtual void presentFrame() override
+ {
+ }
+
+ virtual void captureScreenShot(char const* outputPath) override
+ {
+ }
+
+ virtual ShaderCompiler* getShaderCompiler() override
+ {
+ return this;
+ }
+
+ virtual Buffer* createBuffer(BufferDesc const& desc) override
+ {
+ return nullptr;
+ }
+
+ static DXGI_FORMAT mapFormat(Format format)
+ {
+ switch( format )
+ {
+ case Format::RGB_Float32:
+ return DXGI_FORMAT_R32G32B32_FLOAT;
+ case Format::RG_Float32:
+ return DXGI_FORMAT_R32G32_FLOAT;
+ default:
+ return DXGI_FORMAT_UNKNOWN;
+ }
+ }
+
+ virtual InputLayout* createInputLayout(InputElementDesc const* inputElements, UInt inputElementCount) override
+ {
+ return nullptr;
+ }
+
+ virtual void* map(Buffer* buffer, MapFlavor flavor) override
+ {
+ return nullptr;
+ }
+
+ virtual void unmap(Buffer* buffer) override
+ {
+ }
+
+ virtual void setInputLayout(InputLayout* inputLayout) override
+ {
+ }
+
+ virtual void setPrimitiveTopology(PrimitiveTopology topology) override
+ {
+ }
+
+ virtual void setVertexBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* strides, UInt const* offsets) override
+ {
+ }
+
+ virtual void setShaderProgram(ShaderProgram* inProgram) override
+ {
+ }
+
+ virtual void setConstantBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* offsets) override
+ {
+ }
+
+ virtual void draw(UInt vertexCount, UInt startVertex) override
+ {
+ }
+
+
+ virtual void dispatchCompute(int x, int y, int z) override
+ {
+ }
+
+ virtual BindingState * createBindingState(const ShaderInputLayout & layout)
+ {
+ return nullptr;
+ }
+
+ virtual void setBindingState(BindingState * state)
+ {
+ }
+
+ virtual void serializeOutput(BindingState* state, const char * fileName)
+ {
+ }
+
+ // ShaderCompiler interface
+
+ virtual ShaderProgram* compileProgram(ShaderCompileRequest const& request) override
+ {
+ return nullptr;
+ }
+
+};
+
+Renderer* createD3D12Renderer()
+{
+ return new D3D12Renderer();
+}
+
+} // renderer_test
diff --git a/tools/render-test/render-d3d12.h b/tools/render-test/render-d3d12.h
new file mode 100644
index 000000000..259af7f7b
--- /dev/null
+++ b/tools/render-test/render-d3d12.h
@@ -0,0 +1,10 @@
+// render-d3d12.h
+#pragma once
+
+namespace renderer_test {
+
+class Renderer;
+
+Renderer* createD3D12Renderer();
+
+} // renderer_test
diff --git a/tools/render-test/render-gl.cpp b/tools/render-test/render-gl.cpp
index f07e27985..99b61c03c 100644
--- a/tools/render-test/render-gl.cpp
+++ b/tools/render-test/render-gl.cpp
@@ -453,7 +453,7 @@ public:
auto programID = glCreateProgram();
if (request.computeShader.name)
{
- auto computeShaderID = loadShader(GL_COMPUTE_SHADER, request.computeShader.source.text);
+ auto computeShaderID = loadShader(GL_COMPUTE_SHADER, request.computeShader.source.dataBegin);
glAttachShader(programID, computeShaderID);
@@ -464,8 +464,8 @@ public:
}
else
{
- auto vertexShaderID = loadShader(GL_VERTEX_SHADER, request.vertexShader.source.text);
- auto fragmentShaderID = loadShader(GL_FRAGMENT_SHADER, request.fragmentShader.source.text);
+ auto vertexShaderID = loadShader(GL_VERTEX_SHADER, request.vertexShader.source.dataBegin);
+ auto fragmentShaderID = loadShader(GL_FRAGMENT_SHADER, request.fragmentShader.source.dataBegin);
glAttachShader(programID, vertexShaderID);
glAttachShader(programID, fragmentShaderID);
diff --git a/tools/render-test/render-test.vcxproj b/tools/render-test/render-test.vcxproj
index a175d3973..1b022f913 100644
--- a/tools/render-test/render-test.vcxproj
+++ b/tools/render-test/render-test.vcxproj
@@ -22,7 +22,7 @@
<ProjectGuid>{96610759-07B9-4EEB-A974-5C634A2E742B}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>rendertest</RootNamespace>
- <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
+ <WindowsTargetPlatformVersion>10.0.14393.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
@@ -75,19 +75,23 @@
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
- <IncludePath>$(SolutionDir);$(IncludePath)</IncludePath>
+ <IncludePath>$(SolutionDir)external\;$(SolutionDir);$(IncludePath)</IncludePath>
+ <LibraryPath>$(SolutionDir)external\vulkan\lib\windows-$(PlatformShortName)\;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
- <IncludePath>$(SolutionDir);$(IncludePath)</IncludePath>
+ <IncludePath>$(SolutionDir)external\;$(SolutionDir);$(IncludePath)</IncludePath>
+ <LibraryPath>$(SolutionDir)external\vulkan\lib\windows-$(PlatformShortName)\;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
- <IncludePath>$(SolutionDir);$(IncludePath)</IncludePath>
+ <IncludePath>$(SolutionDir)external\;$(SolutionDir);$(IncludePath)</IncludePath>
+ <LibraryPath>$(SolutionDir)external\vulkan\lib\windows-$(PlatformShortName)\;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
- <IncludePath>$(SolutionDir);$(IncludePath)</IncludePath>
+ <IncludePath>$(SolutionDir)external\;$(SolutionDir);$(IncludePath)</IncludePath>
+ <LibraryPath>$(SolutionDir)external\vulkan\lib\windows-$(PlatformShortName)\;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
@@ -165,14 +169,18 @@
<ClCompile Include="main.cpp" />
<ClCompile Include="options.cpp" />
<ClCompile Include="render-d3d11.cpp" />
+ <ClCompile Include="render-d3d12.cpp" />
<ClCompile Include="render-gl.cpp" />
+ <ClCompile Include="render-vk.cpp" />
<ClCompile Include="shader-input-layout.cpp" />
<ClCompile Include="slang-support.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="options.h" />
<ClInclude Include="render-d3d11.h" />
+ <ClInclude Include="render-d3d12.h" />
<ClInclude Include="render-gl.h" />
+ <ClInclude Include="render-vk.h" />
<ClInclude Include="render.h" />
<ClInclude Include="shader-input-layout.h" />
<ClInclude Include="slang-support.h" />
diff --git a/tools/render-test/render-test.vcxproj.filters b/tools/render-test/render-test.vcxproj.filters
index 985e24b8b..e1077e4e8 100644
--- a/tools/render-test/render-test.vcxproj.filters
+++ b/tools/render-test/render-test.vcxproj.filters
@@ -33,6 +33,12 @@
<ClCompile Include="shader-input-layout.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="render-vk.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="render-d3d12.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="options.h">
@@ -56,5 +62,11 @@
<ClInclude Include="shader-input-layout.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="render-vk.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="render-d3d12.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
</ItemGroup>
</Project> \ No newline at end of file
diff --git a/tools/render-test/render-vk.cpp b/tools/render-test/render-vk.cpp
new file mode 100644
index 000000000..fd080931d
--- /dev/null
+++ b/tools/render-test/render-vk.cpp
@@ -0,0 +1,1033 @@
+// render-vk.cpp
+#include "render-vk.h"
+
+#include "options.h"
+#include "render.h"
+
+#ifdef _WIN32
+#define VK_USE_PLATFORM_WIN32_KHR 1
+#endif
+
+#define VK_NO_PROTOTYPES
+#include <vulkan/vulkan.h>
+
+#define ENABLE_VALIDATION_LAYER 1
+
+
+#ifdef _MSC_VER
+
+#include <stddef.h>
+
+#pragma warning(disable: 4996)
+
+#if (_MSC_VER < 1900)
+#define snprintf sprintf_s
+#endif
+#endif
+
+#define FOREACH_GLOBAL_PROC(M) \
+ M(vkCreateInstance) \
+ /* */
+
+#define FOREACH_INSTANCE_PROC(M) \
+ M(vkCreateDevice) \
+ M(vkCreateDebugReportCallbackEXT) \
+ M(vkDestroyDebugReportCallbackEXT) \
+ M(vkDebugReportMessageEXT) \
+ M(vkEnumeratePhysicalDevices) \
+ M(vkGetPhysicalDeviceProperties) \
+ M(vkGetPhysicalDeviceFeatures) \
+ M(vkGetPhysicalDeviceMemoryProperties) \
+ M(vkGetPhysicalDeviceQueueFamilyProperties) \
+ M(vkGetDeviceProcAddr) \
+ /* */
+
+#define FOREACH_DEVICE_PROC(M) \
+ M(vkCreateDescriptorPool) \
+ M(vkCreateCommandPool) \
+ M(vkGetDeviceQueue) \
+ M(vkAllocateCommandBuffers) \
+ M(vkBeginCommandBuffer) \
+ M(vkEndCommandBuffer) \
+ M(vkQueueSubmit) \
+ M(vkQueueWaitIdle) \
+ M(vkFreeCommandBuffers) \
+ M(vkCreateBuffer) \
+ M(vkGetBufferMemoryRequirements) \
+ M(vkAllocateMemory) \
+ M(vkBindBufferMemory) \
+ M(vkMapMemory) \
+ M(vkUnmapMemory) \
+ M(vkCmdCopyBuffer) \
+ M(vkDestroyBuffer) \
+ M(vkFreeMemory) \
+ M(vkCreateDescriptorSetLayout) \
+ M(vkAllocateDescriptorSets) \
+ M(vkUpdateDescriptorSets) \
+ M(vkCreatePipelineLayout) \
+ M(vkCreateComputePipelines) \
+ M(vkCmdBindPipeline) \
+ M(vkCmdBindDescriptorSets) \
+ M(vkCmdDispatch) \
+ M(vkDestroyPipeline) \
+ M(vkCreateShaderModule) \
+ /* */
+
+namespace renderer_test {
+
+class VKRenderer : public Renderer, public ShaderCompiler
+{
+public:
+
+ VkInstance instance;
+ VkPhysicalDevice physicalDevice;
+ VkPhysicalDeviceProperties deviceProperties;
+ VkPhysicalDeviceFeatures deviceFeatures;
+ VkPhysicalDeviceMemoryProperties deviceMemoryProperties;
+ VkPhysicalDeviceFeatures enabledFeatures;
+ VkDevice device;
+ VkQueue queue;
+ VkCommandPool commandPool;
+ VkSubmitInfo submitInfo;
+ VkDebugReportCallbackEXT debugReportCallback;
+
+
+#define DECLARE_PROC(NAME) PFN_##NAME NAME;
+ DECLARE_PROC(vkGetInstanceProcAddr);
+ FOREACH_GLOBAL_PROC(DECLARE_PROC)
+ FOREACH_INSTANCE_PROC(DECLARE_PROC)
+ FOREACH_DEVICE_PROC(DECLARE_PROC)
+#undef DECLARE_PROC
+
+ // Renderer interface
+
+ void checkResult(VkResult result)
+ {
+ assert(result == VK_SUCCESS);
+ }
+
+ VkBool32 handleDebugMessage(
+ VkDebugReportFlagsEXT flags,
+ VkDebugReportObjectTypeEXT objType,
+ uint64_t srcObject,
+ size_t location,
+ int32_t msgCode,
+ const char* pLayerPrefix,
+ const char* pMsg)
+ {
+ char const* severity = "message";
+ if(flags & VK_DEBUG_REPORT_WARNING_BIT_EXT)
+ severity = "warning";
+ if(flags & VK_DEBUG_REPORT_ERROR_BIT_EXT)
+ severity = "error";
+
+ char buffer[1024];
+ sprintf_s(buffer,
+ "%s: %s %d: %s\n",
+ pLayerPrefix,
+ severity,
+ msgCode,
+ pMsg);
+
+ fprintf(stderr, "%s", buffer);
+ fflush(stderr);
+
+ OutputDebugStringA(buffer);
+
+ return VK_FALSE;
+ }
+
+ static VKAPI_ATTR VkBool32 VKAPI_CALL debugMessageCallback(
+ VkDebugReportFlagsEXT flags,
+ VkDebugReportObjectTypeEXT objType,
+ uint64_t srcObject,
+ size_t location,
+ int32_t msgCode,
+ const char* pLayerPrefix,
+ const char* pMsg,
+ void* pUserData)
+ {
+ return ((VKRenderer*) pUserData)->handleDebugMessage(
+ flags, objType, srcObject, location, msgCode, pLayerPrefix, pMsg);
+ }
+
+ virtual void initialize(void* inWindowHandle) override
+ {
+ char const* dynamicLibraryName = "vulkan-1.dll";
+ HMODULE vulkan = LoadLibraryA(dynamicLibraryName);
+ if(!vulkan)
+ {
+ fprintf(stderr, "error: failed load '%s'\n", dynamicLibraryName);
+ exit(1);
+ }
+
+ vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr) GetProcAddress(vulkan, "vkGetInstanceProcAddr");
+ if(!vkGetInstanceProcAddr)
+ {
+ fprintf(stderr,
+ "error: failed load symbol 'vkGetInstanceProcAddr'\n");
+ exit(1);
+ }
+
+ VkApplicationInfo applicationInfo = { VK_STRUCTURE_TYPE_APPLICATION_INFO };
+ applicationInfo.pApplicationName = "slang-render-test";
+ applicationInfo.pEngineName = "slang-render-test";
+ applicationInfo.apiVersion = VK_API_VERSION_1_0;
+
+ char const* instanceExtensions[] = {
+ VK_KHR_SURFACE_EXTENSION_NAME,
+#ifdef _WIN32
+ VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
+#else
+#endif
+
+#if ENABLE_VALIDATION_LAYER
+ VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
+#endif
+ };
+
+ VkInstanceCreateInfo instanceCreateInfo = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
+ instanceCreateInfo.pApplicationInfo = &applicationInfo;
+
+ instanceCreateInfo.enabledExtensionCount = sizeof(instanceExtensions) / sizeof(instanceExtensions[0]);
+ instanceCreateInfo.ppEnabledExtensionNames = &instanceExtensions[0];
+
+#if ENABLE_VALIDATION_LAYER
+
+ uint32_t layerCount = 1;
+ const char *layerNames[] = {
+ "VK_LAYER_LUNARG_standard_validation"
+ };
+
+ instanceCreateInfo.enabledLayerCount = layerCount;
+ instanceCreateInfo.ppEnabledLayerNames = layerNames;
+#endif
+
+ instance = 0;
+
+#define LOAD_INSTANCE_PROC(NAME) NAME = (PFN_##NAME) vkGetInstanceProcAddr(instance, #NAME);
+
+ FOREACH_GLOBAL_PROC(LOAD_INSTANCE_PROC);
+
+ checkResult(vkCreateInstance(
+ &instanceCreateInfo,
+ nullptr,
+ &instance));
+
+ FOREACH_INSTANCE_PROC(LOAD_INSTANCE_PROC);
+
+#undef LOAD_INSTANCE_PROC
+
+
+#if ENABLE_VALIDATION_LAYER
+ VkDebugReportFlagsEXT debugFlags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
+
+ VkDebugReportCallbackCreateInfoEXT debugCreateInfo = { VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT };
+ debugCreateInfo.pfnCallback = &debugMessageCallback;
+ debugCreateInfo.pUserData = this;
+ debugCreateInfo.flags = debugFlags;
+
+ checkResult(vkCreateDebugReportCallbackEXT(
+ instance, &debugCreateInfo, nullptr, &debugReportCallback));
+
+#endif
+
+ uint32_t physicalDeviceCount = 0;
+ checkResult(vkEnumeratePhysicalDevices(
+ instance, &physicalDeviceCount, nullptr));
+
+ VkPhysicalDevice* physicalDevices = (VkPhysicalDevice*)alloca(
+ physicalDeviceCount * sizeof(VkPhysicalDevice));
+ checkResult(vkEnumeratePhysicalDevices(
+ instance, &physicalDeviceCount, physicalDevices));
+
+ uint32_t selectedDeviceIndex = 0;
+ // TODO: allow override of selected device
+ physicalDevice = physicalDevices[selectedDeviceIndex];
+
+ vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties);
+ vkGetPhysicalDeviceFeatures(physicalDevice, &deviceFeatures);
+ vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemoryProperties);
+
+ uint32_t queueFamilyCount = 0;
+ vkGetPhysicalDeviceQueueFamilyProperties(
+ physicalDevice, &queueFamilyCount, nullptr);
+
+ VkQueueFamilyProperties* queueFamilies = (VkQueueFamilyProperties*)alloca(
+ queueFamilyCount * sizeof(VkQueueFamilyProperties));
+ vkGetPhysicalDeviceQueueFamilyProperties(
+ physicalDevice, &queueFamilyCount, queueFamilies);
+
+ // Find a queue that can service our needs
+ VkQueueFlags reqQueueFlags =
+ VK_QUEUE_GRAPHICS_BIT
+ | VK_QUEUE_COMPUTE_BIT;
+
+ uint32_t queueFamilyIndex = uint32_t(-1);
+ for (uint32_t qq = 0; qq < queueFamilyCount; ++qq)
+ {
+ if ((queueFamilies[qq].queueFlags & reqQueueFlags) == reqQueueFlags)
+ {
+ queueFamilyIndex = qq;
+ break;
+ }
+ }
+ assert(queueFamilyIndex < queueFamilyCount);
+
+ float queuePriority = 0.0f;
+ VkDeviceQueueCreateInfo queueCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO };
+ queueCreateInfo.queueFamilyIndex = queueFamilyIndex;
+ queueCreateInfo.queueCount = 1;
+ queueCreateInfo.pQueuePriorities = &queuePriority;
+
+ char const* const deviceExtensions[] =
+ {
+ VK_KHR_SWAPCHAIN_EXTENSION_NAME,
+ };
+
+ VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
+ deviceCreateInfo.queueCreateInfoCount = 1;
+ deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo;
+ deviceCreateInfo.pEnabledFeatures = &enabledFeatures;
+
+ deviceCreateInfo.enabledExtensionCount = sizeof(deviceExtensions) / sizeof(deviceExtensions[0]);
+ deviceCreateInfo.ppEnabledExtensionNames = &deviceExtensions[0];
+
+ checkResult(vkCreateDevice(
+ physicalDevice, &deviceCreateInfo, nullptr, &device));
+
+#define LOAD_DEVICE_PROC(NAME) NAME = (PFN_##NAME) vkGetDeviceProcAddr(device, #NAME);
+ FOREACH_DEVICE_PROC(LOAD_DEVICE_PROC)
+#undef LOAD_DEVICE_PROC
+
+ // Create a command pool
+
+ VkCommandPoolCreateInfo commandPoolCreateInfo = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
+ commandPoolCreateInfo.queueFamilyIndex = queueFamilyIndex;
+ commandPoolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
+
+ checkResult(vkCreateCommandPool(
+ device, &commandPoolCreateInfo, nullptr, &commandPool));
+
+ vkGetDeviceQueue(
+ device,
+ queueFamilyIndex,
+ 0,
+ &queue);
+
+ // set up swap chain
+
+ // create command buffers
+
+ // depth/stencil?
+
+ // render pass?
+
+ // pipeline cache
+
+ // frame buffer
+
+
+
+// create semaphores for sync
+
+
+ }
+
+ float clearColor[4];
+ virtual void setClearColor(float const* color) override
+ {
+ for(int ii = 0; ii < 4; ++ii)
+ clearColor[ii] = color[ii];
+ }
+
+ virtual void clearFrame() override
+ {
+ }
+
+ virtual void presentFrame() override
+ {
+ }
+
+ virtual void captureScreenShot(char const* outputPath) override
+ {
+ }
+
+ virtual ShaderCompiler* getShaderCompiler() override
+ {
+ return this;
+ }
+
+ VkCommandBuffer getCommandBuffer()
+ {
+ VkCommandBufferAllocateInfo info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
+ info.commandPool = commandPool;
+ info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+ info.commandBufferCount = 1;
+
+ VkCommandBuffer commandBuffer;
+ checkResult(vkAllocateCommandBuffers(
+ device, &info, &commandBuffer));
+
+ return commandBuffer;
+ }
+
+ VkCommandBuffer beginCommandBuffer()
+ {
+ VkCommandBuffer commandBuffer = getCommandBuffer();
+
+ VkCommandBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
+ checkResult(vkBeginCommandBuffer(commandBuffer, &beginInfo));
+
+ return commandBuffer;
+ }
+
+ void flushCommandBuffer(VkCommandBuffer commandBuffer)
+ {
+ checkResult(vkEndCommandBuffer(commandBuffer));
+
+ VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
+ submitInfo.commandBufferCount = 1;
+ submitInfo.pCommandBuffers = &commandBuffer;
+
+ checkResult(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
+ checkResult(vkQueueWaitIdle(queue));
+
+ vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer);
+ }
+
+ struct BufferImpl
+ {
+ VkBuffer buffer;
+ VkDeviceMemory memory;
+ };
+
+ BufferImpl createBufferImpl(
+ size_t bufferSize,
+ VkBufferUsageFlags usage,
+ VkMemoryPropertyFlags reqMemoryProperties,
+ void const* initData = nullptr)
+ {
+ if( initData )
+ {
+ // TODO: what if we are allocating it as CPU-writable anyway?
+ usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT;
+ }
+
+ VkBufferCreateInfo bufferCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
+ bufferCreateInfo.size = bufferSize;
+ bufferCreateInfo.usage = usage;
+
+ VkBuffer buffer;
+ checkResult(vkCreateBuffer(
+ device, &bufferCreateInfo, nullptr, &buffer));
+
+ VkMemoryRequirements memoryReqs = {};
+ vkGetBufferMemoryRequirements(device, buffer, &memoryReqs);
+
+ uint32_t memoryTypeIndex = getMemoryTypeIndex(
+ memoryReqs.memoryTypeBits, reqMemoryProperties);
+
+ VkMemoryPropertyFlags actualMemoryProperites = deviceMemoryProperties.memoryTypes[memoryTypeIndex].propertyFlags;
+
+ VkMemoryAllocateInfo allocateInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
+ allocateInfo.allocationSize = memoryReqs.size;
+ allocateInfo.memoryTypeIndex = memoryTypeIndex;
+
+ VkDeviceMemory memory;
+ checkResult(vkAllocateMemory(
+ device, &allocateInfo, nullptr, &memory));
+
+ checkResult(vkBindBufferMemory(
+ device, buffer, memory, 0));
+
+ if( initData )
+ {
+ // TODO: only create staging buffer if the memory type
+ // used for the buffer doesn't let us fill things in
+ // directly.
+
+ BufferImpl staging = createBufferImpl(
+ bufferSize,
+ VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
+
+ // Copy into staging buffer
+ void* mappedData = nullptr;
+ checkResult(vkMapMemory(device, staging.memory, 0, bufferSize, 0, &mappedData));
+ memcpy(mappedData, initData, bufferSize);
+ vkUnmapMemory(device, staging.memory);
+
+ // Copy from staging buffer to real buffer
+ VkCommandBuffer commandBuffer = beginCommandBuffer();
+
+ VkBufferCopy copyInfo = {};
+ copyInfo.size = bufferSize;
+ vkCmdCopyBuffer(
+ commandBuffer,
+ staging.buffer,
+ buffer,
+ 1,
+ &copyInfo);
+
+ flushCommandBuffer(commandBuffer);
+
+ // Now destroy the staging buffer
+ vkDestroyBuffer(device, staging.buffer, nullptr);
+ vkFreeMemory(device, staging.memory, nullptr);
+ }
+
+ BufferImpl impl;
+ impl.buffer = buffer;
+ impl.memory = memory;
+ return impl;
+ }
+
+ virtual Buffer* createBuffer(BufferDesc const& desc) override
+ {
+ size_t bufferSize = desc.size;
+
+ VkBufferUsageFlags usage = 0;
+ VkMemoryPropertyFlags reqMemoryProperties = 0;
+
+ switch( desc.flavor )
+ {
+ case BufferFlavor::Constant:
+ usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
+ reqMemoryProperties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+ break;
+
+ case BufferFlavor::Vertex:
+ usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
+ reqMemoryProperties = 0;
+ break;
+ }
+
+ BufferImpl bufferImpl = createBufferImpl(
+ bufferSize,
+ usage,
+ reqMemoryProperties,
+ desc.initData);
+
+ BufferImpl* bufferPtr = new BufferImpl();
+ *bufferPtr = bufferImpl;
+ return (Buffer*) bufferPtr;
+ }
+
+ struct InputLayoutImpl
+ {
+ };
+
+ virtual InputLayout* createInputLayout(InputElementDesc const* inputElements, UInt inputElementCount) override
+ {
+ InputLayoutImpl* impl = new InputLayoutImpl();
+
+ // TODO: actually initialize things
+
+ return (InputLayout*) impl;
+ }
+
+ virtual void* map(Buffer* buffer, MapFlavor flavor) override
+ {
+ return nullptr;
+ }
+
+ virtual void unmap(Buffer* buffer) override
+ {
+ }
+
+ virtual void setInputLayout(InputLayout* inputLayout) override
+ {
+ }
+
+ virtual void setPrimitiveTopology(PrimitiveTopology topology) override
+ {
+ }
+
+ virtual void setVertexBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* strides, UInt const* offsets) override
+ {
+ }
+
+ struct ShaderProgramImpl
+ {
+ VkPipelineShaderStageCreateInfo compute;
+ VkPipelineShaderStageCreateInfo vertex;
+ VkPipelineShaderStageCreateInfo fragment;
+ };
+
+ ShaderProgramImpl* currentProgram = nullptr;
+ virtual void setShaderProgram(ShaderProgram* program) override
+ {
+ currentProgram = (ShaderProgramImpl*) program;
+ }
+
+ virtual void setConstantBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* offsets) override
+ {
+ }
+
+ virtual void draw(UInt vertexCount, UInt startVertex = 0) override
+ {
+ }
+
+ struct BindingImpl
+ {
+ ShaderInputType type;
+ InputBufferType bufferType; // Only valid if `type` is `Buffer`
+
+ VkImageView srv;
+ VkBufferView uav;
+ VkBuffer buffer;
+ VkSampler samplerState;
+
+ int binding = 0;
+ bool isOutput = false;
+ int bufferLength = 0;
+ };
+
+ struct BindingStateImpl
+ {
+ Slang::List<BindingImpl> bindings;
+ int numRenderTargets;
+ };
+
+ uint32_t getMemoryTypeIndex(
+ uint32_t inTypeBits,
+ VkMemoryPropertyFlags properties)
+ {
+ uint32_t typeBits = inTypeBits;
+ uint32_t typeIndex = 0;
+ while( typeBits )
+ {
+ if((deviceMemoryProperties.memoryTypes[typeIndex].propertyFlags & properties) == properties)
+ {
+ return typeIndex;
+ }
+ typeIndex++;
+ typeBits >>= 1;
+ }
+
+ assert(!"failed to find a usable memory type");
+ return uint32_t(-1);
+ }
+
+ void createInputBuffer(
+ ShaderInputLayoutEntry const& entry,
+ InputBufferDesc const& bufferDesc,
+ Slang::List<unsigned int> const& bufferData,
+ VkBuffer &bufferOut,
+ VkBufferView &uavOut,
+ VkImageView &srvOut)
+ {
+ size_t bufferSize = bufferData.Count() * sizeof(unsigned int);
+ void const* initData = bufferData.Buffer();
+
+ VkBufferUsageFlags usage = 0;
+ VkMemoryPropertyFlags reqMemoryProperties = 0;
+
+ switch( bufferDesc.type )
+ {
+ case InputBufferType::ConstantBuffer:
+ usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
+ reqMemoryProperties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+ break;
+
+ case InputBufferType::StorageBuffer:
+ usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
+ reqMemoryProperties = 0;
+ break;
+ }
+
+ // If we are going to read back from the buffer, be sure to request
+ // the required access.
+ if(entry.isOutput)
+ {
+ usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
+ }
+
+ BufferImpl bufferImpl = createBufferImpl(
+ bufferSize,
+ usage,
+ reqMemoryProperties,
+ initData);
+
+ // TODO: need to hang onto the `memory` field so
+ // that we can release it when we are done.
+
+ bufferOut = bufferImpl.buffer;
+
+ // Fill in any views needed
+ switch( bufferDesc.type )
+ {
+ case InputBufferType::ConstantBuffer:
+ break;
+
+ case InputBufferType::StorageBuffer:
+ {
+ }
+ break;
+ }
+ }
+
+ void createInputTexture(
+ InputTextureDesc const& inputDesc,
+ VkImageView& viewOut)
+ {
+ TextureData texData;
+ generateTextureData(texData, inputDesc);
+ assert(!"unimplemented");
+ }
+
+ void createInputSampler(
+ InputSamplerDesc const& inputDesc,
+ VkSampler& stateOut)
+ {
+ assert(!"unimplemented");
+ }
+
+ virtual BindingState* createBindingState(const ShaderInputLayout & layout)
+ {
+ BindingStateImpl* bindingState = new BindingStateImpl();
+ bindingState->numRenderTargets = layout.numRenderTargets;
+ for (auto & entry : layout.entries)
+ {
+ BindingImpl binding;
+ binding.type = entry.type;
+ binding.binding = entry.hlslBinding;
+ binding.isOutput = entry.isOutput;
+ switch (entry.type)
+ {
+ case ShaderInputType::Buffer:
+ {
+ createInputBuffer(entry, entry.bufferDesc, entry.bufferData, binding.buffer, binding.uav, binding.srv);
+ binding.bufferLength = (int)(entry.bufferData.Count() * sizeof(unsigned int));
+ binding.bufferType = entry.bufferDesc.type;
+ }
+ break;
+ case ShaderInputType::Texture:
+ {
+ createInputTexture(entry.textureDesc, binding.srv);
+ }
+ break;
+ case ShaderInputType::Sampler:
+ {
+ createInputSampler(entry.samplerDesc, binding.samplerState);
+ }
+ break;
+ case ShaderInputType::CombinedTextureSampler:
+ {
+ throw "not implemented";
+ }
+ break;
+ }
+ bindingState->bindings.Add(binding);
+ }
+
+ return (BindingState*) bindingState;
+ }
+
+ BindingStateImpl* currentBindingState = nullptr;
+ virtual void setBindingState(BindingState * state)
+ {
+ currentBindingState = (BindingStateImpl*) state;
+ }
+
+ virtual void serializeOutput(BindingState* s, const char * fileName)
+ {
+ auto state = (BindingStateImpl*) s;
+
+ FILE * f = fopen(fileName, "wb");
+ int id = 0;
+ for (auto& bb: state->bindings)
+ {
+ if (bb.isOutput)
+ {
+ if (bb.buffer)
+ {
+ // create staging buffer
+ size_t bufferSize = bb.bufferLength;
+ BufferImpl staging = createBufferImpl(
+ bufferSize,
+ VK_BUFFER_USAGE_TRANSFER_DST_BIT,
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
+
+ // Copy from real buffer to staging buffer
+ VkCommandBuffer commandBuffer = beginCommandBuffer();
+
+ VkBufferCopy copyInfo = {};
+ copyInfo.size = bufferSize;
+ vkCmdCopyBuffer(
+ commandBuffer,
+ bb.buffer,
+ staging.buffer,
+ 1,
+ &copyInfo);
+
+ flushCommandBuffer(commandBuffer);
+
+ // Write out the data from the buffer
+ void* mappedData = nullptr;
+ checkResult(vkMapMemory(device, staging.memory, 0, bufferSize, 0, &mappedData));
+
+ auto ptr = (unsigned int *) mappedData;
+ for (auto i = 0u; i < bufferSize / sizeof(unsigned int); i++)
+ fprintf(f, "%X\n", ptr[i]);
+
+ vkUnmapMemory(device, staging.memory);
+
+ // Now destroy the staging buffer
+ vkDestroyBuffer(device, staging.buffer, nullptr);
+ vkFreeMemory(device, staging.memory, nullptr);
+ }
+ else
+ {
+ printf("invalid output type at %d.\n", id);
+ }
+ }
+ id++;
+ }
+ fclose(f);
+
+
+ }
+
+ virtual void dispatchCompute(int x, int y, int z) override
+ {
+
+
+ // HACK: create a new pipeline for every call
+
+ // First create a pipeline layout based on what is bound
+
+ Slang::List<VkDescriptorSetLayoutBinding> bindings;
+
+ for( auto bb : currentBindingState->bindings )
+ {
+ switch( bb.type )
+ {
+ case ShaderInputType::Buffer:
+ {
+ switch(bb.bufferType)
+ {
+ case InputBufferType::StorageBuffer:
+ {
+ VkDescriptorSetLayoutBinding binding = {};
+ binding.binding = bb.binding;
+ binding.descriptorCount = 1;
+ binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+ binding.stageFlags = VK_SHADER_STAGE_ALL;
+
+ bindings.Add(binding);
+ }
+ break;
+
+ default:
+ // handle other cases
+ break;
+ }
+ }
+ break;
+
+ default:
+ // TODO: handle the other cases
+ break;
+ }
+ }
+
+ VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
+ descriptorSetLayoutInfo.bindingCount = uint32_t(bindings.Count());
+ descriptorSetLayoutInfo.pBindings = bindings.Buffer();
+
+ VkDescriptorSetLayout descriptorSetLayout = 0;
+ checkResult(vkCreateDescriptorSetLayout(
+ device, &descriptorSetLayoutInfo, nullptr, &descriptorSetLayout));
+
+ // Create a descriptor pool for allocating sets
+
+ VkDescriptorPoolSize poolSizes[] =
+ {
+ { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 128 },
+ { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 128 },
+ { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 128 },
+ };
+
+ VkDescriptorPoolCreateInfo descriptorPoolInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
+ descriptorPoolInfo.maxSets = 128; // TODO: actually pick a size
+ descriptorPoolInfo.poolSizeCount = sizeof(poolSizes) / sizeof(poolSizes[0]);
+ descriptorPoolInfo.pPoolSizes = poolSizes;
+
+ VkDescriptorPool descriptorPool;
+ checkResult(vkCreateDescriptorPool(
+ device, &descriptorPoolInfo, nullptr, &descriptorPool));
+
+ // Create a descriptor set based on our layout
+
+ VkDescriptorSetAllocateInfo descriptorSetAllocInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
+ descriptorSetAllocInfo.descriptorPool = descriptorPool;
+ descriptorSetAllocInfo.descriptorSetCount = 1;
+ descriptorSetAllocInfo.pSetLayouts = &descriptorSetLayout;
+
+ VkDescriptorSet descriptorSet;
+ checkResult(vkAllocateDescriptorSets(
+ device, &descriptorSetAllocInfo, &descriptorSet));
+
+ // Fill in the descritpor set, using our binding information
+ for( auto bb : currentBindingState->bindings )
+ {
+ switch( bb.type )
+ {
+ case ShaderInputType::Buffer:
+ {
+ switch(bb.bufferType)
+ {
+ case InputBufferType::StorageBuffer:
+ {
+ VkDescriptorBufferInfo bufferInfo;
+ bufferInfo.buffer = bb.buffer;
+ bufferInfo.offset = 0;
+ bufferInfo.range = bb.bufferLength;
+
+ VkWriteDescriptorSet writeInfo = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
+ writeInfo.descriptorCount = 1;
+ writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+ writeInfo.dstSet = descriptorSet;
+ writeInfo.dstBinding = bb.binding;
+ writeInfo.dstArrayElement = 0;
+ writeInfo.pBufferInfo = &bufferInfo;
+
+ vkUpdateDescriptorSets(
+ device,
+ 1,
+ &writeInfo,
+ 0,
+ nullptr);
+ }
+ break;
+
+ default:
+ // handle other cases
+ break;
+ }
+ }
+ break;
+
+ default:
+ // TODO: handle the other cases
+ break;
+ }
+ }
+
+
+ // Create a pipeline layout based on our descriptor set layout(s)
+
+ VkPipelineLayoutCreateInfo pipelineLayoutInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
+ pipelineLayoutInfo.setLayoutCount = 1;
+ pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout;
+
+ VkPipelineLayout pipelineLayout = 0;
+ checkResult(vkCreatePipelineLayout(
+ device, &pipelineLayoutInfo, nullptr, &pipelineLayout));
+
+ // Then create a pipeline to use that layout
+
+ VkComputePipelineCreateInfo computePipelineInfo = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO };
+ computePipelineInfo.stage = currentProgram->compute;
+ computePipelineInfo.layout = pipelineLayout;
+
+ VkPipelineCache pipelineCache = 0;
+
+ VkPipeline pipeline;
+ checkResult(vkCreateComputePipelines(
+ device, pipelineCache, 1, &computePipelineInfo, nullptr, &pipeline));
+
+ // Also create descriptor sets based on the given pipeline layout
+
+ VkCommandBuffer commandBuffer = beginCommandBuffer();
+
+ vkCmdBindPipeline(
+ commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline);
+
+ vkCmdBindDescriptorSets(
+ commandBuffer,
+ VK_PIPELINE_BIND_POINT_COMPUTE,
+ pipelineLayout,
+ 0, 1,
+ &descriptorSet,
+ 0,
+ nullptr);
+
+ vkCmdDispatch(commandBuffer, x, y, z);
+
+ flushCommandBuffer(commandBuffer);
+
+ vkDestroyPipeline(device, pipeline, nullptr);
+
+ // TODO: need to free up the other resources too...
+ }
+
+ // ShaderCompiler interface
+
+ VkPipelineShaderStageCreateInfo compileEntryPoint(
+ ShaderCompileRequest::EntryPoint const& entryPointRequest,
+ VkShaderStageFlagBits stage)
+ {
+ char const* dataBegin = entryPointRequest.source.dataBegin;
+ char const* dataEnd = entryPointRequest.source.dataEnd;
+
+ // We need to make a copy of the code, since the Slang compiler
+ // will free the memory after a compile request is closed.
+ size_t codeSize = dataEnd - dataBegin;
+ char* codeBegin = (char*) malloc(codeSize);
+ memcpy(codeBegin, dataBegin, codeSize);
+
+ VkShaderModuleCreateInfo moduleCreateInfo = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };
+ moduleCreateInfo.pCode = (uint32_t*) codeBegin;
+ moduleCreateInfo.codeSize = codeSize;
+
+ VkShaderModule module;
+ checkResult(vkCreateShaderModule(
+ device,
+ &moduleCreateInfo,
+ nullptr,
+ &module));
+
+ VkPipelineShaderStageCreateInfo shaderStageCreateInfo = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
+ shaderStageCreateInfo.stage = stage;
+
+ shaderStageCreateInfo.module = module;
+ shaderStageCreateInfo.pName = "main";
+ return shaderStageCreateInfo;
+ }
+
+ virtual ShaderProgram* compileProgram(ShaderCompileRequest const& request) override
+ {
+ ShaderProgramImpl* impl = new ShaderProgramImpl();
+
+ if( request.computeShader.name )
+ {
+ impl->compute = compileEntryPoint(
+ request.computeShader,
+ VK_SHADER_STAGE_COMPUTE_BIT);
+ }
+ else
+ {
+ impl->vertex = compileEntryPoint(
+ request.vertexShader,
+ VK_SHADER_STAGE_VERTEX_BIT);
+
+ impl->fragment = compileEntryPoint(
+ request.fragmentShader,
+ VK_SHADER_STAGE_FRAGMENT_BIT);
+ }
+
+ return (ShaderProgram*) impl;
+ }
+};
+
+
+
+Renderer* createVKRenderer()
+{
+ return new VKRenderer();
+}
+
+} // renderer_test
diff --git a/tools/render-test/render-vk.h b/tools/render-test/render-vk.h
new file mode 100644
index 000000000..7f6d789d0
--- /dev/null
+++ b/tools/render-test/render-vk.h
@@ -0,0 +1,10 @@
+// render-vk.h
+#pragma once
+
+namespace renderer_test {
+
+class Renderer;
+
+Renderer* createVKRenderer();
+
+} // renderer_test
diff --git a/tools/render-test/render.h b/tools/render-test/render.h
index 174ba0b7b..5eb0c967d 100644
--- a/tools/render-test/render.h
+++ b/tools/render-test/render.h
@@ -16,7 +16,14 @@ struct ShaderCompileRequest
struct SourceInfo
{
char const* path;
- char const* text;
+
+ // The data may either be source text (in which
+ // case it can be assumed to be nul-terminated with
+ // `dataEnd` pointing at the terminator), or
+ // raw binary data (in which case `dataEnd` points
+ // at the end of the buffer).
+ char const* dataBegin;
+ char const* dataEnd;
};
struct EntryPoint
diff --git a/tools/render-test/slang-support.cpp b/tools/render-test/slang-support.cpp
index 9263aa41b..a75e35bd4 100644
--- a/tools/render-test/slang-support.cpp
+++ b/tools/render-test/slang-support.cpp
@@ -63,24 +63,24 @@ struct SlangShaderCompilerWrapper : public ShaderCompiler
// active in each case.
vertexTranslationUnit = spAddTranslationUnit(slangRequest, sourceLanguage, nullptr);
- spAddTranslationUnitSourceString(slangRequest, vertexTranslationUnit, request.source.path, request.source.text);
+ spAddTranslationUnitSourceString(slangRequest, vertexTranslationUnit, request.source.path, request.source.dataBegin);
spTranslationUnit_addPreprocessorDefine(slangRequest, vertexTranslationUnit, "__GLSL_VERTEX__", "1");
vertexEntryPointName = "main";
fragmentTranslationUnit = spAddTranslationUnit(slangRequest, sourceLanguage, nullptr);
- spAddTranslationUnitSourceString(slangRequest, fragmentTranslationUnit, request.source.path, request.source.text);
+ spAddTranslationUnitSourceString(slangRequest, fragmentTranslationUnit, request.source.path, request.source.dataBegin);
spTranslationUnit_addPreprocessorDefine(slangRequest, fragmentTranslationUnit, "__GLSL_FRAGMENT__", "1");
fragmentEntryPointName = "main";
computeTranslationUnit = spAddTranslationUnit(slangRequest, sourceLanguage, nullptr);
- spAddTranslationUnitSourceString(slangRequest, computeTranslationUnit, request.source.path, request.source.text);
+ spAddTranslationUnitSourceString(slangRequest, computeTranslationUnit, request.source.path, request.source.dataBegin);
spTranslationUnit_addPreprocessorDefine(slangRequest, computeTranslationUnit, "__GLSL_COMPUTE__", "1");
computeEntryPointName = "main";
}
else
{
int translationUnit = spAddTranslationUnit(slangRequest, sourceLanguage, nullptr);
- spAddTranslationUnitSourceString(slangRequest, translationUnit, request.source.path, request.source.text);
+ spAddTranslationUnitSourceString(slangRequest, translationUnit, request.source.path, request.source.dataBegin);
vertexTranslationUnit = translationUnit;
fragmentTranslationUnit = translationUnit;
@@ -108,8 +108,11 @@ struct SlangShaderCompilerWrapper : public ShaderCompiler
if (!compileErr)
{
ShaderCompileRequest innerRequest = request;
- char const* computeCode = spGetEntryPointSource(slangRequest, computeEntryPoint);
- innerRequest.computeShader.source.text = computeCode;
+
+ size_t codeSize = 0;
+ char const* code = (char const*) spGetEntryPointCode(slangRequest, computeEntryPoint, &codeSize);
+ innerRequest.computeShader.source.dataBegin = code;
+ innerRequest.computeShader.source.dataEnd = code + codeSize;
result = innerCompiler->compileProgram(innerRequest);
}
}
@@ -129,11 +132,17 @@ struct SlangShaderCompilerWrapper : public ShaderCompiler
{
ShaderCompileRequest innerRequest = request;
- char const* vertexCode = spGetEntryPointSource(slangRequest, vertexEntryPoint);
- char const* fragmentCode = spGetEntryPointSource(slangRequest, fragmentEntryPoint);
+ size_t vertexCodeSize = 0;
+ char const* vertexCode = (char const*) spGetEntryPointCode(slangRequest, vertexEntryPoint, &vertexCodeSize);
+
+ size_t fragmentCodeSize = 0;
+ char const* fragmentCode = (char const*) spGetEntryPointCode(slangRequest, fragmentEntryPoint, &fragmentCodeSize);
+
+ innerRequest.vertexShader.source.dataBegin = vertexCode;
+ innerRequest.vertexShader.source.dataEnd = vertexCode + vertexCodeSize;
- innerRequest.vertexShader.source.text = vertexCode;
- innerRequest.fragmentShader.source.text = fragmentCode;
+ innerRequest.fragmentShader.source.dataBegin = fragmentCode;
+ innerRequest.fragmentShader.source.dataEnd = fragmentCode + fragmentCodeSize;
result = innerCompiler->compileProgram(innerRequest);
}