summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorTim Foley <tfoleyNV@users.noreply.github.com>2018-08-03 08:39:28 -0700
committerGitHub <noreply@github.com>2018-08-03 08:39:28 -0700
commit68d705f6c805c9b4d31b386e065762e6db13ad18 (patch)
tree97ffc0f24358101222d1bc62ac0c50affc55af12 /tools
parent5ea746a571ced32a8975eb3a238c562b3d487149 (diff)
Major overhaul of Renderer abstraction, to support a new example (#624)
The original goal here was to bring up a second example program: `model-viewer`. While the existing `hello-world` example is enough to get somebody up to speed with the basics of the Slang API (as a drop-in replacement for `D3DCompile` or similar), it doesn't really show any of the big-picture stuff that Slang is meant to enable. There wasn't any use of D3D12/Vulkan descriptor tables/sets, and there wasn't any use of interfaces, generics, or `ParameterBlock`s in the shader code. The `model-viewer` example addresses these issues. Its shader code involves generics, interfaces, and multiple `ParameterBlock`s, and the host-side code demonstrates a few key things for working with Slang: * There is an application-level abstraction for parameter blocks, that combines the graphics-API descriptor set object with Slang type information * There is a shader cache layer used to look up an appropriate variant of a rendering effect by using parameter block types to "plug in" global type variables * There is a clear separation between the phases of compilation: a first phase that does semantic checking and enables reflection-based allocation of graphics API objects, followed by one or more code generation passes for specialized kernels. This example is certainly not perfect, and it will need to be revamped more going forward. In particular: * The output picture is ugly as sin. We need a plan for how to get this to load better content, perhaps even popping up an error message to note that the required input data isn't present in the basic repository. * The shader code is too simplistic. There isn't any real material variety, and the `IMaterial` abstraction is completely wrong. * The use of parameter blocks is facile because there are no resource parameters right now. Fixing that will likely expose issues around interfacing with Slang's reflection API. * The whole example exposes the issue that Slang's current APIs aren't really designed for the benefit of two-phase compilation (since our many client application has been stuck on one-phase compilation). * Global type parameters are actually a Bad Idea that we only did for compatibility with existing codebases. We should not be showing them off in an example of the Right Way to use Slang, but the language support for type parameters on entry points is still not complete. Of course, the majority of the changes here are *not* inside the example applications, and instead involve a major overhaul of the `Renderer` abstraction that is used for both tests and examples. The main thrust of the change is to make the abstraction layer be closer to the D3D12/Vulkan model than to a D3D11-style model. This is important for the `model-viewer` example, since it aspires to show how Slang can be incorporated into a renderer that targets a modern API. The most important bit is actually the use of descriptor sets and "pipeline layouts" a la Vulkan, since without these Slang's `ParameterBlock` abstraction won't make a lot of sense. Implementation of the abstraction for the various APIs has very much been on an as-needed basis. The current implementation is just enough for the two examples to work, plus enough to get all the tests to pass in both debug and release builds on Windows. A big missing feature in the API abstraction right now is memory lifetime management. The code had been trending toward something D3D11-like where a constant buffer could be mapped per-frame with the implementation doing behind-the-scenes allocation for targets like D3D12/Vulkan. I'd like to shift more toward a model of just exposing "transient" allocations that are only valid for one frame, because these are more representation of how an efficient renderer for next-generation APIs will work. That transition isn't actually complete, though, so there are problems with the existing examples where `hello-world` is actually scribbling into memory that the GPU might still be using, while `model-viewer` is doing full-on heavy-weight allocations on a per-frame basis with no real concern for the performance implications. All together, there are a lot of things here that need more work, but this branch has been way too long-lived already, and so I'd like to get this checked in as long as all the tests pass.
Diffstat (limited to 'tools')
-rw-r--r--tools/gfx/circular-resource-heap-d3d12.cpp (renamed from tools/slang-graphics/circular-resource-heap-d3d12.cpp)4
-rw-r--r--tools/gfx/circular-resource-heap-d3d12.h (renamed from tools/slang-graphics/circular-resource-heap-d3d12.h)4
-rw-r--r--tools/gfx/d3d-util.cpp (renamed from tools/slang-graphics/d3d-util.cpp)2
-rw-r--r--tools/gfx/d3d-util.h (renamed from tools/slang-graphics/d3d-util.h)2
-rw-r--r--tools/gfx/descriptor-heap-d3d12.cpp (renamed from tools/slang-graphics/descriptor-heap-d3d12.cpp)4
-rw-r--r--tools/gfx/descriptor-heap-d3d12.h (renamed from tools/slang-graphics/descriptor-heap-d3d12.h)87
-rw-r--r--tools/gfx/gfx.vcxproj (renamed from tools/slang-graphics/slang-graphics.vcxproj)21
-rw-r--r--tools/gfx/gfx.vcxproj.filters (renamed from tools/slang-graphics/slang-graphics.vcxproj.filters)9
-rw-r--r--tools/gfx/model.cpp530
-rw-r--r--tools/gfx/model.h73
-rw-r--r--tools/gfx/render-d3d11.cpp2112
-rw-r--r--tools/gfx/render-d3d11.h (renamed from tools/slang-graphics/render-d3d11.h)4
-rw-r--r--tools/gfx/render-d3d12.cpp (renamed from tools/slang-graphics/render-d3d12.cpp)1632
-rw-r--r--tools/gfx/render-d3d12.h (renamed from tools/slang-graphics/render-d3d12.h)4
-rw-r--r--tools/gfx/render-gl.cpp (renamed from tools/slang-graphics/render-gl.cpp)489
-rw-r--r--tools/gfx/render-gl.h (renamed from tools/slang-graphics/render-gl.h)4
-rw-r--r--tools/gfx/render-vk.cpp (renamed from tools/slang-graphics/render-vk.cpp)1212
-rw-r--r--tools/gfx/render-vk.h (renamed from tools/slang-graphics/render-vk.h)4
-rw-r--r--tools/gfx/render.cpp (renamed from tools/slang-graphics/render.cpp)13
-rw-r--r--tools/gfx/render.h (renamed from tools/slang-graphics/render.h)432
-rw-r--r--tools/gfx/resource-d3d12.cpp (renamed from tools/slang-graphics/resource-d3d12.cpp)2
-rw-r--r--tools/gfx/resource-d3d12.h (renamed from tools/slang-graphics/resource-d3d12.h)2
-rw-r--r--tools/gfx/surface.cpp (renamed from tools/slang-graphics/surface.cpp)2
-rw-r--r--tools/gfx/surface.h (renamed from tools/slang-graphics/surface.h)2
-rw-r--r--tools/gfx/vector-math.h14
-rw-r--r--tools/gfx/vk-api.cpp (renamed from tools/slang-graphics/vk-api.cpp)2
-rw-r--r--tools/gfx/vk-api.h (renamed from tools/slang-graphics/vk-api.h)2
-rw-r--r--tools/gfx/vk-device-queue.cpp (renamed from tools/slang-graphics/vk-device-queue.cpp)2
-rw-r--r--tools/gfx/vk-device-queue.h (renamed from tools/slang-graphics/vk-device-queue.h)2
-rw-r--r--tools/gfx/vk-module.cpp (renamed from tools/slang-graphics/vk-module.cpp)2
-rw-r--r--tools/gfx/vk-module.h (renamed from tools/slang-graphics/vk-module.h)2
-rw-r--r--tools/gfx/vk-swap-chain.cpp (renamed from tools/slang-graphics/vk-swap-chain.cpp)2
-rw-r--r--tools/gfx/vk-swap-chain.h (renamed from tools/slang-graphics/vk-swap-chain.h)2
-rw-r--r--tools/gfx/vk-util.cpp (renamed from tools/slang-graphics/vk-util.cpp)2
-rw-r--r--tools/gfx/vk-util.h (renamed from tools/slang-graphics/vk-util.h)2
-rw-r--r--tools/gfx/window.cpp (renamed from tools/slang-graphics/window.cpp)48
-rw-r--r--tools/gfx/window.h (renamed from tools/slang-graphics/window.h)23
-rw-r--r--tools/render-test/main.cpp117
-rw-r--r--tools/render-test/options.h2
-rw-r--r--tools/render-test/png-serialize-util.h2
-rw-r--r--tools/render-test/render-test.vcxproj10
-rw-r--r--tools/render-test/shader-input-layout.h2
-rw-r--r--tools/render-test/shader-renderer-util.cpp251
-rw-r--r--tools/render-test/shader-renderer-util.h56
-rw-r--r--tools/render-test/slang-support.cpp4
-rw-r--r--tools/render-test/slang-support.h4
-rw-r--r--tools/slang-graphics/render-d3d11.cpp1101
47 files changed, 6321 insertions, 1983 deletions
diff --git a/tools/slang-graphics/circular-resource-heap-d3d12.cpp b/tools/gfx/circular-resource-heap-d3d12.cpp
index 8b63819a5..20e47c4dd 100644
--- a/tools/slang-graphics/circular-resource-heap-d3d12.cpp
+++ b/tools/gfx/circular-resource-heap-d3d12.cpp
@@ -1,6 +1,6 @@
#include "circular-resource-heap-d3d12.h"
-namespace slang_graphics {
+namespace gfx {
using namespace Slang;
D3D12CircularResourceHeap::D3D12CircularResourceHeap():
@@ -219,4 +219,4 @@ D3D12CircularResourceHeap::Cursor D3D12CircularResourceHeap::allocate(size_t siz
return cursor;
}
-} // namespace slang_graphics
+} // namespace gfx
diff --git a/tools/slang-graphics/circular-resource-heap-d3d12.h b/tools/gfx/circular-resource-heap-d3d12.h
index a200d3bbc..cca981601 100644
--- a/tools/slang-graphics/circular-resource-heap-d3d12.h
+++ b/tools/gfx/circular-resource-heap-d3d12.h
@@ -6,7 +6,7 @@
#include "resource-d3d12.h"
-namespace slang_graphics {
+namespace gfx {
/*! \brief The D3D12CircularResourceHeap is a heap that is suited for size constrained real-time resources allocation that
is transitory in nature. It is designed to allocate resources which are used and discarded, often used where in
@@ -202,5 +202,5 @@ class D3D12CircularResourceHeap
ID3D12Device* m_device; ///< The device that resources will be constructed on
};
-} // namespace slang_graphics
+} // namespace gfx
diff --git a/tools/slang-graphics/d3d-util.cpp b/tools/gfx/d3d-util.cpp
index b2c3f87ee..19135707b 100644
--- a/tools/slang-graphics/d3d-util.cpp
+++ b/tools/gfx/d3d-util.cpp
@@ -6,7 +6,7 @@
// We will use the C standard library just for printing error messages.
#include <stdio.h>
-namespace slang_graphics {
+namespace gfx {
using namespace Slang;
/* static */D3D_PRIMITIVE_TOPOLOGY D3DUtil::getPrimitiveTopology(PrimitiveTopology topology)
diff --git a/tools/slang-graphics/d3d-util.h b/tools/gfx/d3d-util.h
index b5f154e6e..04bfae63d 100644
--- a/tools/slang-graphics/d3d-util.h
+++ b/tools/gfx/d3d-util.h
@@ -13,7 +13,7 @@
#include <D3Dcommon.h>
#include <DXGIFormat.h>
-namespace slang_graphics {
+namespace gfx {
class D3DUtil
{
diff --git a/tools/slang-graphics/descriptor-heap-d3d12.cpp b/tools/gfx/descriptor-heap-d3d12.cpp
index 23c56d46d..382fc3219 100644
--- a/tools/slang-graphics/descriptor-heap-d3d12.cpp
+++ b/tools/gfx/descriptor-heap-d3d12.cpp
@@ -1,7 +1,7 @@
#include "descriptor-heap-d3d12.h"
-namespace slang_graphics {
+namespace gfx {
using namespace Slang;
D3D12DescriptorHeap::D3D12DescriptorHeap():
@@ -43,5 +43,5 @@ Result D3D12DescriptorHeap::init(ID3D12Device* device, const D3D12_CPU_DESCRIPTO
return SLANG_OK;
}
-} // namespace slang_graphics
+} // namespace gfx
diff --git a/tools/slang-graphics/descriptor-heap-d3d12.h b/tools/gfx/descriptor-heap-d3d12.h
index 6ddb583dc..2a814583b 100644
--- a/tools/slang-graphics/descriptor-heap-d3d12.h
+++ b/tools/gfx/descriptor-heap-d3d12.h
@@ -5,8 +5,9 @@
#include <d3d12.h>
#include "../../slang-com-ptr.h"
+#include "../../source/core/list.h"
-namespace slang_graphics {
+namespace gfx {
/*! \brief A simple class to manage an underlying Dx12 Descriptor Heap. Allocations are made linearly in order. It is not possible to free
individual allocations, but all allocations can be deallocated with 'deallocateAll'. */
@@ -62,6 +63,88 @@ protected:
int m_descriptorSize; ///< The size of each descriptor
};
+/// A host-visible descriptor, used as "backing storage" for a view.
+///
+/// This type is intended to be used to represent descriptors that
+/// are allocated and freed through a `HostVisibleDescriptorAllocator`.
+struct D3D12HostVisibleDescriptor
+{
+ D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle;
+};
+
+/// An allocator for host-visible descriptors.
+///
+/// Unlike the `D3D12DescriptorHeap` type, this class allows for both
+/// allocation and freeing of descriptors, by maintaining a free list.
+/// In order to keep the implementation simple, this class only supports
+/// allocation of single descriptors and not ranges.
+///
+class D3D12HostVisibleDescriptorAllocator
+{
+ ID3D12Device* m_device;
+ int m_chunkSize;
+ D3D12_DESCRIPTOR_HEAP_TYPE m_type;
+
+ D3D12DescriptorHeap m_heap;
+ Slang::List<D3D12HostVisibleDescriptor> m_freeList;
+ Slang::List<D3D12DescriptorHeap> m_heaps;
+
+public:
+ D3D12HostVisibleDescriptorAllocator()
+ {}
+
+ Slang::Result init(ID3D12Device* device, int chunkSize, D3D12_DESCRIPTOR_HEAP_TYPE type)
+ {
+ m_device = device;
+ m_chunkSize = chunkSize;
+ m_type = type;
+
+ SLANG_RETURN_ON_FAIL(m_heap.init(m_device, m_chunkSize, m_type, D3D12_DESCRIPTOR_HEAP_FLAG_NONE));
+
+ return SLANG_OK;
+ }
+
+ Slang::Result allocate(D3D12HostVisibleDescriptor* outDescriptor)
+ {
+ // TODO: this allocator would take some work to make thread-safe
+
+ if(m_freeList.Count() > 0)
+ {
+ auto descriptor = m_freeList[0];
+ m_freeList.FastRemoveAt(0);
+
+ *outDescriptor = descriptor;
+ return SLANG_OK;
+ }
+
+ int index = m_heap.allocate();
+ if(index < 0)
+ {
+ // Allocate a new heap and try again.
+ m_heaps.Add(m_heap);
+ SLANG_RETURN_ON_FAIL(m_heap.init(m_device, m_chunkSize, m_type, D3D12_DESCRIPTOR_HEAP_FLAG_NONE));
+
+ int index = m_heap.allocate();
+ if(index < 0)
+ {
+ assert(!"descriptor allocation failed on fresh heap");
+ return SLANG_FAIL;
+ }
+ }
+
+ D3D12HostVisibleDescriptor descriptor;
+ descriptor.cpuHandle = m_heap.getCpuHandle(index);
+
+ *outDescriptor = descriptor;
+ return SLANG_OK;
+ }
+
+ void free(D3D12HostVisibleDescriptor descriptor)
+ {
+ m_freeList.Add(descriptor);
+ }
+};
+
// ---------------------------------------------------------------------------
int D3D12DescriptorHeap::allocate()
{
@@ -111,5 +194,5 @@ SLANG_FORCE_INLINE D3D12_GPU_DESCRIPTOR_HANDLE D3D12DescriptorHeap::getGpuHandle
return dst;
}
-} // namespace slang_graphics
+} // namespace gfx
diff --git a/tools/slang-graphics/slang-graphics.vcxproj b/tools/gfx/gfx.vcxproj
index ce7502326..cbafe84b1 100644
--- a/tools/slang-graphics/slang-graphics.vcxproj
+++ b/tools/gfx/gfx.vcxproj
@@ -22,7 +22,7 @@
<ProjectGuid>{222F7498-B40C-4F3F-A704-DDEB91A4484A}</ProjectGuid>
<IgnoreWarnCompileDuplicatedFilename>true</IgnoreWarnCompileDuplicatedFilename>
<Keyword>Win32Proj</Keyword>
- <RootNamespace>slang-graphics</RootNamespace>
+ <RootNamespace>gfx</RootNamespace>
<WindowsTargetPlatformVersion>10.0.14393.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
@@ -68,26 +68,26 @@
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>..\..\bin\windows-x86\debug\</OutDir>
- <IntDir>..\..\intermediate\windows-x86\debug\slang-graphics\</IntDir>
- <TargetName>slang-graphics</TargetName>
+ <IntDir>..\..\intermediate\windows-x86\debug\gfx\</IntDir>
+ <TargetName>gfx</TargetName>
<TargetExt>.lib</TargetExt>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>..\..\bin\windows-x64\debug\</OutDir>
- <IntDir>..\..\intermediate\windows-x64\debug\slang-graphics\</IntDir>
- <TargetName>slang-graphics</TargetName>
+ <IntDir>..\..\intermediate\windows-x64\debug\gfx\</IntDir>
+ <TargetName>gfx</TargetName>
<TargetExt>.lib</TargetExt>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>..\..\bin\windows-x86\release\</OutDir>
- <IntDir>..\..\intermediate\windows-x86\release\slang-graphics\</IntDir>
- <TargetName>slang-graphics</TargetName>
+ <IntDir>..\..\intermediate\windows-x86\release\gfx\</IntDir>
+ <TargetName>gfx</TargetName>
<TargetExt>.lib</TargetExt>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>..\..\bin\windows-x64\release\</OutDir>
- <IntDir>..\..\intermediate\windows-x64\release\slang-graphics\</IntDir>
- <TargetName>slang-graphics</TargetName>
+ <IntDir>..\..\intermediate\windows-x64\release\gfx\</IntDir>
+ <TargetName>gfx</TargetName>
<TargetExt>.lib</TargetExt>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
@@ -174,6 +174,7 @@
<ClInclude Include="circular-resource-heap-d3d12.h" />
<ClInclude Include="d3d-util.h" />
<ClInclude Include="descriptor-heap-d3d12.h" />
+ <ClInclude Include="model.h" />
<ClInclude Include="render-d3d11.h" />
<ClInclude Include="render-d3d12.h" />
<ClInclude Include="render-gl.h" />
@@ -181,6 +182,7 @@
<ClInclude Include="render.h" />
<ClInclude Include="resource-d3d12.h" />
<ClInclude Include="surface.h" />
+ <ClInclude Include="vector-math.h" />
<ClInclude Include="vk-api.h" />
<ClInclude Include="vk-device-queue.h" />
<ClInclude Include="vk-module.h" />
@@ -192,6 +194,7 @@
<ClCompile Include="circular-resource-heap-d3d12.cpp" />
<ClCompile Include="d3d-util.cpp" />
<ClCompile Include="descriptor-heap-d3d12.cpp" />
+ <ClCompile Include="model.cpp" />
<ClCompile Include="render-d3d11.cpp" />
<ClCompile Include="render-d3d12.cpp" />
<ClCompile Include="render-gl.cpp" />
diff --git a/tools/slang-graphics/slang-graphics.vcxproj.filters b/tools/gfx/gfx.vcxproj.filters
index b1e4c42a3..f1c7f7f5e 100644
--- a/tools/slang-graphics/slang-graphics.vcxproj.filters
+++ b/tools/gfx/gfx.vcxproj.filters
@@ -18,6 +18,9 @@
<ClInclude Include="descriptor-heap-d3d12.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="model.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="render-d3d11.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -39,6 +42,9 @@
<ClInclude Include="surface.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="vector-math.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="vk-api.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -68,6 +74,9 @@
<ClCompile Include="descriptor-heap-d3d12.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="model.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="render-d3d11.cpp">
<Filter>Source Files</Filter>
</ClCompile>
diff --git a/tools/gfx/model.cpp b/tools/gfx/model.cpp
new file mode 100644
index 000000000..c8218102e
--- /dev/null
+++ b/tools/gfx/model.cpp
@@ -0,0 +1,530 @@
+// model.cpp
+#include "model.h"
+
+#define TINYOBJLOADER_IMPLEMENTATION
+#include "../../external/tinyobjloader/tiny_obj_loader.h"
+
+#define STB_IMAGE_IMPLEMENTATION
+#include "../../external/stb/stb_image.h"
+
+#define STB_IMAGE_RESIZE_IMPLEMENTATION
+#include "../../external/stb/stb_image_resize.h"
+
+#include "../../external/glm/glm/glm.hpp"
+#include "../../external/glm/glm/gtc/matrix_transform.hpp"
+#include "../../external/glm/glm/gtc/constants.hpp"
+
+#include <memory>
+#include <unordered_map>
+#include <unordered_set>
+
+namespace gfx {
+
+// TinyObj provides a tuple type that bundles up indices, but doesn't
+// provide equality comparison or hashing for that type. We'd like
+// to have a hash function so that we can unique indices.
+//
+// In the simplest case, we could define hashing and operator== operations
+// directly on `tinobj::index_t`, but that would create problems if they
+// revise their API.
+//
+// We will instead define our own wrapper type that supports equality
+// comparisons.
+//
+struct ObjIndexKey
+{
+ tinyobj::index_t index;
+};
+
+bool operator==(ObjIndexKey const& left, ObjIndexKey const& right)
+{
+ return left.index.vertex_index == right.index.vertex_index
+ && left.index.normal_index == right.index.normal_index
+ && left.index.texcoord_index == right.index.texcoord_index;
+}
+
+struct Hasher
+{
+ template<typename T>
+ void add(T const& v)
+ {
+ state ^= std::hash<T>()(v) + 0x9e3779b9 + (state << 6) + (state >> 2);
+ }
+ size_t state = 0;
+};
+
+struct SmoothingGroupVertexID
+{
+ size_t smoothingGroup;
+ size_t positionID;
+};
+bool operator==(SmoothingGroupVertexID const& left, SmoothingGroupVertexID const& right)
+{
+ return left.smoothingGroup == right.smoothingGroup
+ && left.positionID == right.positionID;
+}
+
+}
+
+namespace std
+{
+ template<> struct hash<gfx::ObjIndexKey>
+ {
+ size_t operator()(gfx::ObjIndexKey const& key) const
+ {
+ gfx::Hasher hasher;
+ hasher.add(key.index.vertex_index);
+ hasher.add(key.index.normal_index);
+ hasher.add(key.index.texcoord_index);
+ return hasher.state;
+ }
+ };
+
+ template<> struct hash<gfx::SmoothingGroupVertexID>
+ {
+ size_t operator()(gfx::SmoothingGroupVertexID const& id) const
+ {
+ gfx::Hasher hasher;
+ hasher.add(id.smoothingGroup);
+ hasher.add(id.positionID);
+ return hasher.state;
+ }
+ };
+}
+
+namespace gfx
+{
+
+RefPtr<TextureResource> loadTextureImage(
+ Renderer* renderer,
+ char const* path)
+{
+ int extentX = 0;
+ int extentY = 0;
+ int originalChannelCount = 0;
+ int requestedChannelCount = 4; // force to 4-component result
+ stbi_uc* data = stbi_load(
+ path,
+ &extentX,
+ &extentY,
+ &originalChannelCount,
+ requestedChannelCount);
+ if(!data)
+ return nullptr;
+
+ int channelCount = requestedChannelCount ? requestedChannelCount : originalChannelCount;
+
+ Format format;
+ switch(channelCount)
+ {
+ default:
+ return nullptr;
+
+ case 4: format = Format::RGBA_Unorm_UInt8;
+
+ // TODO: handle other cases here if/when we stop forcing 4-component
+ // results when loading the image with stb_image.
+ }
+
+ std::vector<void*> subresourceInitData;
+ std::vector<ptrdiff_t> mipRowStrides;
+
+ ptrdiff_t stride = extentX * channelCount * sizeof(stbi_uc);
+
+ subresourceInitData.push_back(data);
+ mipRowStrides.push_back(stride);
+
+ // create down-sampled images for the different mip levels
+ bool generateMips = true;
+ if(generateMips)
+ {
+ int prevExtentX = extentX;
+ int prevExtentY = extentY;
+ stbi_uc* prevData = data;
+ ptrdiff_t prevStride = stride;
+
+ for(;;)
+ {
+ if(prevExtentX == 1 && prevExtentY == 1)
+ break;
+
+ int newExtentX = prevExtentX / 2;
+ int newExtentY = prevExtentY / 2;
+
+ if(!newExtentX) newExtentX = 1;
+ if(!newExtentY) newExtentY = 1;
+
+ stbi_uc* newData = (stbi_uc*) malloc(newExtentX * newExtentY * channelCount * sizeof(stbi_uc));
+ ptrdiff_t newStride = newExtentX * channelCount * sizeof(stbi_uc);
+
+ stbir_resize_uint8_srgb(
+ prevData, prevExtentX, prevExtentY, prevStride,
+ newData, newExtentX, newExtentY, newStride,
+ channelCount,
+ STBIR_ALPHA_CHANNEL_NONE,
+ STBIR_FLAG_ALPHA_PREMULTIPLIED);
+
+ subresourceInitData.push_back(newData);
+ mipRowStrides.push_back(newStride);
+
+ prevExtentX = newExtentX;
+ prevExtentY = newExtentY;
+ prevData = newData;
+ prevStride = newStride;
+ }
+ }
+
+ int mipCount = (int) mipRowStrides.size();
+
+ TextureResource::Desc desc;
+ desc.init2D(Resource::Type::Texture2D, format, extentX, extentY, mipCount);
+
+ TextureResource::Data initData;
+ initData.numSubResources = mipCount;
+ initData.numMips = mipCount;
+ initData.subResources = &subresourceInitData[0];
+ initData.mipRowStrides = &mipRowStrides[0];
+
+ auto texture = renderer->createTextureResource(
+ Resource::Usage::PixelShaderResource,
+ desc,
+ &initData);
+
+ free(data);
+
+ return texture;
+}
+
+Result ModelLoader::load(
+ char const* inputPath,
+ void** outModel)
+{
+ // TODO: need to actually allocate/load the data
+
+ tinyobj::attrib_t objVertexAttributes;
+ std::vector<tinyobj::shape_t> objShapes;
+ std::vector<tinyobj::material_t> objMaterials;
+
+ std::string diagnostics;
+ bool shouldTriangulate = true;
+ bool success = tinyobj::LoadObj(
+ &objVertexAttributes,
+ &objShapes,
+ &objMaterials,
+ &diagnostics,
+ inputPath,
+ nullptr,
+ shouldTriangulate);
+
+ if(!diagnostics.empty())
+ {
+ log("%s", diagnostics.c_str());
+ }
+ if(!success)
+ {
+ return SLANG_FAIL;
+ }
+
+ // Translate each material imported by TinyObj into a format that
+ // we can actually use for rendering.
+ //
+ std::vector<void*> materials;
+ for(auto& objMaterial : objMaterials)
+ {
+ MaterialData materialData;
+
+ materialData.diffuseColor = glm::vec3(
+ objMaterial.diffuse[0],
+ objMaterial.diffuse[1],
+ objMaterial.diffuse[2]);
+
+ // load any referenced textures here
+ if(objMaterial.diffuse_texname.length())
+ {
+ materialData.diffuseMap = loadTextureImage(
+ renderer,
+ objMaterial.diffuse_texname.c_str());
+ }
+
+ auto material = callbacks->createMaterial(materialData);
+ materials.push_back(material);
+ }
+
+ // Flip the winding order on all faces if we are asked to...
+ //
+ if(loadFlags & LoadFlag::FlipWinding)
+ {
+ for(auto& objShape : objShapes)
+ {
+ size_t objIndexCounter = 0;
+ size_t objFaceCounter = 0;
+ for(auto objFaceVertexCount : objShape.mesh.num_face_vertices)
+ {
+ size_t beginIndex = objIndexCounter;
+ size_t endIndex = beginIndex + objFaceVertexCount;
+ objIndexCounter = endIndex;
+
+ size_t halfCount = objFaceVertexCount / 2;
+ for(size_t ii = 0; ii < halfCount; ++ii)
+ {
+ std::swap(
+ objShape.mesh.indices[beginIndex + ii],
+ objShape.mesh.indices[endIndex - (ii + 1)]);
+ }
+ }
+ }
+
+ }
+
+ // Identify cases where a face has a vertex without a normal, and in that
+ // case remember that the given vertex needs to be "smoothed" as part of
+ // the smoothing group for that face. Note that it is possible for the
+ // same vertex (position) to be part of faces in distinct smoothing groups.
+ //
+ std::unordered_map<SmoothingGroupVertexID, size_t> smoothedVertexNormals;
+ size_t firstSmoothedNormalID = objVertexAttributes.normals.size() / 3;
+ size_t flatFaceCounter = 0;
+ for(auto& objShape : objShapes)
+ {
+ size_t objIndexCounter = 0;
+ size_t objFaceCounter = 0;
+ for(auto objFaceVertexCount : objShape.mesh.num_face_vertices)
+ {
+ size_t flatFaceIndex = flatFaceCounter++;
+ size_t objFaceIndex = objFaceCounter++;
+ size_t smoothingGroup = objShape.mesh.smoothing_group_ids[objFaceIndex];
+ if(!smoothingGroup)
+ {
+ smoothingGroup = ~flatFaceIndex;
+ }
+
+ for(size_t objFaceVertex = 0; objFaceVertex < objFaceVertexCount; ++objFaceVertex)
+ {
+ tinyobj::index_t& objIndex = objShape.mesh.indices[objIndexCounter++];
+
+ if(objIndex.normal_index < 0)
+ {
+ SmoothingGroupVertexID smoothVertexID;
+ smoothVertexID.positionID = objIndex.vertex_index;
+ smoothVertexID.smoothingGroup = smoothingGroup;
+
+ if(smoothedVertexNormals.find(smoothVertexID) == smoothedVertexNormals.end())
+ {
+ size_t normalID = objVertexAttributes.normals.size() / 3;
+ objVertexAttributes.normals.push_back(0);
+ objVertexAttributes.normals.push_back(0);
+ objVertexAttributes.normals.push_back(0);
+
+ smoothedVertexNormals.insert(std::make_pair(smoothVertexID, normalID));
+
+ objIndex.normal_index = normalID;
+ }
+ }
+ }
+ }
+ }
+ //
+ // Having identified which vertices we need to smooth, we will make another
+ // pass to compute face normals and apply them to the vertices that belong
+ // to the same smoothing group.
+ //
+ flatFaceCounter = 0;
+ for(auto& objShape : objShapes)
+ {
+ size_t objIndexCounter = 0;
+ size_t objFaceCounter = 0;
+ for(auto objFaceVertexCount : objShape.mesh.num_face_vertices)
+ {
+ size_t flatFaceIndex = flatFaceCounter++;
+ size_t objFaceIndex = objFaceCounter++;
+ unsigned int smoothingGroup = objShape.mesh.smoothing_group_ids[objFaceIndex];
+ if(!smoothingGroup)
+ {
+ smoothingGroup = ~flatFaceIndex;
+ }
+
+ glm::vec3 faceNormal;
+ if(objFaceVertexCount >= 3)
+ {
+ glm::vec3 v[3];
+ for(size_t objFaceVertex = 0; objFaceVertex < 3; ++objFaceVertex)
+ {
+ tinyobj::index_t objIndex = objShape.mesh.indices[objIndexCounter + objFaceVertex];
+ if(objIndex.vertex_index >= 0)
+ {
+ v[objFaceVertex] = glm::vec3(
+ objVertexAttributes.vertices[3 * objIndex.vertex_index + 0],
+ objVertexAttributes.vertices[3 * objIndex.vertex_index + 1],
+ objVertexAttributes.vertices[3 * objIndex.vertex_index + 2]);
+ }
+ }
+ faceNormal = cross(v[1] - v[0], v[2] - v[0]);
+ }
+
+ // Add this face normal to any to-be-smoothed vertex on the face.
+ for(size_t objFaceVertex = 0; objFaceVertex < objFaceVertexCount; ++objFaceVertex)
+ {
+ tinyobj::index_t objIndex = objShape.mesh.indices[objIndexCounter++];
+
+ SmoothingGroupVertexID smoothVertexID;
+ smoothVertexID.positionID = objIndex.vertex_index;
+ smoothVertexID.smoothingGroup = smoothingGroup;
+
+ auto ii = smoothedVertexNormals.find(smoothVertexID);
+ if(ii != smoothedVertexNormals.end())
+ {
+ size_t normalID = ii->second;
+ objVertexAttributes.normals[normalID * 3 + 0] += faceNormal.x;
+ objVertexAttributes.normals[normalID * 3 + 1] += faceNormal.y;
+ objVertexAttributes.normals[normalID * 3 + 2] += faceNormal.z;
+ }
+ }
+ }
+ }
+ //
+ // Once we've added all contributions from each smoothing group,
+ // we can normalize the normals to compute the area-weighted average.
+ //
+ size_t normalCount = objVertexAttributes.normals.size() / 3;
+ for(size_t ii = firstSmoothedNormalID; ii < normalCount; ++ii)
+ {
+ glm::vec3 normal = glm::vec3(
+ objVertexAttributes.normals[3 * ii + 0],
+ objVertexAttributes.normals[3 * ii + 1],
+ objVertexAttributes.normals[3 * ii + 2]);
+
+ normal = normalize(normal);
+
+ objVertexAttributes.normals[3 * ii + 0] = normal.x;
+ objVertexAttributes.normals[3 * ii + 1] = normal.y;
+ objVertexAttributes.normals[3 * ii + 2] = normal.z;
+ }
+
+ // TODO: we should sort the faces to group faces with
+ // the same material ID together, in case they weren't
+ // grouped in the original file.
+
+ // We need to undo the .obj indexing stuff so that we have
+ // standard position/normal/etc. data in a single flat array
+
+ std::unordered_map<ObjIndexKey, Index> mapObjIndexToFlatIndex;
+ std::vector<Vertex> flatVertices;
+ std::vector<Index> flatIndices;
+
+ MeshData* currentMesh = nullptr;
+ MeshData currentMeshStorage;
+
+ std::vector<void*> meshes;
+
+ for(auto& objShape : objShapes)
+ {
+ size_t objIndexCounter = 0;
+ size_t objFaceCounter = 0;
+ for(auto objFaceVertexCount : objShape.mesh.num_face_vertices)
+ {
+ size_t objFaceIndex = objFaceCounter++;
+ int faceMaterialID = objShape.mesh.material_ids[objFaceIndex];
+ void* faceMaterial = materials[faceMaterialID];
+
+ if(!currentMesh || (faceMaterial != currentMesh->material))
+ {
+ // finish old mesh.
+ if(currentMesh)
+ {
+ meshes.push_back(callbacks->createMesh(*currentMesh));
+ }
+
+ // Need to start a new mesh.
+ currentMesh = &currentMeshStorage;
+ currentMesh->material = faceMaterial;
+ currentMesh->firstIndex = (int)flatIndices.size();
+ currentMesh->indexCount = 0;
+ }
+
+ for(size_t objFaceVertex = 0; objFaceVertex < objFaceVertexCount; ++objFaceVertex)
+ {
+ tinyobj::index_t objIndex = objShape.mesh.indices[objIndexCounter++];
+ ObjIndexKey objIndexKey; objIndexKey.index = objIndex;
+
+
+ Index flatIndex = Index(-1);
+ auto iter = mapObjIndexToFlatIndex.find(objIndexKey);
+ if(iter != mapObjIndexToFlatIndex.end())
+ {
+ flatIndex = iter->second;
+ }
+ else
+ {
+ Vertex flatVertex;
+ if(objIndex.vertex_index >= 0)
+ {
+ flatVertex.position = scale * glm::vec3(
+ objVertexAttributes.vertices[3 * objIndex.vertex_index + 0],
+ objVertexAttributes.vertices[3 * objIndex.vertex_index + 1],
+ objVertexAttributes.vertices[3 * objIndex.vertex_index + 2]);
+ }
+ if(objIndex.normal_index >= 0)
+ {
+ flatVertex.normal = glm::vec3(
+ objVertexAttributes.normals[3 * objIndex.normal_index + 0],
+ objVertexAttributes.normals[3 * objIndex.normal_index + 1],
+ objVertexAttributes.normals[3 * objIndex.normal_index + 2]);
+ }
+ if(objIndex.texcoord_index >= 0)
+ {
+ flatVertex.uv = glm::vec2(
+ objVertexAttributes.texcoords[2 * objIndex.texcoord_index + 0],
+ objVertexAttributes.texcoords[2 * objIndex.texcoord_index + 1]);
+ }
+
+ flatIndex = flatVertices.size();
+ mapObjIndexToFlatIndex.insert(std::make_pair(objIndexKey, flatIndex));
+ flatVertices.push_back(flatVertex);
+ }
+
+ flatIndices.push_back(flatIndex);
+ currentMesh->indexCount++;
+ }
+ }
+ }
+
+ // finish last mesh.
+ if(currentMesh)
+ {
+ meshes.push_back(callbacks->createMesh(*currentMesh));
+ }
+
+ ModelData modelData;
+
+ modelData.vertexCount = (int)flatVertices.size();
+ modelData.indexCount = (int)flatIndices.size();
+
+ modelData.meshCount = meshes.size();
+ modelData.meshes = meshes.data();
+
+ BufferResource::Desc vertexBufferDesc;
+ vertexBufferDesc.init(modelData.vertexCount * sizeof(Vertex));
+ vertexBufferDesc.setDefaults(Resource::Usage::VertexBuffer);
+
+ modelData.vertexBuffer = renderer->createBufferResource(
+ Resource::Usage::VertexBuffer,
+ vertexBufferDesc,
+ flatVertices.data());
+ if(!modelData.vertexBuffer) return SLANG_FAIL;
+
+ BufferResource::Desc indexBufferDesc;
+ indexBufferDesc.init(modelData.indexCount * sizeof(Index));
+ vertexBufferDesc.setDefaults(Resource::Usage::IndexBuffer);
+
+ modelData.indexBuffer = renderer->createBufferResource(
+ Resource::Usage::IndexBuffer,
+ indexBufferDesc,
+ flatIndices.data());
+ if(!modelData.indexBuffer) return SLANG_FAIL;
+
+ *outModel = callbacks->createModel(modelData);
+
+ return SLANG_OK;
+}
+
+} // gfx
diff --git a/tools/gfx/model.h b/tools/gfx/model.h
new file mode 100644
index 000000000..046b9764b
--- /dev/null
+++ b/tools/gfx/model.h
@@ -0,0 +1,73 @@
+// model.h
+#pragma once
+
+#include "render.h"
+#include "vector-math.h"
+
+#include <vector>
+
+namespace gfx {
+
+struct ModelLoader
+{
+ struct MaterialData
+ {
+ glm::vec3 diffuseColor;
+ RefPtr<TextureResource> diffuseMap;
+ };
+
+ struct Vertex
+ {
+ glm::vec3 position;
+ glm::vec3 normal;
+ glm::vec2 uv;
+ };
+
+ typedef uint32_t Index;
+
+ struct MeshData
+ {
+ int firstIndex;
+ int indexCount;
+
+ void* material;
+ };
+
+ struct ModelData
+ {
+ RefPtr<BufferResource> vertexBuffer;
+ RefPtr<BufferResource> indexBuffer;
+ PrimitiveTopology primitiveTopology;
+ int vertexCount;
+ int indexCount;
+ int meshCount;
+ void* const* meshes;
+ };
+
+ struct ICallbacks
+ {
+ typedef ModelLoader::MaterialData MaterialData;
+ typedef ModelLoader::MeshData MeshData;
+ typedef ModelLoader::ModelData ModelData;
+
+ virtual void* createMaterial(MaterialData const& data) = 0;
+ virtual void* createMesh(MeshData const& data) = 0;
+ virtual void* createModel(ModelData const& data) = 0;
+ };
+
+ typedef uint32_t LoadFlags;
+ enum LoadFlag : LoadFlags
+ {
+ FlipWinding = 1 << 0,
+ };
+
+ ICallbacks* callbacks = nullptr;
+ RefPtr<Renderer> renderer;
+ LoadFlags loadFlags = 0;
+ float scale = 1.0f;
+
+ Result load(char const* inputPath, void** outModel);
+};
+
+
+} // gfx
diff --git a/tools/gfx/render-d3d11.cpp b/tools/gfx/render-d3d11.cpp
new file mode 100644
index 000000000..57c0672bd
--- /dev/null
+++ b/tools/gfx/render-d3d11.cpp
@@ -0,0 +1,2112 @@
+// render-d3d11.cpp
+
+#define _CRT_SECURE_NO_WARNINGS
+
+#include "render-d3d11.h"
+
+//WORKING: #include "options.h"
+#include "render.h"
+#include "d3d-util.h"
+
+#include "surface.h"
+
+// In order to use the Slang API, we need to include its header
+
+//#include <slang.h>
+
+#include "../../slang-com-ptr.h"
+
+// We will be rendering with Direct3D 11, so we need to include
+// the Windows and D3D11 headers
+
+#define WIN32_LEAN_AND_MEAN
+#define NOMINMAX
+#include <Windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#undef NOMINMAX
+
+#include <d3d11_2.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;
+
+namespace gfx {
+
+class D3D11Renderer : public Renderer
+{
+public:
+ enum
+ {
+ kMaxUAVs = 64,
+ kMaxRTVs = 8,
+ };
+
+ // Renderer implementation
+ virtual SlangResult initialize(const Desc& desc, void* inWindowHandle) override;
+ virtual void setClearColor(const float color[4]) override;
+ virtual void clearFrame() override;
+ virtual void presentFrame() override;
+ TextureResource::Desc getSwapChainTextureDesc() override;
+
+ Result createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData, TextureResource** outResource) override;
+ Result createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& desc, const void* initData, BufferResource** outResource) override;
+ Result createSamplerState(SamplerState::Desc const& desc, SamplerState** outSampler) override;
+
+ Result createTextureView(TextureResource* texture, ResourceView::Desc const& desc, ResourceView** outView) override;
+ Result createBufferView(BufferResource* buffer, ResourceView::Desc const& desc, ResourceView** outView) override;
+
+ Result createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount, InputLayout** outLayout) override;
+
+ Result createDescriptorSetLayout(const DescriptorSetLayout::Desc& desc, DescriptorSetLayout** outLayout) override;
+ Result createPipelineLayout(const PipelineLayout::Desc& desc, PipelineLayout** outLayout) override;
+ Result createDescriptorSet(DescriptorSetLayout* layout, DescriptorSet** outDescriptorSet) override;
+
+ Result createProgram(const ShaderProgram::Desc& desc, ShaderProgram** outProgram) override;
+ Result createGraphicsPipelineState(const GraphicsPipelineStateDesc& desc, PipelineState** outState) override;
+ Result createComputePipelineState(const ComputePipelineStateDesc& desc, PipelineState** outState) override;
+
+ virtual SlangResult captureScreenSurface(Surface& surfaceOut) override;
+
+ virtual void* map(BufferResource* buffer, MapFlavor flavor) override;
+ virtual void unmap(BufferResource* buffer) override;
+ virtual void setPrimitiveTopology(PrimitiveTopology topology) override;
+
+ virtual void setDescriptorSet(PipelineType pipelineType, PipelineLayout* layout, UInt index, DescriptorSet* descriptorSet) override;
+
+ virtual void setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) override;
+ virtual void setIndexBuffer(BufferResource* buffer, Format indexFormat, UInt offset) override;
+ virtual void setDepthStencilTarget(ResourceView* depthStencilView) override;
+ virtual void setPipelineState(PipelineType pipelineType, PipelineState* state) override;
+ virtual void draw(UInt vertexCount, UInt startVertex) override;
+ virtual void drawIndexed(UInt indexCount, UInt startIndex, UInt baseVertex) override;
+ virtual void dispatchCompute(int x, int y, int z) override;
+ virtual void submitGpuWork() override {}
+ virtual void waitForGpu() override {}
+ virtual RendererType getRendererType() const override { return RendererType::DirectX11; }
+
+ protected:
+
+#if 0
+ struct BindingDetail
+ {
+ ComPtr<ID3D11ShaderResourceView> m_srv;
+ ComPtr<ID3D11UnorderedAccessView> m_uav;
+ ComPtr<ID3D11SamplerState> m_samplerState;
+ };
+
+ class BindingStateImpl: public BindingState
+ {
+ public:
+ typedef BindingState Parent;
+
+ /// Ctor
+ BindingStateImpl(const Desc& desc):
+ Parent(desc)
+ {}
+
+ List<BindingDetail> m_bindingDetails;
+ };
+#endif
+
+ enum class D3D11DescriptorSlotType
+ {
+ ConstantBuffer,
+ ShaderResourceView,
+ UnorderedAccessView,
+ Sampler,
+
+ CombinedTextureSampler,
+
+ CountOf,
+ };
+
+ class DescriptorSetLayoutImpl : public DescriptorSetLayout
+ {
+ public:
+ struct RangeInfo
+ {
+ D3D11DescriptorSlotType type;
+ UInt arrayIndex;
+ UInt pairedSamplerArrayIndex;
+ };
+ List<RangeInfo> m_ranges;
+
+ UInt m_counts[int(D3D11DescriptorSlotType::CountOf)];
+ };
+
+ class PipelineLayoutImpl : public PipelineLayout
+ {
+ public:
+ struct DescriptorSetInfo
+ {
+ RefPtr<DescriptorSetLayoutImpl> layout;
+ UInt baseIndices[int(D3D11DescriptorSlotType::CountOf)];
+ };
+
+ List<DescriptorSetInfo> m_descriptorSets;
+ UINT m_uavCount;
+ };
+
+ class DescriptorSetImpl : public DescriptorSet
+ {
+ public:
+ virtual void setConstantBuffer(UInt range, UInt index, BufferResource* buffer) override;
+ virtual void setResource(UInt range, UInt index, ResourceView* view) override;
+ virtual void setSampler(UInt range, UInt index, SamplerState* sampler) override;
+ virtual void setCombinedTextureSampler(
+ UInt range,
+ UInt index,
+ ResourceView* textureView,
+ SamplerState* sampler) override;
+
+ RefPtr<DescriptorSetLayoutImpl> m_layout;
+
+ List<ComPtr<ID3D11Buffer>> m_cbs;
+ List<ComPtr<ID3D11ShaderResourceView>> m_srvs;
+ List<ComPtr<ID3D11UnorderedAccessView>> m_uavs;
+ List<ComPtr<ID3D11SamplerState>> m_samplers;
+ };
+
+ class ShaderProgramImpl: public ShaderProgram
+ {
+ public:
+ ComPtr<ID3D11VertexShader> m_vertexShader;
+ ComPtr<ID3D11PixelShader> m_pixelShader;
+ ComPtr<ID3D11ComputeShader> m_computeShader;
+ };
+
+ class BufferResourceImpl: public BufferResource
+ {
+ public:
+ typedef BufferResource Parent;
+
+ BufferResourceImpl(const Desc& desc, Usage initialUsage):
+ Parent(desc),
+ m_initialUsage(initialUsage)
+ {
+ }
+
+ MapFlavor m_mapFlavor;
+ Usage m_initialUsage;
+ ComPtr<ID3D11Buffer> m_buffer;
+ ComPtr<ID3D11Buffer> m_staging;
+ };
+ class TextureResourceImpl : public TextureResource
+ {
+ public:
+ typedef TextureResource Parent;
+
+ TextureResourceImpl(const Desc& desc, Usage initialUsage) :
+ Parent(desc),
+ m_initialUsage(initialUsage)
+ {
+ }
+ Usage m_initialUsage;
+ ComPtr<ID3D11Resource> m_resource;
+
+ };
+
+ class SamplerStateImpl : public SamplerState
+ {
+ public:
+ ComPtr<ID3D11SamplerState> m_sampler;
+ };
+
+
+ class ResourceViewImpl : public ResourceView
+ {
+ public:
+ enum class Type
+ {
+ SRV,
+ UAV,
+ DSV,
+ RTV,
+ };
+ Type m_type;
+ };
+
+ class ShaderResourceViewImpl : public ResourceViewImpl
+ {
+ public:
+ ComPtr<ID3D11ShaderResourceView> m_srv;
+ };
+
+ class UnorderedAccessViewImpl : public ResourceViewImpl
+ {
+ public:
+ ComPtr<ID3D11UnorderedAccessView> m_uav;
+ };
+
+ class DepthStencilViewImpl : public ResourceViewImpl
+ {
+ public:
+ ComPtr<ID3D11DepthStencilView> m_dsv;
+ };
+
+ class RenderTargetViewImpl : public ResourceViewImpl
+ {
+ public:
+ ComPtr<ID3D11RenderTargetView> m_rtv;
+ };
+
+ class InputLayoutImpl: public InputLayout
+ {
+ public:
+ ComPtr<ID3D11InputLayout> m_layout;
+ };
+
+ class PipelineStateImpl : public PipelineState
+ {
+ public:
+ RefPtr<ShaderProgramImpl> m_program;
+ RefPtr<PipelineLayoutImpl> m_pipelineLayout;
+ };
+
+
+ class GraphicsPipelineStateImpl : public PipelineStateImpl
+ {
+ public:
+ UINT m_rtvCount;
+
+ RefPtr<InputLayoutImpl> m_inputLayout;
+ ComPtr<ID3D11DepthStencilState> m_depthStencilState;
+ ComPtr<ID3D11RasterizerState> m_rasterizerState;
+
+ UINT m_stencilRef;
+ };
+
+ class ComputePipelineStateImpl : public PipelineStateImpl
+ {
+ public:
+ };
+
+ /// Capture a texture to a file
+ static HRESULT captureTextureToSurface(ID3D11Device* device, ID3D11DeviceContext* context, ID3D11Texture2D* texture, Surface& surfaceOut);
+
+ void _flushGraphicsState();
+ void _flushComputeState();
+
+ ComPtr<IDXGISwapChain> m_swapChain;
+ ComPtr<ID3D11Device> m_device;
+ ComPtr<ID3D11DeviceContext> m_immediateContext;
+ ComPtr<ID3D11Texture2D> m_backBufferTexture;
+
+ RefPtr<TextureResourceImpl> m_primaryRenderTargetTexture;
+ RefPtr<RenderTargetViewImpl> m_primaryRenderTargetView;
+
+// List<ComPtr<ID3D11RenderTargetView> > m_renderTargetViews;
+// List<ComPtr<ID3D11Texture2D> > m_renderTargetTextures;
+
+ bool m_renderTargetBindingsDirty = false;
+
+ RefPtr<GraphicsPipelineStateImpl> m_currentGraphicsState;
+ RefPtr<ComputePipelineStateImpl> m_currentComputeState;
+
+ ComPtr<ID3D11RenderTargetView> m_rtvBindings[kMaxRTVs];
+ ComPtr<ID3D11DepthStencilView> m_dsvBinding;
+ ComPtr<ID3D11UnorderedAccessView> m_uavBindings[int(PipelineType::CountOf)][kMaxUAVs];
+ bool m_targetBindingsDirty[int(PipelineType::CountOf)];
+
+ Desc m_desc;
+
+ float m_clearColor[4] = { 0, 0, 0, 0 };
+};
+
+Renderer* createD3D11Renderer()
+{
+ return new D3D11Renderer();
+}
+
+/* static */HRESULT D3D11Renderer::captureTextureToSurface(ID3D11Device* device, ID3D11DeviceContext* context, ID3D11Texture2D* texture, Surface& surfaceOut)
+{
+ if (!context) return E_INVALIDARG;
+ if (!texture) return E_INVALIDARG;
+
+ D3D11_TEXTURE2D_DESC textureDesc;
+ texture->GetDesc(&textureDesc);
+
+ // Don't bother supporting MSAA for right now
+ if (textureDesc.SampleDesc.Count > 1)
+ {
+ fprintf(stderr, "ERROR: cannot capture multi-sample texture\n");
+ return E_INVALIDARG;
+ }
+
+ HRESULT hr = S_OK;
+ ComPtr<ID3D11Texture2D> stagingTexture;
+
+ if (textureDesc.Usage == D3D11_USAGE_STAGING && (textureDesc.CPUAccessFlags & D3D11_CPU_ACCESS_READ))
+ {
+ stagingTexture = texture;
+ }
+ else
+ {
+ // Modify the descriptor to give us a staging texture
+ textureDesc.BindFlags = 0;
+ textureDesc.MiscFlags &= ~D3D11_RESOURCE_MISC_TEXTURECUBE;
+ textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
+ textureDesc.Usage = D3D11_USAGE_STAGING;
+
+ hr = device->CreateTexture2D(&textureDesc, 0, stagingTexture.writeRef());
+ if (FAILED(hr))
+ {
+ fprintf(stderr, "ERROR: failed to create staging texture\n");
+ return hr;
+ }
+
+ context->CopyResource(stagingTexture, texture);
+ }
+
+ // Now just read back texels from the staging textures
+ {
+ D3D11_MAPPED_SUBRESOURCE mappedResource;
+ SLANG_RETURN_ON_FAIL(context->Map(stagingTexture, 0, D3D11_MAP_READ, 0, &mappedResource));
+
+ Result res = surfaceOut.set(textureDesc.Width, textureDesc.Height, Format::RGBA_Unorm_UInt8, mappedResource.RowPitch, mappedResource.pData, SurfaceAllocator::getMallocAllocator());
+
+ // Make sure to unmap
+ context->Unmap(stagingTexture, 0);
+ return res;
+ }
+}
+
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!! Renderer interface !!!!!!!!!!!!!!!!!!!!!!!!!!
+
+SlangResult D3D11Renderer::initialize(const Desc& desc, void* inWindowHandle)
+{
+ auto windowHandle = (HWND)inWindowHandle;
+ m_desc = desc;
+
+ // Rather than statically link against D3D, we load it dynamically.
+ HMODULE d3dModule = LoadLibraryA("d3d11.dll");
+ if (!d3dModule)
+ {
+ fprintf(stderr, "error: failed load 'd3d11.dll'\n");
+ return SLANG_FAIL;
+ }
+
+ PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN D3D11CreateDeviceAndSwapChain_ =
+ (PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN)GetProcAddress(d3dModule, "D3D11CreateDeviceAndSwapChain");
+ if (!D3D11CreateDeviceAndSwapChain_)
+ {
+ fprintf(stderr,
+ "error: failed load symbol 'D3D11CreateDeviceAndSwapChain'\n");
+ return SLANG_FAIL;
+ }
+
+ UINT deviceFlags = 0;
+
+#ifdef _DEBUG
+ // We will enable the D3D debug more for debug builds.
+ //
+ // TODO: we should probably provide a command-line option
+ // to override this kind of default rather than leave it
+ // up to each back-end to specify.
+ deviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
+#endif
+
+ // Our swap chain uses RGBA8 with sRGB, with double buffering.
+ DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 };
+ swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+
+ // Note(tfoley): Disabling sRGB for DX back buffer for now, so that we
+ // can get consistent output with OpenGL, where setting up sRGB will
+ // probably be more involved.
+ // swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
+ swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+
+ swapChainDesc.SampleDesc.Count = 1;
+ swapChainDesc.SampleDesc.Quality = 0;
+ swapChainDesc.BufferCount = 2;
+ swapChainDesc.OutputWindow = windowHandle;
+ swapChainDesc.Windowed = TRUE;
+ swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
+ swapChainDesc.Flags = 0;
+
+ // We will ask for the highest feature level that can be supported.
+ const D3D_FEATURE_LEVEL featureLevels[] = {
+ D3D_FEATURE_LEVEL_11_1,
+ D3D_FEATURE_LEVEL_11_0,
+ D3D_FEATURE_LEVEL_10_1,
+ D3D_FEATURE_LEVEL_10_0,
+ D3D_FEATURE_LEVEL_9_3,
+ D3D_FEATURE_LEVEL_9_2,
+ D3D_FEATURE_LEVEL_9_1,
+ };
+ D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_9_1;
+ const int totalNumFeatureLevels = SLANG_COUNT_OF(featureLevels);
+
+ // On a machine that does not have an up-to-date version of D3D installed,
+ // the `D3D11CreateDeviceAndSwapChain` call will fail with `E_INVALIDARG`
+ // if you ask for featuer level 11_1. The workaround is to call
+ // `D3D11CreateDeviceAndSwapChain` up to twice: the first time with 11_1
+ // at the start of the list of requested feature levels, and the second
+ // time without it.
+
+ for (int ii = 0; ii < 2; ++ii)
+ {
+ const HRESULT hr = D3D11CreateDeviceAndSwapChain_(
+ nullptr, // adapter (use default)
+ D3D_DRIVER_TYPE_REFERENCE,
+// D3D_DRIVER_TYPE_HARDWARE,
+ nullptr, // software
+ deviceFlags,
+ &featureLevels[ii],
+ totalNumFeatureLevels - ii,
+ D3D11_SDK_VERSION,
+ &swapChainDesc,
+ m_swapChain.writeRef(),
+ m_device.writeRef(),
+ &featureLevel,
+ m_immediateContext.writeRef());
+
+ // Failures with `E_INVALIDARG` might be due to feature level 11_1
+ // not being supported.
+ if (hr == E_INVALIDARG)
+ {
+ continue;
+ }
+
+ // Other failures are real, though.
+ SLANG_RETURN_ON_FAIL(hr);
+ // We must have a swap chain
+ break;
+ }
+
+ // TODO: Add support for debugging to help detect leaks:
+ //
+ // ComPtr<ID3D11Debug> gDebug;
+ // m_device->QueryInterface(IID_PPV_ARGS(gDebug.writeRef()));
+ //
+
+ // After we've created the swap chain, we can request a pointer to the
+ // back buffer as a D3D11 texture, and create a render-target view from it.
+
+ static const IID kIID_ID3D11Texture2D = {
+ 0x6f15aaf2, 0xd208, 0x4e89, 0x9a, 0xb4, 0x48,
+ 0x95, 0x35, 0xd3, 0x4f, 0x9c };
+
+ SLANG_RETURN_ON_FAIL(m_swapChain->GetBuffer(0, kIID_ID3D11Texture2D, (void**)m_backBufferTexture.writeRef()));
+
+// for (int i = 0; i < 8; i++)
+ {
+ ComPtr<ID3D11Texture2D> texture;
+ D3D11_TEXTURE2D_DESC textureDesc;
+ m_backBufferTexture->GetDesc(&textureDesc);
+ SLANG_RETURN_ON_FAIL(m_device->CreateTexture2D(&textureDesc, nullptr, texture.writeRef()));
+
+ ComPtr<ID3D11RenderTargetView> rtv;
+ D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
+ rtvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ rtvDesc.Texture2D.MipSlice = 0;
+ rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
+ SLANG_RETURN_ON_FAIL(m_device->CreateRenderTargetView(texture, &rtvDesc, rtv.writeRef()));
+
+ TextureResource::Desc resourceDesc;
+ resourceDesc.init2D(Resource::Type::Texture2D, Format::RGBA_Unorm_UInt8, textureDesc.Width, textureDesc.Height, 1);
+
+ RefPtr<TextureResource> primaryRenderTargetTexture;
+ SLANG_RETURN_ON_FAIL(createTextureResource(Resource::Usage::RenderTarget, resourceDesc, nullptr, primaryRenderTargetTexture.writeRef()));
+
+ ResourceView::Desc viewDesc;
+ viewDesc.format = resourceDesc.format;
+ viewDesc.type = ResourceView::Type::RenderTarget;
+ RefPtr<ResourceView> primaryRenderTargetView;
+ SLANG_RETURN_ON_FAIL(createTextureView(primaryRenderTargetTexture, viewDesc, primaryRenderTargetView.writeRef()));
+
+ m_primaryRenderTargetTexture = (TextureResourceImpl*) primaryRenderTargetTexture.Ptr();
+ m_primaryRenderTargetView = (RenderTargetViewImpl*) primaryRenderTargetView.Ptr();
+ }
+
+// m_immediateContext->OMSetRenderTargets(1, m_primaryRenderTargetView->m_rtv.readRef(), nullptr);
+ m_rtvBindings[0] = m_primaryRenderTargetView->m_rtv;
+ m_targetBindingsDirty[int(PipelineType::Graphics)] = true;
+
+ // Similarly, we are going to set up a viewport once, and then never
+ // switch, since this is a simple test app.
+ D3D11_VIEWPORT viewport;
+ viewport.TopLeftX = 0;
+ viewport.TopLeftY = 0;
+ viewport.Width = (float)desc.width;
+ viewport.Height = (float)desc.height;
+ viewport.MaxDepth = 1; // TODO(tfoley): use reversed depth
+ viewport.MinDepth = 0;
+ m_immediateContext->RSSetViewports(1, &viewport);
+
+ return SLANG_OK;
+}
+
+void D3D11Renderer::setClearColor(const float color[4])
+{
+ memcpy(m_clearColor, color, sizeof(m_clearColor));
+}
+
+void D3D11Renderer::clearFrame()
+{
+ m_immediateContext->ClearRenderTargetView(m_primaryRenderTargetView->m_rtv, m_clearColor);
+
+ if(m_dsvBinding)
+ {
+ m_immediateContext->ClearDepthStencilView(m_dsvBinding, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
+ }
+}
+
+void D3D11Renderer::presentFrame()
+{
+ m_immediateContext->CopyResource(m_backBufferTexture, m_primaryRenderTargetTexture->m_resource);
+ m_swapChain->Present(0, 0);
+}
+
+TextureResource::Desc D3D11Renderer::getSwapChainTextureDesc()
+{
+ D3D11_TEXTURE2D_DESC dxDesc;
+ ((ID3D11Texture2D*)m_primaryRenderTargetTexture->m_resource.get())->GetDesc(&dxDesc);
+
+ TextureResource::Desc desc;
+ desc.init2D(Resource::Type::Texture2D, Format::Unknown, dxDesc.Width, dxDesc.Height, 1);
+
+ return desc;
+}
+
+SlangResult D3D11Renderer::captureScreenSurface(Surface& surfaceOut)
+{
+ return captureTextureToSurface(m_device, m_immediateContext, (ID3D11Texture2D*) m_primaryRenderTargetTexture->m_resource.get(), surfaceOut);
+}
+
+static D3D11_BIND_FLAG _calcResourceFlag(Resource::BindFlag::Enum bindFlag)
+{
+ typedef Resource::BindFlag BindFlag;
+ switch (bindFlag)
+ {
+ case BindFlag::VertexBuffer: return D3D11_BIND_VERTEX_BUFFER;
+ case BindFlag::IndexBuffer: return D3D11_BIND_INDEX_BUFFER;
+ case BindFlag::ConstantBuffer: return D3D11_BIND_CONSTANT_BUFFER;
+ case BindFlag::StreamOutput: return D3D11_BIND_STREAM_OUTPUT;
+ case BindFlag::RenderTarget: return D3D11_BIND_RENDER_TARGET;
+ case BindFlag::DepthStencil: return D3D11_BIND_DEPTH_STENCIL;
+ case BindFlag::UnorderedAccess: return D3D11_BIND_UNORDERED_ACCESS;
+ case BindFlag::PixelShaderResource: return D3D11_BIND_SHADER_RESOURCE;
+ case BindFlag::NonPixelShaderResource: return D3D11_BIND_SHADER_RESOURCE;
+ default: return D3D11_BIND_FLAG(0);
+ }
+}
+
+static int _calcResourceBindFlags(int bindFlags)
+{
+ int dstFlags = 0;
+ while (bindFlags)
+ {
+ int lsb = bindFlags & -bindFlags;
+
+ dstFlags |= _calcResourceFlag(Resource::BindFlag::Enum(lsb));
+ bindFlags &= ~lsb;
+ }
+ return dstFlags;
+}
+
+static int _calcResourceAccessFlags(int accessFlags)
+{
+ switch (accessFlags)
+ {
+ case 0: return 0;
+ case Resource::AccessFlag::Read: return D3D11_CPU_ACCESS_READ;
+ case Resource::AccessFlag::Write: return D3D11_CPU_ACCESS_WRITE;
+ case Resource::AccessFlag::Read |
+ Resource::AccessFlag::Write: return D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
+ default: assert(!"Invalid flags"); return 0;
+ }
+}
+
+Result D3D11Renderer::createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& descIn, const TextureResource::Data* initData, TextureResource** outResource)
+{
+ TextureResource::Desc srcDesc(descIn);
+ srcDesc.setDefaults(initialUsage);
+
+ const int effectiveArraySize = srcDesc.calcEffectiveArraySize();
+
+ if(initData)
+ {
+ assert(initData->numSubResources == srcDesc.numMipLevels * effectiveArraySize * srcDesc.size.depth);
+ }
+
+ const DXGI_FORMAT format = D3DUtil::getMapFormat(srcDesc.format);
+ if (format == DXGI_FORMAT_UNKNOWN)
+ {
+ return SLANG_FAIL;
+ }
+
+ const int bindFlags = _calcResourceBindFlags(srcDesc.bindFlags);
+
+ // Set up the initialize data
+ List<D3D11_SUBRESOURCE_DATA> subRes;
+ D3D11_SUBRESOURCE_DATA* subResourcesPtr = nullptr;
+ if(initData)
+ {
+ subRes.SetSize(srcDesc.numMipLevels * effectiveArraySize);
+ {
+ int subResourceIndex = 0;
+ for (int i = 0; i < effectiveArraySize; i++)
+ {
+ for (int j = 0; j < srcDesc.numMipLevels; j++)
+ {
+ const int mipHeight = TextureResource::calcMipSize(srcDesc.size.height, j);
+
+ D3D11_SUBRESOURCE_DATA& data = subRes[subResourceIndex];
+
+ data.pSysMem = initData->subResources[subResourceIndex];
+
+ data.SysMemPitch = UINT(initData->mipRowStrides[j]);
+ data.SysMemSlicePitch = UINT(initData->mipRowStrides[j] * mipHeight);
+
+ subResourceIndex++;
+ }
+ }
+ }
+ subResourcesPtr = subRes.Buffer();
+ }
+
+ const int accessFlags = _calcResourceAccessFlags(srcDesc.cpuAccessFlags);
+
+ RefPtr<TextureResourceImpl> texture(new TextureResourceImpl(srcDesc, initialUsage));
+
+ switch (srcDesc.type)
+ {
+ case Resource::Type::Texture1D:
+ {
+ D3D11_TEXTURE1D_DESC desc = { 0 };
+ desc.BindFlags = bindFlags;
+ desc.CPUAccessFlags = accessFlags;
+ desc.Format = format;
+ desc.MiscFlags = 0;
+ desc.MipLevels = srcDesc.numMipLevels;
+ desc.ArraySize = effectiveArraySize;
+ desc.Width = srcDesc.size.width;
+ desc.Usage = D3D11_USAGE_DEFAULT;
+
+ ComPtr<ID3D11Texture1D> texture1D;
+ SLANG_RETURN_ON_FAIL(m_device->CreateTexture1D(&desc, subResourcesPtr, texture1D.writeRef()));
+
+ texture->m_resource = texture1D;
+ break;
+ }
+ case Resource::Type::TextureCube:
+ case Resource::Type::Texture2D:
+ {
+ D3D11_TEXTURE2D_DESC desc = { 0 };
+ desc.BindFlags = bindFlags;
+ desc.CPUAccessFlags = accessFlags;
+ desc.Format = format;
+ desc.MiscFlags = 0;
+ desc.MipLevels = srcDesc.numMipLevels;
+ desc.ArraySize = effectiveArraySize;
+
+ desc.Width = srcDesc.size.width;
+ desc.Height = srcDesc.size.height;
+ desc.Usage = D3D11_USAGE_DEFAULT;
+ desc.SampleDesc.Count = srcDesc.sampleDesc.numSamples;
+ desc.SampleDesc.Quality = srcDesc.sampleDesc.quality;
+
+ if (srcDesc.type == Resource::Type::TextureCube)
+ {
+ desc.MiscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE;
+ }
+
+ ComPtr<ID3D11Texture2D> texture2D;
+ SLANG_RETURN_ON_FAIL(m_device->CreateTexture2D(&desc, subResourcesPtr, texture2D.writeRef()));
+
+ texture->m_resource = texture2D;
+ break;
+ }
+ case Resource::Type::Texture3D:
+ {
+ D3D11_TEXTURE3D_DESC desc = { 0 };
+ desc.BindFlags = bindFlags;
+ desc.CPUAccessFlags = accessFlags;
+ desc.Format = format;
+ desc.MiscFlags = 0;
+ desc.MipLevels = srcDesc.numMipLevels;
+ desc.Width = srcDesc.size.width;
+ desc.Height = srcDesc.size.height;
+ desc.Depth = srcDesc.size.depth;
+ desc.Usage = D3D11_USAGE_DEFAULT;
+
+ ComPtr<ID3D11Texture3D> texture3D;
+ SLANG_RETURN_ON_FAIL(m_device->CreateTexture3D(&desc, subResourcesPtr, texture3D.writeRef()));
+
+ texture->m_resource = texture3D;
+ break;
+ }
+ default:
+ return SLANG_FAIL;
+ }
+
+ *outResource = texture.detach();
+ return SLANG_OK;
+}
+
+Result D3D11Renderer::createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& descIn, const void* initData, BufferResource** outResource)
+{
+ BufferResource::Desc srcDesc(descIn);
+ srcDesc.setDefaults(initialUsage);
+
+ // Make aligned to 256 bytes... not sure why, but if you remove this the tests do fail.
+ const size_t alignedSizeInBytes = D3DUtil::calcAligned(srcDesc.sizeInBytes, 256);
+
+ // Hack to make the initialization never read from out of bounds memory, by copying into a buffer
+ List<uint8_t> initDataBuffer;
+ if (initData && alignedSizeInBytes > srcDesc.sizeInBytes)
+ {
+ initDataBuffer.SetSize(alignedSizeInBytes);
+ ::memcpy(initDataBuffer.Buffer(), initData, srcDesc.sizeInBytes);
+ initData = initDataBuffer.Buffer();
+ }
+
+ D3D11_BUFFER_DESC bufferDesc = { 0 };
+ bufferDesc.ByteWidth = UINT(alignedSizeInBytes);
+ bufferDesc.BindFlags = _calcResourceBindFlags(srcDesc.bindFlags);
+ // For read we'll need to do some staging
+ bufferDesc.CPUAccessFlags = _calcResourceAccessFlags(descIn.cpuAccessFlags & Resource::AccessFlag::Write);
+ bufferDesc.Usage = D3D11_USAGE_DEFAULT;
+
+ // If written by CPU, make it dynamic
+ if (descIn.cpuAccessFlags & Resource::AccessFlag::Write)
+ {
+ bufferDesc.Usage = D3D11_USAGE_DYNAMIC;
+ }
+
+ switch (initialUsage)
+ {
+ case Resource::Usage::ConstantBuffer:
+ {
+ // We'll just assume ConstantBuffers are dynamic for now
+ bufferDesc.Usage = D3D11_USAGE_DYNAMIC;
+ break;
+ }
+ default: break;
+ }
+
+ if (bufferDesc.BindFlags & (D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE))
+ {
+ //desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;
+ if (srcDesc.elementSize != 0)
+ {
+ bufferDesc.StructureByteStride = srcDesc.elementSize;
+ bufferDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
+ }
+ else
+ {
+ bufferDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
+ }
+ }
+
+ D3D11_SUBRESOURCE_DATA subResourceData = { 0 };
+ subResourceData.pSysMem = initData;
+
+ RefPtr<BufferResourceImpl> buffer(new BufferResourceImpl(srcDesc, initialUsage));
+
+ SLANG_RETURN_ON_FAIL(m_device->CreateBuffer(&bufferDesc, initData ? &subResourceData : nullptr, buffer->m_buffer.writeRef()));
+
+ if (srcDesc.cpuAccessFlags & Resource::AccessFlag::Read)
+ {
+ D3D11_BUFFER_DESC bufDesc = {};
+ bufDesc.BindFlags = 0;
+ bufDesc.ByteWidth = (UINT)alignedSizeInBytes;
+ bufDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
+ bufDesc.Usage = D3D11_USAGE_STAGING;
+
+ SLANG_RETURN_ON_FAIL(m_device->CreateBuffer(&bufDesc, nullptr, buffer->m_staging.writeRef()));
+ }
+
+ *outResource = buffer.detach();
+ return SLANG_OK;
+}
+
+D3D11_FILTER_TYPE translateFilterMode(TextureFilteringMode mode)
+{
+ switch (mode)
+ {
+ default:
+ return D3D11_FILTER_TYPE(0);
+
+#define CASE(SRC, DST) \
+ case TextureFilteringMode::SRC: return D3D11_FILTER_TYPE_##DST
+
+ CASE(Point, POINT);
+ CASE(Linear, LINEAR);
+
+#undef CASE
+ }
+}
+
+D3D11_FILTER_REDUCTION_TYPE translateFilterReduction(TextureReductionOp op)
+{
+ switch (op)
+ {
+ default:
+ return D3D11_FILTER_REDUCTION_TYPE(0);
+
+#define CASE(SRC, DST) \
+ case TextureReductionOp::SRC: return D3D11_FILTER_REDUCTION_TYPE_##DST
+
+ CASE(Average, STANDARD);
+ CASE(Comparison, COMPARISON);
+ CASE(Minimum, MINIMUM);
+ CASE(Maximum, MAXIMUM);
+
+#undef CASE
+ }
+}
+
+D3D11_TEXTURE_ADDRESS_MODE translateAddressingMode(TextureAddressingMode mode)
+{
+ switch (mode)
+ {
+ default:
+ return D3D11_TEXTURE_ADDRESS_MODE(0);
+
+#define CASE(SRC, DST) \
+ case TextureAddressingMode::SRC: return D3D11_TEXTURE_ADDRESS_##DST
+
+ CASE(Wrap, WRAP);
+ CASE(ClampToEdge, CLAMP);
+ CASE(ClampToBorder, BORDER);
+ CASE(MirrorRepeat, MIRROR);
+ CASE(MirrorOnce, MIRROR_ONCE);
+
+#undef CASE
+ }
+}
+
+static D3D11_COMPARISON_FUNC translateComparisonFunc(ComparisonFunc func)
+{
+ switch (func)
+ {
+ default:
+ // TODO: need to report failures
+ return D3D11_COMPARISON_ALWAYS;
+
+#define CASE(FROM, TO) \
+ case ComparisonFunc::FROM: return D3D11_COMPARISON_##TO
+
+ CASE(Never, NEVER);
+ CASE(Less, LESS);
+ CASE(Equal, EQUAL);
+ CASE(LessEqual, LESS_EQUAL);
+ CASE(Greater, GREATER);
+ CASE(NotEqual, NOT_EQUAL);
+ CASE(GreaterEqual, GREATER_EQUAL);
+ CASE(Always, ALWAYS);
+#undef CASE
+ }
+}
+
+Result D3D11Renderer::createSamplerState(SamplerState::Desc const& desc, SamplerState** outSampler)
+{
+ D3D11_FILTER_REDUCTION_TYPE dxReduction = translateFilterReduction(desc.reductionOp);
+ D3D11_FILTER dxFilter;
+ if (desc.maxAnisotropy > 1)
+ {
+ dxFilter = D3D11_ENCODE_ANISOTROPIC_FILTER(dxReduction);
+ }
+ else
+ {
+ D3D11_FILTER_TYPE dxMin = translateFilterMode(desc.minFilter);
+ D3D11_FILTER_TYPE dxMag = translateFilterMode(desc.magFilter);
+ D3D11_FILTER_TYPE dxMip = translateFilterMode(desc.mipFilter);
+
+ dxFilter = D3D11_ENCODE_BASIC_FILTER(dxMin, dxMag, dxMip, dxReduction);
+ }
+
+ D3D11_SAMPLER_DESC dxDesc = {};
+ dxDesc.Filter = dxFilter;
+ dxDesc.AddressU = translateAddressingMode(desc.addressU);
+ dxDesc.AddressV = translateAddressingMode(desc.addressV);
+ dxDesc.AddressW = translateAddressingMode(desc.addressW);
+ dxDesc.MipLODBias = desc.mipLODBias;
+ dxDesc.MaxAnisotropy = desc.maxAnisotropy;
+ dxDesc.ComparisonFunc = translateComparisonFunc(desc.comparisonFunc);
+ for (int ii = 0; ii < 4; ++ii)
+ dxDesc.BorderColor[ii] = desc.borderColor[ii];
+ dxDesc.MinLOD = desc.minLOD;
+ dxDesc.MaxLOD = desc.maxLOD;
+
+ ComPtr<ID3D11SamplerState> sampler;
+ SLANG_RETURN_ON_FAIL(m_device->CreateSamplerState(
+ &dxDesc,
+ sampler.writeRef()));
+
+ RefPtr<SamplerStateImpl> samplerImpl = new SamplerStateImpl();
+ samplerImpl->m_sampler = sampler;
+ *outSampler = samplerImpl.detach();
+ return SLANG_OK;
+}
+
+Result D3D11Renderer::createTextureView(TextureResource* texture, ResourceView::Desc const& desc, ResourceView** outView)
+{
+ auto resourceImpl = (TextureResourceImpl*) texture;
+
+ switch (desc.type)
+ {
+ default:
+ return SLANG_FAIL;
+
+ case ResourceView::Type::RenderTarget:
+ {
+ ComPtr<ID3D11RenderTargetView> rtv;
+ SLANG_RETURN_ON_FAIL(m_device->CreateRenderTargetView(resourceImpl->m_resource, nullptr, rtv.writeRef()));
+
+ RefPtr<RenderTargetViewImpl> viewImpl = new RenderTargetViewImpl();
+ viewImpl->m_type = ResourceViewImpl::Type::RTV;
+ viewImpl->m_rtv = rtv;
+ *outView = viewImpl.detach();
+ return SLANG_OK;
+ }
+ break;
+
+ case ResourceView::Type::DepthStencil:
+ {
+ ComPtr<ID3D11DepthStencilView> dsv;
+ SLANG_RETURN_ON_FAIL(m_device->CreateDepthStencilView(resourceImpl->m_resource, nullptr, dsv.writeRef()));
+
+ RefPtr<DepthStencilViewImpl> viewImpl = new DepthStencilViewImpl();
+ viewImpl->m_type = ResourceViewImpl::Type::DSV;
+ viewImpl->m_dsv = dsv;
+ *outView = viewImpl.detach();
+ return SLANG_OK;
+ }
+ break;
+
+ case ResourceView::Type::UnorderedAccess:
+ {
+ ComPtr<ID3D11UnorderedAccessView> uav;
+ SLANG_RETURN_ON_FAIL(m_device->CreateUnorderedAccessView(resourceImpl->m_resource, nullptr, uav.writeRef()));
+
+ RefPtr<UnorderedAccessViewImpl> viewImpl = new UnorderedAccessViewImpl();
+ viewImpl->m_type = ResourceViewImpl::Type::UAV;
+ viewImpl->m_uav = uav;
+ *outView = viewImpl.detach();
+ return SLANG_OK;
+ }
+ break;
+
+ case ResourceView::Type::ShaderResource:
+ {
+ ComPtr<ID3D11ShaderResourceView> srv;
+ SLANG_RETURN_ON_FAIL(m_device->CreateShaderResourceView(resourceImpl->m_resource, nullptr, srv.writeRef()));
+
+ RefPtr<ShaderResourceViewImpl> viewImpl = new ShaderResourceViewImpl();
+ viewImpl->m_type = ResourceViewImpl::Type::SRV;
+ viewImpl->m_srv = srv;
+ *outView = viewImpl.detach();
+ return SLANG_OK;
+ }
+ break;
+ }
+}
+
+Result D3D11Renderer::createBufferView(BufferResource* buffer, ResourceView::Desc const& desc, ResourceView** outView)
+{
+ auto resourceImpl = (BufferResourceImpl*) buffer;
+ auto resourceDesc = resourceImpl->getDesc();
+
+ switch (desc.type)
+ {
+ default:
+ return SLANG_FAIL;
+
+ case ResourceView::Type::UnorderedAccess:
+ {
+ D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
+ uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
+ uavDesc.Format = D3DUtil::getMapFormat(desc.format);
+ uavDesc.Buffer.FirstElement = 0;
+ uavDesc.Buffer.NumElements = resourceDesc.sizeInBytes;
+
+ if(resourceDesc.elementSize)
+ {
+ uavDesc.Buffer.NumElements = resourceDesc.sizeInBytes / resourceDesc.elementSize;
+ }
+ else if(desc.format == Format::Unknown)
+ {
+ uavDesc.Buffer.Flags |= D3D11_BUFFER_UAV_FLAG_RAW;
+ uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
+ }
+
+ ComPtr<ID3D11UnorderedAccessView> uav;
+ SLANG_RETURN_ON_FAIL(m_device->CreateUnorderedAccessView(resourceImpl->m_buffer, &uavDesc, uav.writeRef()));
+
+ RefPtr<UnorderedAccessViewImpl> viewImpl = new UnorderedAccessViewImpl();
+ viewImpl->m_type = ResourceViewImpl::Type::UAV;
+ viewImpl->m_uav = uav;
+ *outView = viewImpl.detach();
+ return SLANG_OK;
+ }
+ break;
+
+ case ResourceView::Type::ShaderResource:
+ {
+ D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
+ srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
+ srvDesc.Format = D3DUtil::getMapFormat(desc.format);
+ srvDesc.Buffer.ElementOffset = 0;
+ srvDesc.Buffer.ElementWidth = 1;
+ srvDesc.Buffer.FirstElement = 0;
+ srvDesc.Buffer.NumElements = resourceDesc.sizeInBytes;
+
+ if(resourceDesc.elementSize)
+ {
+ srvDesc.Buffer.ElementWidth = resourceDesc.elementSize;
+ srvDesc.Buffer.NumElements = resourceDesc.sizeInBytes / resourceDesc.elementSize;
+ }
+
+ ComPtr<ID3D11ShaderResourceView> srv;
+ SLANG_RETURN_ON_FAIL(m_device->CreateShaderResourceView(resourceImpl->m_buffer, &srvDesc, srv.writeRef()));
+
+ RefPtr<ShaderResourceViewImpl> viewImpl = new ShaderResourceViewImpl();
+ viewImpl->m_type = ResourceViewImpl::Type::SRV;
+ viewImpl->m_srv = srv;
+ *outView = viewImpl.detach();
+ return SLANG_OK;
+ }
+ break;
+ }
+}
+
+Result D3D11Renderer::createInputLayout(const InputElementDesc* inputElementsIn, UInt inputElementCount, InputLayout** outLayout)
+{
+ D3D11_INPUT_ELEMENT_DESC inputElements[16] = {};
+
+ char hlslBuffer[1024];
+ char* hlslCursor = &hlslBuffer[0];
+
+ hlslCursor += sprintf(hlslCursor, "float4 main(\n");
+
+ for (UInt ii = 0; ii < inputElementCount; ++ii)
+ {
+ inputElements[ii].SemanticName = inputElementsIn[ii].semanticName;
+ inputElements[ii].SemanticIndex = (UINT)inputElementsIn[ii].semanticIndex;
+ inputElements[ii].Format = D3DUtil::getMapFormat(inputElementsIn[ii].format);
+ inputElements[ii].InputSlot = 0;
+ inputElements[ii].AlignedByteOffset = (UINT)inputElementsIn[ii].offset;
+ inputElements[ii].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
+ inputElements[ii].InstanceDataStepRate = 0;
+
+ if (ii != 0)
+ {
+ hlslCursor += sprintf(hlslCursor, ",\n");
+ }
+
+ char const* typeName = "Unknown";
+ switch (inputElementsIn[ii].format)
+ {
+ case Format::RGBA_Float32:
+ typeName = "float4";
+ break;
+ case Format::RGB_Float32:
+ typeName = "float3";
+ break;
+ case Format::RG_Float32:
+ typeName = "float2";
+ break;
+ case Format::R_Float32:
+ typeName = "float";
+ break;
+ default:
+ return SLANG_FAIL;
+ }
+
+ hlslCursor += sprintf(hlslCursor, "%s a%d : %s%d",
+ typeName,
+ (int)ii,
+ inputElementsIn[ii].semanticName,
+ (int)inputElementsIn[ii].semanticIndex);
+ }
+
+ hlslCursor += sprintf(hlslCursor, "\n) : SV_Position { return 0; }");
+
+ ComPtr<ID3DBlob> vertexShaderBlob;
+ SLANG_RETURN_ON_FAIL(D3DUtil::compileHLSLShader("inputLayout", hlslBuffer, "main", "vs_5_0", vertexShaderBlob));
+
+ ComPtr<ID3D11InputLayout> inputLayout;
+ SLANG_RETURN_ON_FAIL(m_device->CreateInputLayout(&inputElements[0], (UINT)inputElementCount, vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(),
+ inputLayout.writeRef()));
+
+ RefPtr<InputLayoutImpl> impl = new InputLayoutImpl;
+ impl->m_layout.swap(inputLayout);
+
+ *outLayout = impl.detach();
+ return SLANG_OK;
+}
+
+void* D3D11Renderer::map(BufferResource* bufferIn, MapFlavor flavor)
+{
+ BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(bufferIn);
+
+ D3D11_MAP mapType;
+ ID3D11Buffer* buffer = bufferResource->m_buffer;
+
+ switch (flavor)
+ {
+ case MapFlavor::WriteDiscard:
+ mapType = D3D11_MAP_WRITE_DISCARD;
+ break;
+ case MapFlavor::HostWrite:
+ mapType = D3D11_MAP_WRITE;
+ break;
+ case MapFlavor::HostRead:
+ mapType = D3D11_MAP_READ;
+
+ buffer = bufferResource->m_staging;
+ if (!buffer)
+ {
+ return nullptr;
+ }
+
+ // Okay copy the data over
+ m_immediateContext->CopyResource(buffer, bufferResource->m_buffer);
+
+ break;
+ default:
+ return nullptr;
+ }
+
+ // We update our constant buffer per-frame, just for the purposes
+ // of the example, but we don't actually load different data
+ // per-frame (we always use an identity projection).
+ D3D11_MAPPED_SUBRESOURCE mappedSub;
+ SLANG_RETURN_NULL_ON_FAIL(m_immediateContext->Map(buffer, 0, mapType, 0, &mappedSub));
+
+ bufferResource->m_mapFlavor = flavor;
+
+ return mappedSub.pData;
+}
+
+void D3D11Renderer::unmap(BufferResource* bufferIn)
+{
+ BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(bufferIn);
+ ID3D11Buffer* buffer = (bufferResource->m_mapFlavor == MapFlavor::HostRead) ? bufferResource->m_staging : bufferResource->m_buffer;
+ m_immediateContext->Unmap(buffer, 0);
+}
+
+#if 0
+void D3D11Renderer::setInputLayout(InputLayout* inputLayoutIn)
+{
+ auto inputLayout = static_cast<InputLayoutImpl*>(inputLayoutIn);
+ m_immediateContext->IASetInputLayout(inputLayout->m_layout);
+}
+#endif
+
+void D3D11Renderer::setPrimitiveTopology(PrimitiveTopology topology)
+{
+ m_immediateContext->IASetPrimitiveTopology(D3DUtil::getPrimitiveTopology(topology));
+}
+
+void D3D11Renderer::setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffersIn, const UInt* stridesIn, const UInt* offsetsIn)
+{
+ static const int kMaxVertexBuffers = 16;
+ assert(slotCount <= kMaxVertexBuffers);
+
+ UINT vertexStrides[kMaxVertexBuffers];
+ UINT vertexOffsets[kMaxVertexBuffers];
+ ID3D11Buffer* dxBuffers[kMaxVertexBuffers];
+
+ auto buffers = (BufferResourceImpl*const*)buffersIn;
+
+ for (UInt ii = 0; ii < slotCount; ++ii)
+ {
+ vertexStrides[ii] = (UINT)stridesIn[ii];
+ vertexOffsets[ii] = (UINT)offsetsIn[ii];
+ dxBuffers[ii] = buffers[ii]->m_buffer;
+ }
+
+ m_immediateContext->IASetVertexBuffers((UINT)startSlot, (UINT)slotCount, dxBuffers, &vertexStrides[0], &vertexOffsets[0]);
+}
+
+void D3D11Renderer::setIndexBuffer(BufferResource* buffer, Format indexFormat, UInt offset)
+{
+ DXGI_FORMAT dxFormat = D3DUtil::getMapFormat(indexFormat);
+ m_immediateContext->IASetIndexBuffer(((BufferResourceImpl*)buffer)->m_buffer, dxFormat, offset);
+}
+
+void D3D11Renderer::setDepthStencilTarget(ResourceView* depthStencilView)
+{
+ m_dsvBinding = ((DepthStencilViewImpl*) depthStencilView)->m_dsv;
+ m_targetBindingsDirty[int(PipelineType::Graphics)] = true;
+}
+
+void D3D11Renderer::setPipelineState(PipelineType pipelineType, PipelineState* state)
+{
+ switch(pipelineType)
+ {
+ default:
+ break;
+
+ case PipelineType::Graphics:
+ {
+ auto stateImpl = (GraphicsPipelineStateImpl*) state;
+ auto programImpl = stateImpl->m_program;
+
+ // TODO: We could conceivably do some lightweight state
+ // differencing here (e.g., check if `programImpl` is the
+ // same as the program that is currently bound).
+ //
+ // It isn't clear how much that would pay off given that
+ // the D3D11 runtime seems to do its own state diffing.
+
+ // IA
+
+ m_immediateContext->IASetInputLayout(stateImpl->m_inputLayout->m_layout);
+
+ // VS
+
+ m_immediateContext->VSSetShader(programImpl->m_vertexShader, nullptr, 0);
+
+ // HS
+
+ // DS
+
+ // GS
+
+ // RS
+
+ m_immediateContext->RSSetState(stateImpl->m_rasterizerState);
+
+ // PS
+
+ m_immediateContext->PSSetShader(programImpl->m_pixelShader, nullptr, 0);
+
+ // OM
+
+ m_immediateContext->OMSetDepthStencilState(stateImpl->m_depthStencilState, stateImpl->m_stencilRef);
+
+ m_currentGraphicsState = stateImpl;
+ }
+ break;
+
+ case PipelineType::Compute:
+ {
+ auto stateImpl = (ComputePipelineStateImpl*) state;
+ auto programImpl = stateImpl->m_program;
+
+ // CS
+
+ m_immediateContext->CSSetShader(programImpl->m_computeShader, nullptr, 0);
+
+ m_currentComputeState = stateImpl;
+ }
+ break;
+ }
+
+ /// ...
+}
+
+void D3D11Renderer::draw(UInt vertexCount, UInt startVertex)
+{
+ _flushGraphicsState();
+ m_immediateContext->Draw((UINT)vertexCount, (UINT)startVertex);
+}
+
+void D3D11Renderer::drawIndexed(UInt indexCount, UInt startIndex, UInt baseVertex)
+{
+ _flushGraphicsState();
+ m_immediateContext->DrawIndexed((UINT)indexCount, (UINT)startIndex, (UInt)baseVertex);
+}
+
+Result D3D11Renderer::createProgram(const ShaderProgram::Desc& desc, ShaderProgram** outProgram)
+{
+ if (desc.pipelineType == PipelineType::Compute)
+ {
+ auto computeKernel = desc.findKernel(StageType::Compute);
+
+ ComPtr<ID3D11ComputeShader> computeShader;
+ SLANG_RETURN_ON_FAIL(m_device->CreateComputeShader(computeKernel->codeBegin, computeKernel->getCodeSize(), nullptr, computeShader.writeRef()));
+
+ RefPtr<ShaderProgramImpl> shaderProgram = new ShaderProgramImpl();
+ shaderProgram->m_computeShader.swap(computeShader);
+
+ *outProgram = shaderProgram.detach();
+ return SLANG_OK;
+ }
+ else
+ {
+ auto vertexKernel = desc.findKernel(StageType::Vertex);
+ auto fragmentKernel = desc.findKernel(StageType::Fragment);
+
+ ComPtr<ID3D11VertexShader> vertexShader;
+ ComPtr<ID3D11PixelShader> pixelShader;
+
+ SLANG_RETURN_ON_FAIL(m_device->CreateVertexShader(vertexKernel->codeBegin, vertexKernel->getCodeSize(), nullptr, vertexShader.writeRef()));
+ SLANG_RETURN_ON_FAIL(m_device->CreatePixelShader(fragmentKernel->codeBegin, fragmentKernel->getCodeSize(), nullptr, pixelShader.writeRef()));
+
+ RefPtr<ShaderProgramImpl> shaderProgram = new ShaderProgramImpl();
+ shaderProgram->m_vertexShader.swap(vertexShader);
+ shaderProgram->m_pixelShader.swap(pixelShader);
+
+ *outProgram = shaderProgram.detach();
+ return SLANG_OK;
+ }
+}
+
+static D3D11_STENCIL_OP translateStencilOp(StencilOp op)
+{
+ switch(op)
+ {
+ default:
+ // TODO: need to report failures
+ return D3D11_STENCIL_OP_KEEP;
+
+#define CASE(FROM, TO) \
+ case StencilOp::FROM: return D3D11_STENCIL_OP_##TO
+
+ CASE(Keep, KEEP);
+ CASE(Zero, ZERO);
+ CASE(Replace, REPLACE);
+ CASE(IncrementSaturate, INCR_SAT);
+ CASE(DecrementSaturate, DECR_SAT);
+ CASE(Invert, INVERT);
+ CASE(IncrementWrap, INCR);
+ CASE(DecrementWrap, DECR);
+#undef CASE
+
+ }
+}
+
+static D3D11_FILL_MODE translateFillMode(FillMode mode)
+{
+ switch(mode)
+ {
+ default:
+ // TODO: need to report failures
+ return D3D11_FILL_SOLID;
+
+ case FillMode::Solid: return D3D11_FILL_SOLID;
+ case FillMode::Wireframe: return D3D11_FILL_WIREFRAME;
+ }
+}
+
+static D3D11_CULL_MODE translateCullMode(CullMode mode)
+{
+ switch(mode)
+ {
+ default:
+ // TODO: need to report failures
+ return D3D11_CULL_NONE;
+
+ case CullMode::None: return D3D11_CULL_NONE;
+ case CullMode::Back: return D3D11_CULL_BACK;
+ case CullMode::Front: return D3D11_CULL_FRONT;
+ }
+}
+
+Result D3D11Renderer::createGraphicsPipelineState(const GraphicsPipelineStateDesc& desc, PipelineState** outState)
+{
+ auto programImpl = (ShaderProgramImpl*) desc.program;
+
+ ComPtr<ID3D11DepthStencilState> depthStencilState;
+ {
+ D3D11_DEPTH_STENCIL_DESC dsDesc;
+ dsDesc.DepthEnable = desc.depthStencil.depthTestEnable;
+ dsDesc.DepthWriteMask = desc.depthStencil.depthWriteEnable ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
+ dsDesc.DepthFunc = translateComparisonFunc(desc.depthStencil.depthFunc);
+ dsDesc.StencilEnable = desc.depthStencil.stencilEnable;
+ dsDesc.StencilReadMask = desc.depthStencil.stencilReadMask;
+ dsDesc.StencilWriteMask = desc.depthStencil.stencilWriteMask;
+
+ #define FACE(DST, SRC) \
+ dsDesc.DST.StencilFailOp = translateStencilOp( desc.depthStencil.SRC.stencilFailOp); \
+ dsDesc.DST.StencilDepthFailOp = translateStencilOp( desc.depthStencil.SRC.stencilDepthFailOp); \
+ dsDesc.DST.StencilPassOp = translateStencilOp( desc.depthStencil.SRC.stencilPassOp); \
+ dsDesc.DST.StencilFunc = translateComparisonFunc(desc.depthStencil.SRC.stencilFunc); \
+ /* end */
+
+ FACE(FrontFace, frontFace);
+ FACE(BackFace, backFace);
+
+ SLANG_RETURN_ON_FAIL(m_device->CreateDepthStencilState(
+ &dsDesc,
+ depthStencilState.writeRef()));
+ }
+
+ ComPtr<ID3D11RasterizerState> rasterizerState;
+ {
+ D3D11_RASTERIZER_DESC rsDesc;
+ rsDesc.FillMode = translateFillMode(desc.rasterizer.fillMode);
+ rsDesc.CullMode = translateCullMode(desc.rasterizer.cullMode);
+ rsDesc.FrontCounterClockwise = desc.rasterizer.frontFace == FrontFaceMode::Clockwise;
+ rsDesc.DepthBias = desc.rasterizer.depthBias;
+ rsDesc.DepthBiasClamp = desc.rasterizer.depthBiasClamp;
+ rsDesc.SlopeScaledDepthBias = desc.rasterizer.slopeScaledDepthBias;
+ rsDesc.DepthClipEnable = desc.rasterizer.depthClipEnable;
+ rsDesc.ScissorEnable = desc.rasterizer.scissorEnable;
+ rsDesc.MultisampleEnable = desc.rasterizer.multisampleEnable;
+ rsDesc.AntialiasedLineEnable = desc.rasterizer.antialiasedLineEnable;
+
+ SLANG_RETURN_ON_FAIL(m_device->CreateRasterizerState(
+ &rsDesc,
+ rasterizerState.writeRef()));
+
+ }
+
+ RefPtr<GraphicsPipelineStateImpl> state = new GraphicsPipelineStateImpl();
+ state->m_program = programImpl;
+ state->m_stencilRef = desc.depthStencil.stencilRef;
+ state->m_depthStencilState = depthStencilState;
+ state->m_rasterizerState = rasterizerState;
+ state->m_pipelineLayout = (PipelineLayoutImpl*) desc.pipelineLayout;
+ state->m_inputLayout = (InputLayoutImpl*) desc.inputLayout;
+ state->m_rtvCount = desc.renderTargetCount;
+
+ *outState = state.detach();
+ return SLANG_OK;
+}
+
+Result D3D11Renderer::createComputePipelineState(const ComputePipelineStateDesc& desc, PipelineState** outState)
+{
+ auto programImpl = (ShaderProgramImpl*) desc.program;
+ auto pipelineLayoutImpl = (PipelineLayoutImpl*) desc.pipelineLayout;
+
+ RefPtr<ComputePipelineStateImpl> state = new ComputePipelineStateImpl();
+ state->m_program = programImpl;
+ state->m_pipelineLayout = pipelineLayoutImpl;
+
+ *outState = state.detach();
+ return SLANG_OK;
+}
+
+void D3D11Renderer::dispatchCompute(int x, int y, int z)
+{
+ _flushComputeState();
+ m_immediateContext->Dispatch(x, y, z);
+}
+
+Result D3D11Renderer::createDescriptorSetLayout(const DescriptorSetLayout::Desc& desc, DescriptorSetLayout** outLayout)
+{
+ RefPtr<DescriptorSetLayoutImpl> descriptorSetLayoutImpl = new DescriptorSetLayoutImpl();
+
+ UInt counts[int(D3D11DescriptorSlotType::CountOf)] = { 0, };
+
+ UInt rangeCount = desc.slotRangeCount;
+ for(UInt rr = 0; rr < rangeCount; ++rr)
+ {
+ auto rangeDesc = desc.slotRanges[rr];
+
+ DescriptorSetLayoutImpl::RangeInfo rangeInfo;
+
+ switch(rangeDesc.type)
+ {
+ default:
+ assert(!"invalid slot type");
+ return SLANG_FAIL;
+
+ case DescriptorSlotType::Sampler:
+ rangeInfo.type = D3D11DescriptorSlotType::Sampler;
+ break;
+
+ case DescriptorSlotType::CombinedImageSampler:
+ rangeInfo.type = D3D11DescriptorSlotType::CombinedTextureSampler;
+ break;
+
+ case DescriptorSlotType::UniformBuffer:
+ case DescriptorSlotType::DynamicUniformBuffer:
+ rangeInfo.type = D3D11DescriptorSlotType::ConstantBuffer;
+ break;
+
+ case DescriptorSlotType::SampledImage:
+ case DescriptorSlotType::UniformTexelBuffer:
+ case DescriptorSlotType::InputAttachment:
+ rangeInfo.type = D3D11DescriptorSlotType::ShaderResourceView;
+ break;
+
+ case DescriptorSlotType::StorageImage:
+ case DescriptorSlotType::StorageTexelBuffer:
+ case DescriptorSlotType::StorageBuffer:
+ case DescriptorSlotType::DynamicStorageBuffer:
+ rangeInfo.type = D3D11DescriptorSlotType::UnorderedAccessView;
+ break;
+ }
+
+ if(rangeInfo.type == D3D11DescriptorSlotType::CombinedTextureSampler)
+ {
+ auto srvTypeIndex = int(D3D11DescriptorSlotType::ShaderResourceView);
+ auto samplerTypeIndex = int(D3D11DescriptorSlotType::Sampler);
+
+ rangeInfo.arrayIndex = counts[srvTypeIndex];
+ rangeInfo.pairedSamplerArrayIndex = counts[samplerTypeIndex];
+
+ counts[srvTypeIndex] += rangeDesc.count;
+ counts[samplerTypeIndex] += rangeDesc.count;
+ }
+ else
+ {
+ auto typeIndex = int(rangeInfo.type);
+
+ rangeInfo.arrayIndex = counts[typeIndex];
+ counts[typeIndex] += rangeDesc.count;
+ }
+ descriptorSetLayoutImpl->m_ranges.Add(rangeInfo);
+ }
+
+ for(int ii = 0; ii < int(D3D11DescriptorSlotType::CountOf); ++ii)
+ {
+ descriptorSetLayoutImpl->m_counts[ii] = counts[ii];
+ }
+
+ *outLayout = descriptorSetLayoutImpl.detach();
+ return SLANG_OK;
+}
+
+Result D3D11Renderer::createPipelineLayout(const PipelineLayout::Desc& desc, PipelineLayout** outLayout)
+{
+ RefPtr<PipelineLayoutImpl> pipelineLayoutImpl = new PipelineLayoutImpl();
+
+ UInt counts[int(D3D11DescriptorSlotType::CountOf)] = { 0, };
+
+ UInt setCount = desc.descriptorSetCount;
+ for(UInt ii = 0; ii < setCount; ++ii)
+ {
+ auto setDesc = desc.descriptorSets[ii];
+ PipelineLayoutImpl::DescriptorSetInfo setInfo;
+
+ setInfo.layout = (DescriptorSetLayoutImpl*) setDesc.layout;
+
+ for(int jj = 0; jj < int(D3D11DescriptorSlotType::CountOf); ++jj)
+ {
+ setInfo.baseIndices[jj] = counts[jj];
+ counts[jj] += setInfo.layout->m_counts[jj];
+ }
+
+ pipelineLayoutImpl->m_descriptorSets.Add(setInfo);
+ }
+
+ pipelineLayoutImpl->m_uavCount = counts[int(D3D11DescriptorSlotType::UnorderedAccessView)];
+
+ *outLayout = pipelineLayoutImpl.detach();
+ return SLANG_OK;
+}
+
+Result D3D11Renderer::createDescriptorSet(DescriptorSetLayout* layout, DescriptorSet** outDescriptorSet)
+{
+ auto layoutImpl = (DescriptorSetLayoutImpl*)layout;
+
+ RefPtr<DescriptorSetImpl> descriptorSetImpl = new DescriptorSetImpl();
+
+ descriptorSetImpl->m_layout = layoutImpl;
+ descriptorSetImpl->m_cbs .SetSize(layoutImpl->m_counts[int(D3D11DescriptorSlotType::ConstantBuffer)]);
+ descriptorSetImpl->m_srvs .SetSize(layoutImpl->m_counts[int(D3D11DescriptorSlotType::ShaderResourceView)]);
+ descriptorSetImpl->m_uavs .SetSize(layoutImpl->m_counts[int(D3D11DescriptorSlotType::UnorderedAccessView)]);
+ descriptorSetImpl->m_samplers.SetSize(layoutImpl->m_counts[int(D3D11DescriptorSlotType::Sampler)]);
+
+ *outDescriptorSet = descriptorSetImpl.detach();
+ return SLANG_OK;
+}
+
+
+#if 0
+BindingState* D3D11Renderer::createBindingState(const BindingState::Desc& bindingStateDesc)
+{
+ RefPtr<BindingStateImpl> bindingState(new BindingStateImpl(bindingStateDesc));
+
+ const auto& srcBindings = bindingStateDesc.m_bindings;
+ const int numBindings = int(srcBindings.Count());
+
+ auto& dstDetails = bindingState->m_bindingDetails;
+ dstDetails.SetSize(numBindings);
+
+ for (int i = 0; i < numBindings; ++i)
+ {
+ auto& dstDetail = dstDetails[i];
+ const auto& srcBinding = srcBindings[i];
+
+ assert(srcBinding.registerRange.isSingle());
+
+ switch (srcBinding.bindingType)
+ {
+ case BindingType::Buffer:
+ {
+ assert(srcBinding.resource && srcBinding.resource->isBuffer());
+
+ BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(srcBinding.resource.Ptr());
+ const BufferResource::Desc& desc = buffer->getDesc();
+
+ const int elemSize = bufferDesc.elementSize <= 0 ? 1 : bufferDesc.elementSize;
+
+ if (bufferDesc.bindFlags & Resource::BindFlag::UnorderedAccess)
+ {
+ D3D11_UNORDERED_ACCESS_VIEW_DESC viewDesc;
+ memset(&viewDesc, 0, sizeof(viewDesc));
+ viewDesc.Buffer.FirstElement = 0;
+ viewDesc.Buffer.NumElements = (UINT)(bufferDesc.sizeInBytes / elemSize);
+ viewDesc.Buffer.Flags = 0;
+ viewDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
+ viewDesc.Format = D3DUtil::getMapFormat(bufferDesc.format);
+
+ if (bufferDesc.elementSize == 0 && bufferDesc.format == Format::Unknown)
+ {
+ viewDesc.Buffer.Flags |= D3D11_BUFFER_UAV_FLAG_RAW;
+ viewDesc.Format = DXGI_FORMAT_R32_TYPELESS;
+ }
+
+ SLANG_RETURN_NULL_ON_FAIL(m_device->CreateUnorderedAccessView(buffer->m_buffer, &viewDesc, dstDetail.m_uav.writeRef()));
+ }
+ if (bufferDesc.bindFlags & (Resource::BindFlag::NonPixelShaderResource | Resource::BindFlag::PixelShaderResource))
+ {
+ D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc;
+ memset(&viewDesc, 0, sizeof(viewDesc));
+ viewDesc.Buffer.FirstElement = 0;
+ viewDesc.Buffer.ElementWidth = elemSize;
+ viewDesc.Buffer.NumElements = (UINT)(bufferDesc.sizeInBytes / elemSize);
+ viewDesc.Buffer.ElementOffset = 0;
+ viewDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
+ viewDesc.Format = DXGI_FORMAT_UNKNOWN;
+
+ if (bufferDesc.elementSize == 0)
+ {
+ viewDesc.Format = DXGI_FORMAT_R32_FLOAT;
+ }
+
+ SLANG_RETURN_NULL_ON_FAIL(m_device->CreateShaderResourceView(buffer->m_buffer, &viewDesc, dstDetail.m_srv.writeRef()));
+ }
+ break;
+ }
+ case BindingType::Texture:
+ case BindingType::CombinedTextureSampler:
+ {
+ assert(srcBinding.resource && srcBinding.resource->isTexture());
+
+ TextureResourceImpl* texture = static_cast<TextureResourceImpl*>(srcBinding.resource.Ptr());
+
+ const TextureResource::Desc& textureDesc = texture->getDesc();
+
+ D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc;
+ viewDesc.Format = D3DUtil::getMapFormat(textureDesc.format);
+
+ switch (texture->getType())
+ {
+ case Resource::Type::Texture1D:
+ {
+ if (textureDesc.arraySize <= 0)
+ {
+ viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D;
+ viewDesc.Texture1D.MipLevels = textureDesc.numMipLevels;
+ viewDesc.Texture1D.MostDetailedMip = 0;
+ }
+ else
+ {
+ viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1DARRAY;
+ viewDesc.Texture1DArray.ArraySize = textureDesc.arraySize;
+ viewDesc.Texture1DArray.FirstArraySlice = 0;
+ viewDesc.Texture1DArray.MipLevels = textureDesc.numMipLevels;
+ viewDesc.Texture1DArray.MostDetailedMip = 0;
+ }
+ break;
+ }
+ case Resource::Type::Texture2D:
+ {
+ if (textureDesc.arraySize <= 0)
+ {
+ viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+ viewDesc.Texture2D.MipLevels = textureDesc.numMipLevels;
+ viewDesc.Texture2D.MostDetailedMip = 0;
+ }
+ else
+ {
+ viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
+ viewDesc.Texture2DArray.ArraySize = textureDesc.arraySize;
+ viewDesc.Texture2DArray.FirstArraySlice = 0;
+ viewDesc.Texture2DArray.MipLevels = textureDesc.numMipLevels;
+ viewDesc.Texture2DArray.MostDetailedMip = 0;
+ }
+ break;
+ }
+ case Resource::Type::TextureCube:
+ {
+ if (textureDesc.arraySize <= 0)
+ {
+ viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
+ viewDesc.TextureCube.MipLevels = textureDesc.numMipLevels;
+ viewDesc.TextureCube.MostDetailedMip = 0;
+ }
+ else
+ {
+ viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBEARRAY;
+ viewDesc.TextureCubeArray.MipLevels = textureDesc.numMipLevels;
+ viewDesc.TextureCubeArray.MostDetailedMip = 0;
+ viewDesc.TextureCubeArray.First2DArrayFace = 0;
+ viewDesc.TextureCubeArray.NumCubes = textureDesc.arraySize;
+ }
+ break;
+ }
+ case Resource::Type::Texture3D:
+ {
+ viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
+ viewDesc.Texture3D.MipLevels = textureDesc.numMipLevels; // Old code fixed as one
+ viewDesc.Texture3D.MostDetailedMip = 0;
+ break;
+ }
+ default:
+ {
+ assert(!"Unhandled type");
+ return nullptr;
+ }
+ }
+
+ SLANG_RETURN_NULL_ON_FAIL(m_device->CreateShaderResourceView(texture->m_resource, &viewDesc, dstDetail.m_srv.writeRef()));
+ break;
+ }
+ case BindingType::Sampler:
+ {
+ const BindingState::SamplerDesc& samplerDesc = bindingStateDesc.m_samplerDescs[srcBinding.descIndex];
+
+ D3D11_SAMPLER_DESC desc = {};
+ desc.AddressU = desc.AddressV = desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
+
+ if (samplerDesc.isCompareSampler)
+ {
+ desc.ComparisonFunc = D3D11_COMPARISON_LESS_EQUAL;
+ desc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT;
+ desc.MinLOD = desc.MaxLOD = 0.0f;
+ }
+ else
+ {
+ desc.Filter = D3D11_FILTER_ANISOTROPIC;
+ desc.MaxAnisotropy = 8;
+ desc.MinLOD = 0.0f;
+ desc.MaxLOD = 100.0f;
+ }
+ SLANG_RETURN_NULL_ON_FAIL(m_device->CreateSamplerState(&desc, dstDetail.m_samplerState.writeRef()));
+ break;
+ }
+ default:
+ {
+ assert(!"Unhandled type");
+ return nullptr;
+ }
+ }
+ }
+
+ // Done
+ return bindingState.detach();
+}
+
+void D3D11Renderer::_applyBindingState(bool isCompute)
+{
+ auto context = m_immediateContext.get();
+
+ const auto& details = m_currentBindings->m_bindingDetails;
+ const auto& bindings = m_currentBindings->getDesc().m_bindings;
+
+ const int numBindings = int(bindings.Count());
+
+ for (int i = 0; i < numBindings; ++i)
+ {
+ const auto& binding = bindings[i];
+ const auto& detail = details[i];
+
+ const int bindingIndex = binding.registerRange.getSingleIndex();
+
+ switch (binding.bindingType)
+ {
+ case BindingType::Buffer:
+ {
+ assert(binding.resource && binding.resource->isBuffer());
+ if (binding.resource->canBind(Resource::BindFlag::ConstantBuffer))
+ {
+ ID3D11Buffer* buffer = static_cast<BufferResourceImpl*>(binding.resource.Ptr())->m_buffer;
+ if (isCompute)
+ context->CSSetConstantBuffers(bindingIndex, 1, &buffer);
+ else
+ {
+ context->VSSetConstantBuffers(bindingIndex, 1, &buffer);
+ context->PSSetConstantBuffers(bindingIndex, 1, &buffer);
+ }
+ }
+ else if (detail.m_uav)
+ {
+ if (isCompute)
+ context->CSSetUnorderedAccessViews(bindingIndex, 1, detail.m_uav.readRef(), nullptr);
+ else
+ context->OMSetRenderTargetsAndUnorderedAccessViews(
+ m_currentBindings->getDesc().m_numRenderTargets,
+ m_renderTargetViews.Buffer()->readRef(),
+ m_depthStencilView,
+ bindingIndex,
+ 1,
+ detail.m_uav.readRef(),
+ nullptr);
+ }
+ else
+ {
+ if (isCompute)
+ context->CSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef());
+ else
+ {
+ context->PSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef());
+ context->VSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef());
+ }
+ }
+ break;
+ }
+ case BindingType::Texture:
+ {
+ if (detail.m_uav)
+ {
+ if (isCompute)
+ context->CSSetUnorderedAccessViews(bindingIndex, 1, detail.m_uav.readRef(), nullptr);
+ else
+ context->OMSetRenderTargetsAndUnorderedAccessViews(D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL,
+ nullptr, nullptr, bindingIndex, 1, detail.m_uav.readRef(), nullptr);
+ }
+ else
+ {
+ if (isCompute)
+ context->CSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef());
+ else
+ {
+ context->PSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef());
+ context->VSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef());
+ }
+ }
+ break;
+ }
+ case BindingType::Sampler:
+ {
+ if (isCompute)
+ context->CSSetSamplers(bindingIndex, 1, detail.m_samplerState.readRef());
+ else
+ {
+ context->PSSetSamplers(bindingIndex, 1, detail.m_samplerState.readRef());
+ context->VSSetSamplers(bindingIndex, 1, detail.m_samplerState.readRef());
+ }
+ break;
+ }
+ default:
+ {
+ assert(!"Not implemented");
+ return;
+ }
+ }
+ }
+}
+
+void D3D11Renderer::setBindingState(BindingState* state)
+{
+ m_currentBindings = static_cast<BindingStateImpl*>(state);
+}
+#endif
+
+void D3D11Renderer::_flushGraphicsState()
+{
+ auto pipelineType = int(PipelineType::Graphics);
+ if(m_targetBindingsDirty[pipelineType])
+ {
+ m_targetBindingsDirty[pipelineType] = false;
+
+ auto pipelineState = m_currentGraphicsState.Ptr();
+
+ auto rtvCount = pipelineState->m_rtvCount;
+ auto uavCount = pipelineState->m_pipelineLayout->m_uavCount;
+
+ m_immediateContext->OMSetRenderTargetsAndUnorderedAccessViews(
+ rtvCount,
+ m_rtvBindings[0].readRef(),
+ m_dsvBinding,
+ rtvCount,
+ uavCount,
+ m_uavBindings[pipelineType][0].readRef(),
+ nullptr);
+ }
+}
+
+void D3D11Renderer::_flushComputeState()
+{
+ auto pipelineType = int(PipelineType::Compute);
+ if(m_targetBindingsDirty[pipelineType])
+ {
+ m_targetBindingsDirty[pipelineType] = false;
+
+ auto pipelineState = m_currentComputeState.Ptr();
+
+ auto uavCount = pipelineState->m_pipelineLayout->m_uavCount;
+
+ m_immediateContext->CSSetUnorderedAccessViews(
+ 0,
+ uavCount,
+ m_uavBindings[pipelineType][0].readRef(),
+ nullptr);
+ }
+}
+
+void D3D11Renderer::DescriptorSetImpl::setConstantBuffer(UInt range, UInt index, BufferResource* buffer)
+{
+ auto bufferImpl = (BufferResourceImpl*) buffer;
+ auto& rangeInfo = m_layout->m_ranges[range];
+
+ assert(rangeInfo.type == D3D11DescriptorSlotType::ConstantBuffer);
+
+ m_cbs[rangeInfo.arrayIndex + index] = bufferImpl->m_buffer;
+}
+
+void D3D11Renderer::DescriptorSetImpl::setResource(UInt range, UInt index, ResourceView* view)
+{
+ auto viewImpl = (ResourceViewImpl*)view;
+ auto& rangeInfo = m_layout->m_ranges[range];
+
+ switch (rangeInfo.type)
+ {
+ case D3D11DescriptorSlotType::ShaderResourceView:
+ {
+ assert(viewImpl->m_type == ResourceViewImpl::Type::SRV);
+ auto srvImpl = (ShaderResourceViewImpl*)viewImpl;
+ m_srvs[rangeInfo.arrayIndex + index] = srvImpl->m_srv;
+ }
+ break;
+
+ case D3D11DescriptorSlotType::UnorderedAccessView:
+ {
+ assert(viewImpl->m_type == ResourceViewImpl::Type::UAV);
+ auto uavImpl = (UnorderedAccessViewImpl*)viewImpl;
+ m_uavs[rangeInfo.arrayIndex + index] = uavImpl->m_uav;
+ }
+ break;
+
+ default:
+ assert(!"invalid to bind a resource view to this descriptor range");
+ break;
+ }
+}
+
+void D3D11Renderer::DescriptorSetImpl::setSampler(UInt range, UInt index, SamplerState* sampler)
+{
+ auto samplerImpl = (SamplerStateImpl*) sampler;
+ auto& rangeInfo = m_layout->m_ranges[range];
+
+ assert(rangeInfo.type == D3D11DescriptorSlotType::Sampler);
+
+ m_samplers[rangeInfo.arrayIndex + index] = samplerImpl->m_sampler;
+}
+
+void D3D11Renderer::DescriptorSetImpl::setCombinedTextureSampler(
+ UInt range,
+ UInt index,
+ ResourceView* textureView,
+ SamplerState* sampler)
+{
+ auto viewImpl = (ResourceViewImpl*) textureView;
+ auto samplerImpl = (SamplerStateImpl*)sampler;
+
+ auto& rangeInfo = m_layout->m_ranges[range];
+ assert(rangeInfo.type == D3D11DescriptorSlotType::CombinedTextureSampler);
+
+ assert(viewImpl->m_type == ResourceViewImpl::Type::SRV);
+ auto srvImpl = (ShaderResourceViewImpl*)viewImpl;
+ m_srvs[rangeInfo.arrayIndex + index] = srvImpl->m_srv;
+
+ m_samplers[rangeInfo.arrayIndex + index] = samplerImpl->m_sampler;
+
+ // TODO: need a place to bind the matching sampler...
+ m_srvs[rangeInfo.pairedSamplerArrayIndex + index] = srvImpl->m_srv;
+}
+
+void D3D11Renderer::setDescriptorSet(PipelineType pipelineType, PipelineLayout* layout, UInt index, DescriptorSet* descriptorSet)
+{
+ auto pipelineLayoutImpl = (PipelineLayoutImpl*)layout;
+ auto descriptorSetImpl = (DescriptorSetImpl*) descriptorSet;
+
+ auto descriptorSetLayoutImpl = descriptorSetImpl->m_layout;
+ auto& setInfo = pipelineLayoutImpl->m_descriptorSets[index];
+
+ // Note: `setInfo->layout` and `descriptorSetLayoutImpl` need to be compatible
+
+ // TODO: If/when we add per-stage visibility masks, it would be best to organize
+ // this as a loop over stages, so that we only do the binding that is required
+ // for each stage.
+
+ {
+ int slotType = int(D3D11DescriptorSlotType::ConstantBuffer);
+ UInt slotCount = setInfo.layout->m_counts[slotType];
+ if(slotCount)
+ {
+ UInt startSlot = setInfo.baseIndices[slotType];
+
+ auto cbs = descriptorSetImpl->m_cbs[0].readRef();
+
+ m_immediateContext->VSSetConstantBuffers(startSlot, slotCount, cbs);
+ // ...
+ m_immediateContext->PSSetConstantBuffers(startSlot, slotCount, cbs);
+
+ m_immediateContext->CSSetConstantBuffers(startSlot, slotCount, cbs);
+ }
+ }
+
+ {
+ int slotType = int(D3D11DescriptorSlotType::ShaderResourceView);
+ UInt slotCount = setInfo.layout->m_counts[slotType];
+ if(slotCount)
+ {
+ UInt startSlot = setInfo.baseIndices[slotType];
+
+ auto srvs = descriptorSetImpl->m_srvs[0].readRef();
+
+ m_immediateContext->VSSetShaderResources(startSlot, slotCount, srvs);
+ // ...
+ m_immediateContext->PSSetShaderResources(startSlot, slotCount, srvs);
+
+ m_immediateContext->CSSetShaderResources(startSlot, slotCount, srvs);
+ }
+ }
+
+ {
+ int slotType = int(D3D11DescriptorSlotType::Sampler);
+ UInt slotCount = setInfo.layout->m_counts[slotType];
+ if(slotCount)
+ {
+ UInt startSlot = setInfo.baseIndices[slotType];
+
+ auto samplers = descriptorSetImpl->m_samplers[0].readRef();
+
+ m_immediateContext->VSSetSamplers(startSlot, slotCount, samplers);
+ // ...
+ m_immediateContext->PSSetSamplers(startSlot, slotCount, samplers);
+
+ m_immediateContext->CSSetSamplers(startSlot, slotCount, samplers);
+ }
+ }
+
+ {
+ // Note: UAVs are handled differently from other bindings, because
+ // D3D11 requires all UAVs to be set with a single call, rather
+ // than allowing incremental updates. We will therefore shadow
+ // the UAV bindings with `m_uavBindings` and then flush them
+ // as needed right before a draw/dispatch.
+ //
+ int slotType = int(D3D11DescriptorSlotType::UnorderedAccessView);
+ UInt slotCount = setInfo.layout->m_counts[slotType];
+ if(slotCount)
+ {
+ UInt startSlot = setInfo.baseIndices[slotType];
+
+ auto uavs = descriptorSetImpl->m_uavs[0].readRef();
+
+ for(UINT ii = 0; ii < slotCount; ++ii)
+ {
+ m_uavBindings[int(pipelineType)][startSlot + ii] = uavs[ii];
+ }
+ m_targetBindingsDirty[int(pipelineType)] = true;
+ }
+ }
+
+
+}
+
+} // renderer_test
diff --git a/tools/slang-graphics/render-d3d11.h b/tools/gfx/render-d3d11.h
index 7b3d25e9f..9e671d541 100644
--- a/tools/slang-graphics/render-d3d11.h
+++ b/tools/gfx/render-d3d11.h
@@ -1,10 +1,10 @@
// render-d3d11.h
#pragma once
-namespace slang_graphics {
+namespace gfx {
class Renderer;
Renderer* createD3D11Renderer();
-} // slang_graphics
+} // gfx
diff --git a/tools/slang-graphics/render-d3d12.cpp b/tools/gfx/render-d3d12.cpp
index 24c9ecacb..2d3b8f521 100644
--- a/tools/slang-graphics/render-d3d12.cpp
+++ b/tools/gfx/render-d3d12.cpp
@@ -1,4 +1,4 @@
-// render-d3d12.cpp
+// render-d3d12.cpp
#define _CRT_SECURE_NO_WARNINGS
#include "render-d3d12.h"
@@ -46,7 +46,7 @@
#define ENABLE_DEBUG_LAYER 1
-namespace slang_graphics {
+namespace gfx {
using namespace Slang;
class D3D12Renderer : public Renderer
@@ -57,20 +57,40 @@ public:
virtual void setClearColor(const float color[4]) override;
virtual void clearFrame() override;
virtual void presentFrame() override;
- virtual TextureResource* createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData) override;
- virtual BufferResource* createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& bufferDesc, const void* initData) override;
+ TextureResource::Desc getSwapChainTextureDesc() override;
+
+ Result createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData, TextureResource** outResource) override;
+ Result createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& desc, const void* initData, BufferResource** outResource) override;
+ Result createSamplerState(SamplerState::Desc const& desc, SamplerState** outSampler) override;
+
+ Result createTextureView(TextureResource* texture, ResourceView::Desc const& desc, ResourceView** outView) override;
+ Result createBufferView(BufferResource* buffer, ResourceView::Desc const& desc, ResourceView** outView) override;
+
+ Result createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount, InputLayout** outLayout) override;
+
+ Result createDescriptorSetLayout(const DescriptorSetLayout::Desc& desc, DescriptorSetLayout** outLayout) override;
+ Result createPipelineLayout(const PipelineLayout::Desc& desc, PipelineLayout** outLayout) override;
+ Result createDescriptorSet(DescriptorSetLayout* layout, DescriptorSet** outDescriptorSet) override;
+
+ Result createProgram(const ShaderProgram::Desc& desc, ShaderProgram** outProgram) override;
+ Result createGraphicsPipelineState(const GraphicsPipelineStateDesc& desc, PipelineState** outState) override;
+ Result createComputePipelineState(const ComputePipelineStateDesc& desc, PipelineState** outState) override;
+
virtual SlangResult captureScreenSurface(Surface& surfaceOut) override;
- virtual InputLayout* createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount) override;
- virtual BindingState* createBindingState(const BindingState::Desc& bindingStateDesc) override;
- virtual ShaderProgram* createProgram(const ShaderProgram::Desc& desc) override;
+
virtual void* map(BufferResource* buffer, MapFlavor flavor) override;
virtual void unmap(BufferResource* buffer) override;
- virtual void setInputLayout(InputLayout* inputLayout) override;
+// virtual void setInputLayout(InputLayout* inputLayout) override;
virtual void setPrimitiveTopology(PrimitiveTopology topology) override;
- virtual void setBindingState(BindingState* state);
+
+ virtual void setDescriptorSet(PipelineType pipelineType, PipelineLayout* layout, UInt index, DescriptorSet* descriptorSet) override;
+
virtual void setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) override;
- virtual void setShaderProgram(ShaderProgram* inProgram) override;
+ virtual void setIndexBuffer(BufferResource* buffer, Format indexFormat, UInt offset) override;
+ virtual void setDepthStencilTarget(ResourceView* depthStencilView) override;
+ virtual void setPipelineState(PipelineType pipelineType, PipelineState* state) override;
virtual void draw(UInt vertexCount, UInt startVertex) override;
+ virtual void drawIndexed(UInt indexCount, UInt startIndex, UInt baseVertex) override;
virtual void dispatchCompute(int x, int y, int z) override;
virtual void submitGpuWork() override;
virtual void waitForGpu() override;
@@ -82,6 +102,9 @@ protected:
static const Int kMaxNumRenderFrames = 4;
static const Int kMaxNumRenderTargets = 3;
+ static const Int kMaxRTVCount = 8;
+ static const Int kMaxDescriptorSetCount = 16;
+
struct Submitter
{
virtual void setRootConstantBufferView(int index, D3D12_GPU_VIRTUAL_ADDRESS gpuBufferLocation) = 0;
@@ -153,11 +176,28 @@ protected:
static BackingStyle _calcResourceBackingStyle(Usage usage)
{
+ // Note: the D3D12 back-end has support for "versioning" of constant buffers,
+ // where the same logical `BufferResource` can actually point to different
+ // backing storage over its lifetime, to emulate the ability to modify the
+ // buffer contents as in D3D11, etc.
+ //
+ // The VK back-end doesn't have the same behavior, and it is difficult
+ // to both support this degree of flexibility *and* efficeintly exploit
+ // descriptor tables (since any table referencing the buffer would need
+ // to be updated when a new buffer "version" gets allocated).
+ //
+ // I'm choosing to disable this for now, and make all buffers be memory-backed,
+ // although this creates synchronization issues that we'll have to address
+ // next.
+
+ return BackingStyle::ResourceBacked;
+#if 0
switch (usage)
{
case Usage::ConstantBuffer: return BackingStyle::MemoryBacked;
default: return BackingStyle::ResourceBacked;
}
+#endif
}
BackingStyle m_backingStyle; ///< How the resource is 'backed' - either as a resource or cpu memory. Cpu memory is typically used for constant buffers.
@@ -183,6 +223,19 @@ protected:
D3D12Resource m_resource;
};
+ class SamplerStateImpl : public SamplerState
+ {
+ public:
+ D3D12_CPU_DESCRIPTOR_HANDLE m_cpuHandle;
+ };
+
+ class ResourceViewImpl : public ResourceView
+ {
+ public:
+ RefPtr<Resource> m_resource;
+ D3D12HostVisibleDescriptor m_descriptor;
+ };
+
class InputLayoutImpl: public InputLayout
{
public:
@@ -190,6 +243,7 @@ protected:
List<char> m_text; ///< Holds all strings to keep in scope
};
+#if 0
struct BindingDetail
{
int m_srvIndex = -1;
@@ -216,20 +270,99 @@ protected:
{}
List<BindingDetail> m_bindingDetails; ///< These match 1-1 to the bindings in the m_desc
-
- D3D12DescriptorHeap m_viewHeap; ///< Cbv, Srv, Uav
- D3D12DescriptorHeap m_samplerHeap; ///< Heap for samplers
};
+#endif
- class RenderState: public RefObject
+ class DescriptorSetLayoutImpl : public DescriptorSetLayout
{
- public:
- D3D12_PRIMITIVE_TOPOLOGY_TYPE m_primitiveTopologyType;
- RefPtr<BindingStateImpl> m_bindingState;
- RefPtr<InputLayoutImpl> m_inputLayout;
- RefPtr<ShaderProgramImpl> m_shaderProgram;
+ public:
+ struct RangeInfo
+ {
+ DescriptorSlotType type;
+ Int count;
+ Int arrayIndex;
+ };
+
+ List<RangeInfo> m_ranges;
+ List<D3D12_DESCRIPTOR_RANGE> m_dxRanges;
+ List<D3D12_ROOT_PARAMETER> m_dxRootParameters;
+
+ Int m_resourceCount;
+ Int m_samplerCount;
+ };
+
+ class PipelineLayoutImpl : public PipelineLayout
+ {
+ public:
ComPtr<ID3D12RootSignature> m_rootSignature;
+ UInt m_descriptorSetCount;
+ };
+
+ class DescriptorSetImpl : public DescriptorSet
+ {
+ public:
+ virtual void setConstantBuffer(UInt range, UInt index, BufferResource* buffer) override;
+ virtual void setResource(UInt range, UInt index, ResourceView* view) override;
+ virtual void setSampler(UInt range, UInt index, SamplerState* sampler) override;
+ virtual void setCombinedTextureSampler(
+ UInt range,
+ UInt index,
+ ResourceView* textureView,
+ SamplerState* sampler) override;
+
+ RefPtr<D3D12Renderer> m_renderer;
+ RefPtr<DescriptorSetLayoutImpl> m_layout;
+
+ D3D12DescriptorHeap* m_resourceHeap = nullptr;
+ D3D12DescriptorHeap* m_samplerHeap = nullptr;
+
+ Int m_resourceTable = 0;
+ Int m_samplerTable = 0;
+
+ // The following arrays are used to retain the relevant
+ // objects so that they will not be released while this
+ // descriptor-set is still alive.
+ //
+ // For the `m_resourceObjects` array, the values are either
+ // the relevant `ResourceViewImpl` for SRV/UAV slots, or
+ // a `BufferResourceImpl` for a CBV slot.
+ //
+ List<RefPtr<RefObject>> m_resourceObjects;
+ List<RefPtr<SamplerStateImpl>> m_samplerObjects;
+ };
+
+
+ // During command submission, we need all the descriptor tables that get
+ // used to come from a single heap (for each descritpor heap type).
+ //
+ // We will thus keep a single heap of each type that we hope will hold
+ // all the descriptors that actually get needed in a frame.
+ //
+ // TODO: we need an allocation policy to reallocate and resize these
+ // if/when we run out of space during a frame.
+ //
+ D3D12DescriptorHeap m_viewHeap; ///< Cbv, Srv, Uav
+ D3D12DescriptorHeap m_samplerHeap; ///< Heap for samplers
+
+ D3D12HostVisibleDescriptorAllocator m_rtvAllocator;
+ D3D12HostVisibleDescriptorAllocator m_dsvAllocator;
+
+ D3D12HostVisibleDescriptorAllocator m_viewAllocator;
+ D3D12HostVisibleDescriptorAllocator m_samplerAllocator;
+
+ // Space in the GPU-visible heaps is precious, so we will also keep
+ // around CPU-visible heaps for storing descriptors in a format
+ // that is ready for copying into the GPU-visible heaps as needed.
+ //
+ D3D12DescriptorHeap m_cpuViewHeap; ///< Cbv, Srv, Uav
+ D3D12DescriptorHeap m_cpuSamplerHeap; ///< Heap for samplers
+
+ class PipelineStateImpl : public PipelineState
+ {
+ public:
+ PipelineType m_pipelineType;
+ RefPtr<PipelineLayoutImpl> m_pipelineLayout;
ComPtr<ID3D12PipelineState> m_pipelineState;
};
@@ -240,6 +373,7 @@ protected:
int m_offset;
};
+#if 0
struct BindParameters
{
enum
@@ -261,6 +395,7 @@ protected:
D3D12_ROOT_PARAMETER m_parameters[kMaxParameters];
int m_paramIndex;
};
+#endif
struct GraphicsSubmitter : public Submitter
{
@@ -329,15 +464,16 @@ protected:
ID3D12GraphicsCommandList* getCommandList() const { return m_commandList; }
- RenderState* calcRenderState();
+// RenderState* calcRenderState();
+
/// From current bindings calculate the root signature and pipeline state
- Result calcGraphicsPipelineState(ComPtr<ID3D12RootSignature>& sigOut, ComPtr<ID3D12PipelineState>& pipelineStateOut);
- Result calcComputePipelineState(ComPtr<ID3D12RootSignature>& signatureOut, ComPtr<ID3D12PipelineState>& pipelineStateOut);
+// Result calcGraphicsPipelineState(ComPtr<ID3D12RootSignature>& sigOut, ComPtr<ID3D12PipelineState>& pipelineStateOut);
+// Result calcComputePipelineState(ComPtr<ID3D12RootSignature>& signatureOut, ComPtr<ID3D12PipelineState>& pipelineStateOut);
- Result _bindRenderState(RenderState* renderState, ID3D12GraphicsCommandList* commandList, Submitter* submitter);
+ Result _bindRenderState(PipelineStateImpl* pipelineStateImpl, ID3D12GraphicsCommandList* commandList, Submitter* submitter);
- Result _calcBindParameters(BindParameters& params);
- RenderState* findRenderState(PipelineType pipelineType);
+// Result _calcBindParameters(BindParameters& params);
+// RenderState* findRenderState(PipelineType pipelineType);
PFN_D3D12_SERIALIZE_ROOT_SIGNATURE m_D3D12SerializeRootSignature = nullptr;
@@ -347,9 +483,17 @@ protected:
List<BoundVertexBuffer> m_boundVertexBuffers;
- RefPtr<ShaderProgramImpl> m_boundShaderProgram;
- RefPtr<InputLayoutImpl> m_boundInputLayout;
- RefPtr<BindingStateImpl> m_boundBindingState;
+ RefPtr<BufferResourceImpl> m_boundIndexBuffer;
+ DXGI_FORMAT m_boundIndexFormat;
+ UINT m_boundIndexOffset;
+
+ RefPtr<PipelineStateImpl> m_currentPipelineState;
+
+// RefPtr<ShaderProgramImpl> m_boundShaderProgram;
+// RefPtr<InputLayoutImpl> m_boundInputLayout;
+
+// RefPtr<BindingStateImpl> m_boundBindingState;
+ RefPtr<DescriptorSetImpl> m_boundDescriptorSets[int(PipelineType::CountOf)][kMaxDescriptorSetCount];
DXGI_FORMAT m_targetFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
DXGI_FORMAT m_depthStencilFormat = DXGI_FORMAT_D24_UNORM_S8_UINT;
@@ -376,17 +520,17 @@ protected:
ComPtr<ID3D12Device> m_device;
ComPtr<IDXGISwapChain3> m_swapChain;
ComPtr<ID3D12CommandQueue> m_commandQueue;
- ComPtr<ID3D12DescriptorHeap> m_rtvHeap;
+// ComPtr<ID3D12DescriptorHeap> m_rtvHeap;
ComPtr<ID3D12GraphicsCommandList> m_commandList;
D3D12_RECT m_scissorRect = {};
- List<RefPtr<RenderState> > m_renderStates; ///< Holds list of all render state combinations
- RenderState* m_currentRenderState = nullptr; ///< The current combination
+// List<RefPtr<RenderState> > m_renderStates; ///< Holds list of all render state combinations
+// RenderState* m_currentRenderState = nullptr; ///< The current combination
UINT m_rtvDescriptorSize = 0;
- ComPtr<ID3D12DescriptorHeap> m_dsvHeap;
+// ComPtr<ID3D12DescriptorHeap> m_dsvHeap;
UINT m_dsvDescriptorSize = 0;
// Synchronization objects.
@@ -408,8 +552,8 @@ protected:
D3D12Resource m_backBufferResources[kMaxNumRenderTargets];
D3D12Resource m_renderTargetResources[kMaxNumRenderTargets];
- D3D12Resource m_depthStencil;
- D3D12_CPU_DESCRIPTOR_HANDLE m_depthStencilView = {};
+ RefPtr<ResourceViewImpl> m_rtvs[kMaxRTVCount];
+ RefPtr<ResourceViewImpl> m_dsv;
int32_t m_depthStencilUsageFlags = 0; ///< D3DUtil::UsageFlag combination for depth stencil
int32_t m_targetUsageFlags = 0; ///< D3DUtil::UsageFlag combination for target
@@ -615,15 +759,12 @@ void D3D12Renderer::_resetCommandList()
ID3D12GraphicsCommandList* commandList = getCommandList();
commandList->Reset(frame.m_commandAllocator, nullptr);
- D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = { m_rtvHeap->GetCPUDescriptorHandleForHeapStart().ptr + m_renderTargetIndex * m_rtvDescriptorSize };
- if (m_depthStencil)
- {
- commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, &m_depthStencilView);
- }
- else
- {
- commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr);
- }
+ // TIM: when should this get set?
+// commandList->OMSetRenderTargets(
+// 1,
+// &m_rtvs[0]->m_descriptor.cpuHandle,
+// FALSE,
+// m_dsv ? &m_dsv->m_descriptor.cpuHandle : nullptr);
// Set necessary state.
commandList->RSSetViewports(1, &m_viewport);
@@ -797,6 +938,7 @@ Result D3D12Renderer::captureTextureToSurface(D3D12Resource& resource, Surface&
}
}
+#if 0
Result D3D12Renderer::calcComputePipelineState(ComPtr<ID3D12RootSignature>& signatureOut, ComPtr<ID3D12PipelineState>& pipelineStateOut)
{
BindParameters bindParameters;
@@ -832,123 +974,9 @@ Result D3D12Renderer::calcComputePipelineState(ComPtr<ID3D12RootSignature>& sign
return SLANG_OK;
}
+#endif
-Result D3D12Renderer::calcGraphicsPipelineState(ComPtr<ID3D12RootSignature>& signatureOut, ComPtr<ID3D12PipelineState>& pipelineStateOut)
-{
- BindParameters bindParameters;
- _calcBindParameters(bindParameters);
-
- ComPtr<ID3D12RootSignature> rootSignature;
- ComPtr<ID3D12PipelineState> pipelineState;
-
- {
- // Deny unnecessary access to certain pipeline stages
- D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc;
- rootSignatureDesc.NumParameters = bindParameters.m_paramIndex;
- rootSignatureDesc.pParameters = bindParameters.m_parameters;
- rootSignatureDesc.NumStaticSamplers = 0;
- rootSignatureDesc.pStaticSamplers = nullptr;
- rootSignatureDesc.Flags = m_boundInputLayout ? D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT : D3D12_ROOT_SIGNATURE_FLAG_NONE;
-
- ComPtr<ID3DBlob> signature;
- ComPtr<ID3DBlob> error;
- SLANG_RETURN_ON_FAIL(m_D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, signature.writeRef(), error.writeRef()));
- SLANG_RETURN_ON_FAIL(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(rootSignature.writeRef())));
- }
-
- {
- // Describe and create the graphics pipeline state object (PSO)
- D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
-
- psoDesc.pRootSignature = rootSignature;
-
- psoDesc.VS = { m_boundShaderProgram->m_vertexShader.Buffer(), m_boundShaderProgram->m_vertexShader.Count() };
- psoDesc.PS = { m_boundShaderProgram->m_pixelShader.Buffer(), m_boundShaderProgram->m_pixelShader.Count() };
-
- {
- psoDesc.InputLayout = { m_boundInputLayout->m_elements.Buffer(), UINT(m_boundInputLayout->m_elements.Count()) };
- psoDesc.PrimitiveTopologyType = m_primitiveTopologyType;
-
- {
- const int numRenderTargets = m_boundBindingState ? m_boundBindingState->getDesc().m_numRenderTargets : 1;
-
- psoDesc.DSVFormat = m_depthStencilFormat;
- psoDesc.NumRenderTargets = numRenderTargets;
- for (Int i = 0; i < numRenderTargets; i++)
- {
- psoDesc.RTVFormats[i] = m_targetFormat;
- }
-
- psoDesc.SampleDesc.Count = 1;
- psoDesc.SampleDesc.Quality = 0;
-
- psoDesc.SampleMask = UINT_MAX;
- }
-
- {
- auto& rs = psoDesc.RasterizerState;
- rs.FillMode = D3D12_FILL_MODE_SOLID;
- rs.CullMode = D3D12_CULL_MODE_NONE;
- rs.FrontCounterClockwise = FALSE;
- rs.DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
- rs.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
- rs.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
- rs.DepthClipEnable = TRUE;
- rs.MultisampleEnable = FALSE;
- rs.AntialiasedLineEnable = FALSE;
- rs.ForcedSampleCount = 0;
- rs.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
- }
-
- {
- D3D12_BLEND_DESC& blend = psoDesc.BlendState;
-
- blend.AlphaToCoverageEnable = FALSE;
- blend.IndependentBlendEnable = FALSE;
- const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc =
- {
- FALSE,FALSE,
- D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD,
- D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD,
- D3D12_LOGIC_OP_NOOP,
- D3D12_COLOR_WRITE_ENABLE_ALL,
- };
- for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i)
- {
- blend.RenderTarget[i] = defaultRenderTargetBlendDesc;
- }
- }
-
- {
- auto& ds = psoDesc.DepthStencilState;
-
- ds.DepthEnable = FALSE;
- ds.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
- ds.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
- //ds.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
- ds.StencilEnable = FALSE;
- ds.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK;
- ds.StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK;
- const D3D12_DEPTH_STENCILOP_DESC defaultStencilOp =
- {
- D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_COMPARISON_FUNC_ALWAYS
- };
- ds.FrontFace = defaultStencilOp;
- ds.BackFace = defaultStencilOp;
- }
- }
-
- psoDesc.PrimitiveTopologyType = m_primitiveTopologyType;
-
- SLANG_RETURN_ON_FAIL(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(pipelineState.writeRef())));
- }
-
- signatureOut.swap(rootSignature);
- pipelineStateOut.swap(pipelineState);
-
- return SLANG_OK;
-}
-
+#if 0
D3D12Renderer::RenderState* D3D12Renderer::findRenderState(PipelineType pipelineType)
{
switch (pipelineType)
@@ -1172,72 +1200,74 @@ Result D3D12Renderer::_calcBindParameters(BindParameters& params)
}
return SLANG_OK;
}
+#endif
-Result D3D12Renderer::_bindRenderState(RenderState* renderState, ID3D12GraphicsCommandList* commandList, Submitter* submitter)
+Result D3D12Renderer::_bindRenderState(PipelineStateImpl* pipelineStateImpl, ID3D12GraphicsCommandList* commandList, Submitter* submitter)
{
- BindingStateImpl* bindingState = m_boundBindingState;
+ // TODO: we should only set some of this state as needed...
- submitter->setRootSignature(renderState->m_rootSignature);
- commandList->SetPipelineState(renderState->m_pipelineState);
+ auto pipelineTypeIndex = (int) pipelineStateImpl->m_pipelineType;
+ auto pipelineLayout = pipelineStateImpl->m_pipelineLayout;
- if (bindingState)
- {
- ID3D12DescriptorHeap* heaps[] =
- {
- bindingState->m_viewHeap.getHeap(),
- bindingState->m_samplerHeap.getHeap(),
- };
- commandList->SetDescriptorHeaps(SLANG_COUNT_OF(heaps), heaps);
- }
- else
+ submitter->setRootSignature(pipelineLayout->m_rootSignature);
+ commandList->SetPipelineState(pipelineStateImpl->m_pipelineState);
+
+ ID3D12DescriptorHeap* heaps[] =
{
- commandList->SetDescriptorHeaps(0, nullptr);
- }
+ m_viewHeap.getHeap(),
+ m_samplerHeap.getHeap(),
+ };
+ commandList->SetDescriptorHeaps(SLANG_COUNT_OF(heaps), heaps);
+
+ // We need to copy descriptors over from the descriptor sets
+ // (where they are stored in CPU-visible heaps) to the GPU-visible
+ // heaps so that they can be accessed by shader code.
+ Int descriptorSetCount = pipelineLayout->m_descriptorSetCount;
+ Int rootParameterIndex = 0;
+ for(Int dd = 0; dd < descriptorSetCount; ++dd)
{
- int index = 0;
+ auto descriptorSet = m_boundDescriptorSets[pipelineTypeIndex][dd];
+ auto descriptorSetLayout = descriptorSet->m_layout;
+
+ // TODO: require that `descriptorSetLayout` is compatible with
+ // `pipelineLayout->descriptorSetlayouts[dd]`.
- int numConstantBuffers = 0;
{
- if (bindingState)
+ if(auto descriptorCount = descriptorSetLayout->m_resourceCount)
{
- D3D12DescriptorHeap& heap = bindingState->m_viewHeap;
- const auto& details = bindingState->m_bindingDetails;
- const auto& bindings = bindingState->getDesc().m_bindings;
- const int numBindings = int(details.Count());
+ auto& gpuHeap = m_viewHeap;
+ auto gpuDescriptorTable = gpuHeap.allocate(descriptorCount);
- for (int i = 0; i < numBindings; i++)
- {
- const auto& detail = details[i];
- const auto& binding = bindings[i];
+ auto& cpuHeap = *descriptorSet->m_resourceHeap;
+ auto cpuDescriptorTable = descriptorSet->m_resourceTable;
- if (binding.bindingType == BindingType::Buffer)
- {
- assert(binding.resource && binding.resource->isBuffer());
- if (binding.resource->canBind(Resource::BindFlag::ConstantBuffer))
- {
- BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(binding.resource.Ptr());
- buffer->bindConstantBufferView(m_circularResourceHeap, index++, submitter);
- numConstantBuffers++;
- }
- }
+ m_device->CopyDescriptorsSimple(
+ descriptorCount,
+ gpuHeap.getCpuHandle(gpuDescriptorTable),
+ cpuHeap.getCpuHandle(cpuDescriptorTable),
+ D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
- if (detail.m_srvIndex >= 0)
- {
- submitter->setRootDescriptorTable(index++, heap.getGpuHandle(detail.m_srvIndex));
- }
-
- if (detail.m_uavIndex >= 0)
- {
- submitter->setRootDescriptorTable(index++, heap.getGpuHandle(detail.m_uavIndex));
- }
- }
+ submitter->setRootDescriptorTable(rootParameterIndex++, gpuHeap.getGpuHandle(gpuDescriptorTable));
}
}
-
- if (bindingState && bindingState->m_samplerHeap.getUsedSize() > 0)
{
- submitter->setRootDescriptorTable(index, bindingState->m_samplerHeap.getGpuStart());
+ if(auto descriptorCount = descriptorSetLayout->m_samplerCount)
+ {
+ auto& gpuHeap = m_samplerHeap;
+ auto gpuDescriptorTable = gpuHeap.allocate(descriptorCount);
+
+ auto& cpuHeap = *descriptorSet->m_samplerHeap;
+ auto cpuDescriptorTable = descriptorSet->m_samplerTable;
+
+ m_device->CopyDescriptorsSimple(
+ descriptorCount,
+ gpuHeap.getCpuHandle(gpuDescriptorTable),
+ cpuHeap.getCpuHandle(cpuDescriptorTable),
+ D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
+
+ submitter->setRootDescriptorTable(rootParameterIndex++, gpuHeap.getGpuHandle(gpuDescriptorTable));
+ }
}
}
@@ -1339,9 +1369,15 @@ Result D3D12Renderer::initialize(const Desc& desc, void* inWindowHandle)
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(m_device.writeRef()))))
+ else
+ {
+ continue;
+ }
+
+ if (SUCCEEDED(D3D12CreateDevice_(candidateAdapter, featureLevel, IID_PPV_ARGS(m_device.writeRef()))))
{
// We found one!
adapter = candidateAdapter;
@@ -1356,6 +1392,27 @@ Result D3D12Renderer::initialize(const Desc& desc, void* inWindowHandle)
return SLANG_FAIL;
}
+ // set up debug layer
+#ifndef NDEBUG
+ {
+
+ LOAD_D3D_PROC(PFN_D3D12_GET_DEBUG_INTERFACE, D3D12GetDebugInterface);
+ if (!D3D12GetDebugInterface_)
+ {
+ return SLANG_FAIL;
+ }
+
+ ComPtr<ID3D12Debug> debug;
+
+ if (!SUCCEEDED(D3D12GetDebugInterface_(IID_PPV_ARGS(debug.writeRef()))))
+ {
+ return SLANG_FAIL;
+ }
+
+ debug->EnableDebugLayer();
+ }
+#endif
+
m_numRenderFrames = 3;
m_numRenderTargets = 2;
@@ -1432,27 +1489,17 @@ Result D3D12Renderer::initialize(const Desc& desc, void* inWindowHandle)
m_renderTargetIndex = m_swapChain->GetCurrentBackBufferIndex();
// Create descriptor heaps.
- {
- // Describe and create a render target view (RTV) descriptor heap.
- D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {};
- rtvHeapDesc.NumDescriptors = m_numRenderTargets;
- rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
- rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
- SLANG_RETURN_ON_FAIL(m_device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(m_rtvHeap.writeRef())));
- m_rtvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
- }
+ SLANG_RETURN_ON_FAIL(m_viewHeap.init (m_device, 256, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE));
+ SLANG_RETURN_ON_FAIL(m_samplerHeap.init(m_device, 16, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE));
- {
- // Describe and create a depth stencil view (DSV) descriptor heap.
- D3D12_DESCRIPTOR_HEAP_DESC dsvHeapDesc = {};
- dsvHeapDesc.NumDescriptors = 1;
- dsvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
- dsvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
- SLANG_RETURN_ON_FAIL(m_device->CreateDescriptorHeap(&dsvHeapDesc, IID_PPV_ARGS(m_dsvHeap.writeRef())));
+ SLANG_RETURN_ON_FAIL(m_cpuViewHeap.init (m_device, 1024, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE));
+ SLANG_RETURN_ON_FAIL(m_cpuSamplerHeap.init(m_device, 64, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, D3D12_DESCRIPTOR_HEAP_FLAG_NONE));
- m_dsvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
- }
+ SLANG_RETURN_ON_FAIL(m_rtvAllocator.init (m_device, 16, D3D12_DESCRIPTOR_HEAP_TYPE_RTV));
+ SLANG_RETURN_ON_FAIL(m_dsvAllocator.init (m_device, 16, D3D12_DESCRIPTOR_HEAP_TYPE_DSV));
+ SLANG_RETURN_ON_FAIL(m_viewAllocator.init (m_device, 64, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV));
+ SLANG_RETURN_ON_FAIL(m_samplerAllocator.init(m_device, 16, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER));
// Setup frame resources
{
@@ -1488,7 +1535,7 @@ Result D3D12Renderer::createFrameResources()
{
// Create back buffers
{
- D3D12_CPU_DESCRIPTOR_HANDLE rtvStart(m_rtvHeap->GetCPUDescriptorHandleForHeapStart());
+// D3D12_CPU_DESCRIPTOR_HANDLE rtvStart(m_rtvHeap->GetCPUDescriptorHandleForHeapStart());
// Work out target format
D3D12_RESOURCE_DESC resourceDesc;
@@ -1543,8 +1590,10 @@ Result D3D12Renderer::createFrameResources()
m_renderTargets[i] = &m_renderTargetResources[i];
}
- D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = { rtvStart.ptr + i * m_rtvDescriptorSize };
- m_device->CreateRenderTargetView(*m_renderTargets[i], nullptr, rtvHandle);
+ D3D12HostVisibleDescriptor rtvDescriptor;
+ SLANG_RETURN_ON_FAIL(m_rtvAllocator.allocate(&rtvDescriptor));
+
+ m_device->CreateRenderTargetView(*m_renderTargets[i], nullptr, rtvDescriptor.cpuHandle);
}
}
@@ -1594,6 +1643,7 @@ Result D3D12Renderer::createFrameResources()
resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
resourceDesc.Alignment = 0;
+#if 0
SLANG_RETURN_ON_FAIL(m_depthStencil.initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, resourceDesc, D3D12_RESOURCE_STATE_DEPTH_WRITE, &clearValue));
// Set the depth stencil
@@ -1605,6 +1655,7 @@ Result D3D12Renderer::createFrameResources()
// Set up as the depth stencil view
m_device->CreateDepthStencilView(m_depthStencil, &depthStencilDesc, m_dsvHeap->GetCPUDescriptorHandleForHeapStart());
m_depthStencilView = m_dsvHeap->GetCPUDescriptorHandleForHeapStart();
+#endif
}
m_viewport.Width = static_cast<float>(m_desc.width);
@@ -1625,11 +1676,13 @@ void D3D12Renderer::setClearColor(const float color[4])
void D3D12Renderer::clearFrame()
{
// Record commands
- D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = { m_rtvHeap->GetCPUDescriptorHandleForHeapStart().ptr + m_renderTargetIndex * m_rtvDescriptorSize };
- m_commandList->ClearRenderTargetView(rtvHandle, m_clearColor, 0, nullptr);
- if (m_depthStencil)
+ if(auto rtv = m_rtvs[0])
+ {
+ m_commandList->ClearRenderTargetView(rtv->m_descriptor.cpuHandle, m_clearColor, 0, nullptr);
+ }
+ if (m_dsv)
{
- m_commandList->ClearDepthStencilView(m_depthStencilView, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr);
+ m_commandList->ClearDepthStencilView(m_dsv->m_descriptor.cpuHandle, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr);
}
}
@@ -1677,6 +1730,14 @@ void D3D12Renderer::presentFrame()
beginRender();
}
+TextureResource::Desc D3D12Renderer::getSwapChainTextureDesc()
+{
+ TextureResource::Desc desc;
+ desc.init2D(Resource::Type::Texture2D, Format::Unknown, m_desc.width, m_desc.height, 1);
+
+ return desc;
+}
+
SlangResult D3D12Renderer::captureScreenSurface(Surface& surfaceOut)
{
return captureTextureToSurface(*m_renderTargets[m_renderTargetIndex], surfaceOut);
@@ -1743,7 +1804,7 @@ static D3D12_RESOURCE_DIMENSION _calcResourceDimension(Resource::Type type)
}
}
-TextureResource* D3D12Renderer::createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& descIn, const TextureResource::Data* initData)
+Result D3D12Renderer::createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& descIn, const TextureResource::Data* initData, TextureResource** outResource)
{
// Description of uploading on Dx12
// https://msdn.microsoft.com/en-us/library/windows/desktop/dn899215%28v=vs.85%29.aspx
@@ -1754,7 +1815,7 @@ TextureResource* D3D12Renderer::createTextureResource(Resource::Usage initialUsa
const DXGI_FORMAT pixelFormat = D3DUtil::getMapFormat(srcDesc.format);
if (pixelFormat == DXGI_FORMAT_UNKNOWN)
{
- return nullptr;
+ return SLANG_FAIL;
}
const int arraySize = srcDesc.calcEffectiveArraySize();
@@ -1762,7 +1823,7 @@ TextureResource* D3D12Renderer::createTextureResource(Resource::Usage initialUsa
const D3D12_RESOURCE_DIMENSION dimension = _calcResourceDimension(srcDesc.type);
if (dimension == D3D12_RESOURCE_DIMENSION_UNKNOWN)
{
- return nullptr;
+ return SLANG_FAIL;
}
const int numMipMaps = srcDesc.numMipLevels;
@@ -1796,7 +1857,7 @@ TextureResource* D3D12Renderer::createTextureResource(Resource::Usage initialUsa
heapProps.CreationNodeMask = 1;
heapProps.VisibleNodeMask = 1;
- SLANG_RETURN_NULL_ON_FAIL(texture->m_resource.initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, resourceDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr));
+ SLANG_RETURN_ON_FAIL(texture->m_resource.initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, resourceDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr));
texture->m_resource.setDebugName(L"Texture");
}
@@ -1849,7 +1910,7 @@ TextureResource* D3D12Renderer::createTextureResource(Resource::Usage initialUsa
uploadResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
uploadResourceDesc.Alignment = 0;
- SLANG_RETURN_NULL_ON_FAIL(uploadTexture.initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, uploadResourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr));
+ SLANG_RETURN_ON_FAIL(uploadTexture.initCommitted(m_device, heapProps, D3D12_HEAP_FLAG_NONE, uploadResourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr));
uploadTexture.setDebugName(L"TextureUpload");
}
@@ -1911,35 +1972,42 @@ TextureResource* D3D12Renderer::createTextureResource(Resource::Usage initialUsa
subResourceIndex++;
}
- {
- // const D3D12_RESOURCE_STATES finalState = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
- const D3D12_RESOURCE_STATES finalState = _calcResourceState(initialUsage);
+ // Block - waiting for copy to complete (so can drop upload texture)
+ submitGpuWorkAndWait();
+ }
- D3D12BarrierSubmitter submitter(m_commandList);
- texture->m_resource.transition(finalState, submitter);
- }
+ {
+ const D3D12_RESOURCE_STATES finalState = _calcResourceState(initialUsage);
+ D3D12BarrierSubmitter submitter(m_commandList);
+ texture->m_resource.transition(finalState, submitter);
- // Block - waiting for copy to complete (so can drop upload texture)
submitGpuWorkAndWait();
}
- return texture.detach();
+ *outResource = texture.detach();
+ return SLANG_OK;
}
-BufferResource* D3D12Renderer::createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& descIn, const void* initData)
+Result D3D12Renderer::createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& descIn, const void* initData, BufferResource** outResource)
{
typedef BufferResourceImpl::BackingStyle Style;
BufferResource::Desc srcDesc(descIn);
srcDesc.setDefaults(initialUsage);
+ // Always align up to 256 bytes, since that is required for constant buffers.
+ //
+ // TODO: only do this for buffers that could potentially be bound as constant buffers...
+ //
+ const size_t alignedSizeInBytes = D3DUtil::calcAligned(srcDesc.sizeInBytes, 256);
+
RefPtr<BufferResourceImpl> buffer(new BufferResourceImpl(initialUsage, srcDesc));
// Save the style
buffer->m_backingStyle = BufferResourceImpl::_calcResourceBackingStyle(initialUsage);
D3D12_RESOURCE_DESC bufferDesc;
- _initBufferResourceDesc(srcDesc.sizeInBytes, bufferDesc);
+ _initBufferResourceDesc(alignedSizeInBytes, bufferDesc);
bufferDesc.Flags = _calcResourceBindFlags(initialUsage, srcDesc.bindFlags);
@@ -1949,7 +2017,7 @@ BufferResource* D3D12Renderer::createBufferResource(Resource::Usage initialUsage
{
// Assume the constant buffer will change every frame. We'll just keep a copy of the contents
// in regular memory until it needed
- buffer->m_memory.SetSize(UInt(srcDesc.sizeInBytes));
+ buffer->m_memory.SetSize(UInt(alignedSizeInBytes));
// Initialize
if (initData)
{
@@ -1960,16 +2028,268 @@ BufferResource* D3D12Renderer::createBufferResource(Resource::Usage initialUsage
case Style::ResourceBacked:
{
const D3D12_RESOURCE_STATES initialState = _calcResourceState(initialUsage);
- SLANG_RETURN_NULL_ON_FAIL(createBuffer(bufferDesc, initData, buffer->m_uploadResource, initialState, buffer->m_resource));
+ SLANG_RETURN_ON_FAIL(createBuffer(bufferDesc, initData, buffer->m_uploadResource, initialState, buffer->m_resource));
break;
}
- default: return nullptr;
+ default:
+ return SLANG_FAIL;
+ }
+
+ *outResource = buffer.detach();
+ return SLANG_OK;
+}
+
+D3D12_FILTER_TYPE translateFilterMode(TextureFilteringMode mode)
+{
+ switch (mode)
+ {
+ default:
+ return D3D12_FILTER_TYPE(0);
+
+#define CASE(SRC, DST) \
+ case TextureFilteringMode::SRC: return D3D12_FILTER_TYPE_##DST
+
+ CASE(Point, POINT);
+ CASE(Linear, LINEAR);
+
+#undef CASE
+ }
+}
+
+D3D12_FILTER_REDUCTION_TYPE translateFilterReduction(TextureReductionOp op)
+{
+ switch (op)
+ {
+ default:
+ return D3D12_FILTER_REDUCTION_TYPE(0);
+
+#define CASE(SRC, DST) \
+ case TextureReductionOp::SRC: return D3D12_FILTER_REDUCTION_TYPE_##DST
+
+ CASE(Average, STANDARD);
+ CASE(Comparison, COMPARISON);
+ CASE(Minimum, MINIMUM);
+ CASE(Maximum, MAXIMUM);
+
+#undef CASE
+ }
+}
+
+D3D12_TEXTURE_ADDRESS_MODE translateAddressingMode(TextureAddressingMode mode)
+{
+ switch (mode)
+ {
+ default:
+ return D3D12_TEXTURE_ADDRESS_MODE(0);
+
+#define CASE(SRC, DST) \
+ case TextureAddressingMode::SRC: return D3D12_TEXTURE_ADDRESS_MODE_##DST
+
+ CASE(Wrap, WRAP);
+ CASE(ClampToEdge, CLAMP);
+ CASE(ClampToBorder, BORDER);
+ CASE(MirrorRepeat, MIRROR);
+ CASE(MirrorOnce, MIRROR_ONCE);
+
+#undef CASE
+ }
+}
+
+static D3D12_COMPARISON_FUNC translateComparisonFunc(ComparisonFunc func)
+{
+ switch (func)
+ {
+ default:
+ // TODO: need to report failures
+ return D3D12_COMPARISON_FUNC_ALWAYS;
+
+#define CASE(FROM, TO) \
+ case ComparisonFunc::FROM: return D3D12_COMPARISON_FUNC_##TO
+
+ CASE(Never, NEVER);
+ CASE(Less, LESS);
+ CASE(Equal, EQUAL);
+ CASE(LessEqual, LESS_EQUAL);
+ CASE(Greater, GREATER);
+ CASE(NotEqual, NOT_EQUAL);
+ CASE(GreaterEqual, GREATER_EQUAL);
+ CASE(Always, ALWAYS);
+#undef CASE
+ }
+}
+
+Result D3D12Renderer::createSamplerState(SamplerState::Desc const& desc, SamplerState** outSampler)
+{
+ D3D12_FILTER_REDUCTION_TYPE dxReduction = translateFilterReduction(desc.reductionOp);
+ D3D12_FILTER dxFilter;
+ if (desc.maxAnisotropy > 1)
+ {
+ dxFilter = D3D12_ENCODE_ANISOTROPIC_FILTER(dxReduction);
+ }
+ else
+ {
+ D3D12_FILTER_TYPE dxMin = translateFilterMode(desc.minFilter);
+ D3D12_FILTER_TYPE dxMag = translateFilterMode(desc.magFilter);
+ D3D12_FILTER_TYPE dxMip = translateFilterMode(desc.mipFilter);
+
+ dxFilter = D3D12_ENCODE_BASIC_FILTER(dxMin, dxMag, dxMip, dxReduction);
+ }
+
+ D3D12_SAMPLER_DESC dxDesc = {};
+ dxDesc.Filter = dxFilter;
+ dxDesc.AddressU = translateAddressingMode(desc.addressU);
+ dxDesc.AddressV = translateAddressingMode(desc.addressV);
+ dxDesc.AddressW = translateAddressingMode(desc.addressW);
+ dxDesc.MipLODBias = desc.mipLODBias;
+ dxDesc.MaxAnisotropy = desc.maxAnisotropy;
+ dxDesc.ComparisonFunc = translateComparisonFunc(desc.comparisonFunc);
+ for (int ii = 0; ii < 4; ++ii)
+ dxDesc.BorderColor[ii] = desc.borderColor[ii];
+ dxDesc.MinLOD = desc.minLOD;
+ dxDesc.MaxLOD = desc.maxLOD;
+
+ auto samplerHeap = &m_cpuSamplerHeap;
+
+ int indexInSamplerHeap = samplerHeap->allocate();
+ if(indexInSamplerHeap < 0)
+ {
+ // We ran out of room in our CPU sampler heap.
+ //
+ // TODO: this should not be a catastrophic failure, because
+ // we should just allocate another CPU sampler heap that
+ // can service subsequent allocation.
+ //
+ return SLANG_FAIL;
+ }
+ auto cpuDescriptorHandle = samplerHeap->getCpuHandle(indexInSamplerHeap);
+
+ m_device->CreateSampler(&dxDesc, cpuDescriptorHandle);
+
+ // TODO: We really ought to have a free-list of sampler-heap
+ // entries that we check before we go to the heap, and then
+ // when we are done with a sampler we simply add it to the free list.
+ //
+ RefPtr<SamplerStateImpl> samplerImpl = new SamplerStateImpl();
+ samplerImpl->m_cpuHandle = cpuDescriptorHandle;
+ *outSampler = samplerImpl.detach();
+ return SLANG_OK;
+}
+
+Result D3D12Renderer::createTextureView(TextureResource* texture, ResourceView::Desc const& desc, ResourceView** outView)
+{
+ auto resourceImpl = (TextureResourceImpl*) texture;
+
+ RefPtr<ResourceViewImpl> viewImpl = new ResourceViewImpl();
+ viewImpl->m_resource = resourceImpl;
+
+ switch (desc.type)
+ {
+ default:
+ return SLANG_FAIL;
+
+ case ResourceView::Type::RenderTarget:
+ {
+ SLANG_RETURN_ON_FAIL(m_rtvAllocator.allocate(&viewImpl->m_descriptor));
+ m_device->CreateRenderTargetView(resourceImpl->m_resource, nullptr, viewImpl->m_descriptor.cpuHandle);
+ }
+ break;
+
+ case ResourceView::Type::DepthStencil:
+ {
+ SLANG_RETURN_ON_FAIL(m_dsvAllocator.allocate(&viewImpl->m_descriptor));
+ m_device->CreateDepthStencilView(resourceImpl->m_resource, nullptr, viewImpl->m_descriptor.cpuHandle);
+ }
+ break;
+
+ case ResourceView::Type::UnorderedAccess:
+ {
+ // TODO: need to support the separate "counter resource" for the case
+ // of append/consume buffers with attached counters.
+
+ SLANG_RETURN_ON_FAIL(m_viewAllocator.allocate(&viewImpl->m_descriptor));
+ m_device->CreateUnorderedAccessView(resourceImpl->m_resource, nullptr, nullptr, viewImpl->m_descriptor.cpuHandle);
+ }
+ break;
+
+ case ResourceView::Type::ShaderResource:
+ {
+ SLANG_RETURN_ON_FAIL(m_viewAllocator.allocate(&viewImpl->m_descriptor));
+ m_device->CreateShaderResourceView(resourceImpl->m_resource, nullptr, viewImpl->m_descriptor.cpuHandle);
+ }
+ break;
}
- return buffer.detach();
+ *outView = viewImpl.detach();
+ return SLANG_OK;
+}
+
+Result D3D12Renderer::createBufferView(BufferResource* buffer, ResourceView::Desc const& desc, ResourceView** outView)
+{
+ auto resourceImpl = (BufferResourceImpl*) buffer;
+ auto resourceDesc = resourceImpl->getDesc();
+
+ RefPtr<ResourceViewImpl> viewImpl = new ResourceViewImpl();
+ viewImpl->m_resource = resourceImpl;
+
+ switch (desc.type)
+ {
+ default:
+ return SLANG_FAIL;
+
+ case ResourceView::Type::UnorderedAccess:
+ {
+ D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
+ uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
+ uavDesc.Format = D3DUtil::getMapFormat(desc.format);
+ uavDesc.Buffer.FirstElement = 0;
+ uavDesc.Buffer.NumElements = resourceDesc.sizeInBytes;
+
+ if(resourceDesc.elementSize)
+ {
+ uavDesc.Buffer.StructureByteStride = resourceDesc.elementSize;
+ uavDesc.Buffer.NumElements = resourceDesc.sizeInBytes / resourceDesc.elementSize;
+ }
+ else if(desc.format == Format::Unknown)
+ {
+ uavDesc.Buffer.Flags |= D3D12_BUFFER_UAV_FLAG_RAW;
+ uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
+ }
+
+
+ // TODO: need to support the separate "counter resource" for the case
+ // of append/consume buffers with attached counters.
+
+ SLANG_RETURN_ON_FAIL(m_viewAllocator.allocate(&viewImpl->m_descriptor));
+ m_device->CreateUnorderedAccessView(resourceImpl->m_resource, nullptr, &uavDesc, viewImpl->m_descriptor.cpuHandle);
+ }
+ break;
+
+ case ResourceView::Type::ShaderResource:
+ {
+ D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
+ srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
+ srvDesc.Format = D3DUtil::getMapFormat(desc.format);
+ srvDesc.Buffer.StructureByteStride = 0;
+ srvDesc.Buffer.FirstElement = 0;
+ srvDesc.Buffer.NumElements = resourceDesc.sizeInBytes;
+
+ if(resourceDesc.elementSize)
+ {
+ srvDesc.Buffer.StructureByteStride = resourceDesc.elementSize;
+ srvDesc.Buffer.NumElements = resourceDesc.sizeInBytes / resourceDesc.elementSize;
+ }
+
+ SLANG_RETURN_ON_FAIL(m_viewAllocator.allocate(&viewImpl->m_descriptor));
+ m_device->CreateShaderResourceView(resourceImpl->m_resource, &srvDesc, viewImpl->m_descriptor.cpuHandle);
+ }
+ break;
+ }
+
+ *outView = viewImpl.detach();
+ return SLANG_OK;
}
-InputLayout* D3D12Renderer::createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount)
+Result D3D12Renderer::createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount, InputLayout** outLayout)
{
RefPtr<InputLayoutImpl> layout(new InputLayoutImpl);
@@ -2012,7 +2332,8 @@ InputLayout* D3D12Renderer::createInputLayout(const InputElementDesc* inputEleme
dstEle.InstanceDataStepRate = 0;
}
- return layout.detach();
+ *outLayout = layout.detach();
+ return SLANG_OK;
}
void* D3D12Renderer::map(BufferResource* bufferIn, MapFlavor flavor)
@@ -2164,10 +2485,12 @@ void D3D12Renderer::unmap(BufferResource* bufferIn)
}
}
+#if 0
void D3D12Renderer::setInputLayout(InputLayout* inputLayout)
{
m_boundInputLayout = static_cast<InputLayoutImpl*>(inputLayout);
}
+#endif
void D3D12Renderer::setPrimitiveTopology(PrimitiveTopology topology)
{
@@ -2211,28 +2534,37 @@ void D3D12Renderer::setVertexBuffers(UInt startSlot, UInt slotCount, BufferResou
}
}
-void D3D12Renderer::setShaderProgram(ShaderProgram* inProgram)
+void D3D12Renderer::setIndexBuffer(BufferResource* buffer, Format indexFormat, UInt offset)
+{
+ m_boundIndexBuffer = (BufferResourceImpl*) buffer;
+ m_boundIndexFormat = D3DUtil::getMapFormat(indexFormat);
+ m_boundIndexOffset = offset;
+}
+
+void D3D12Renderer::setDepthStencilTarget(ResourceView* depthStencilView)
{
- m_boundShaderProgram = static_cast<ShaderProgramImpl*>(inProgram);
+}
+
+void D3D12Renderer::setPipelineState(PipelineType pipelineType, PipelineState* state)
+{
+ m_currentPipelineState = (PipelineStateImpl*)state;
}
void D3D12Renderer::draw(UInt vertexCount, UInt startVertex)
{
ID3D12GraphicsCommandList* commandList = m_commandList;
- RenderState* renderState = calcRenderState();
- if (!renderState)
+ auto pipelineState = m_currentPipelineState.Ptr();
+ if (!pipelineState || (pipelineState->m_pipelineType != PipelineType::Graphics))
{
- assert(!"Couldn't create render state");
+ assert(!"No graphics pipeline state set");
return;
}
- BindingStateImpl* bindingState = m_boundBindingState;
-
// Submit - setting for graphics
{
GraphicsSubmitter submitter(commandList);
- _bindRenderState(renderState, commandList, &submitter);
+ _bindRenderState(pipelineState, commandList, &submitter);
}
commandList->IASetPrimitiveTopology(m_primitiveTopology);
@@ -2248,31 +2580,49 @@ void D3D12Renderer::draw(UInt vertexCount, UInt startVertex)
if (buffer)
{
D3D12_VERTEX_BUFFER_VIEW& vertexView = vertexViews[numVertexViews++];
- vertexView.BufferLocation = buffer->m_resource.getResource()->GetGPUVirtualAddress();
- vertexView.SizeInBytes = int(buffer->getDesc().sizeInBytes);
+ vertexView.BufferLocation = buffer->m_resource.getResource()->GetGPUVirtualAddress()
+ + boundVertexBuffer.m_offset;
+ vertexView.SizeInBytes = buffer->getDesc().sizeInBytes - boundVertexBuffer.m_offset;
vertexView.StrideInBytes = boundVertexBuffer.m_stride;
}
}
commandList->IASetVertexBuffers(0, numVertexViews, vertexViews);
}
+ // Set up index buffer
+ if(m_boundIndexBuffer)
+ {
+ D3D12_INDEX_BUFFER_VIEW indexBufferView;
+ indexBufferView.BufferLocation = m_boundIndexBuffer->m_resource.getResource()->GetGPUVirtualAddress()
+ + m_boundIndexOffset;
+ indexBufferView.SizeInBytes = m_boundIndexBuffer->getDesc().sizeInBytes - m_boundIndexOffset;
+ indexBufferView.Format = m_boundIndexFormat;
+
+ commandList->IASetIndexBuffer(&indexBufferView);
+ }
+
commandList->DrawInstanced(UINT(vertexCount), 1, UINT(startVertex), 0);
}
+void D3D12Renderer::drawIndexed(UInt indexCount, UInt startIndex, UInt baseVertex)
+{
+}
+
void D3D12Renderer::dispatchCompute(int x, int y, int z)
{
ID3D12GraphicsCommandList* commandList = m_commandList;
- RenderState* renderState = calcRenderState();
+ auto pipelineStateImpl = m_currentPipelineState;
// Submit binding for compute
{
ComputeSubmitter submitter(commandList);
- _bindRenderState(renderState, commandList, &submitter);
+ _bindRenderState(pipelineStateImpl, commandList, &submitter);
}
commandList->Dispatch(x, y, z);
}
+#if 0
BindingState* D3D12Renderer::createBindingState(const BindingState::Desc& bindingStateDesc)
{
RefPtr<BindingStateImpl> bindingState(new BindingStateImpl(bindingStateDesc));
@@ -2298,7 +2648,7 @@ BindingState* D3D12Renderer::createBindingState(const BindingState::Desc& bindin
{
assert(srcEntry.resource && srcEntry.resource->isBuffer());
BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(srcEntry.resource.Ptr());
- const BufferResource::Desc& bufferDesc = bufferResource->getDesc();
+ const BufferResource::Desc& desc = bufferResource->getDesc();
const size_t bufferSize = bufferDesc.sizeInBytes;
const int elemSize = bufferDesc.elementSize <= 0 ? sizeof(uint32_t) : bufferDesc.elementSize;
@@ -2440,8 +2790,160 @@ void D3D12Renderer::setBindingState(BindingState* state)
{
m_boundBindingState = static_cast<BindingStateImpl*>(state);
}
+#endif
+
+void D3D12Renderer::DescriptorSetImpl::setConstantBuffer(UInt range, UInt index, BufferResource* buffer)
+{
+ auto dxDevice = m_renderer->m_device;
+
+
+ auto resourceImpl = (BufferResourceImpl*) buffer;
+ auto resourceDesc = resourceImpl->getDesc();
+
+ // Constant buffer view size must be a multiple of 256 bytes, so we round it up here.
+ const size_t alignedSizeInBytes = D3DUtil::calcAligned(resourceDesc.sizeInBytes, 256);
+
+ D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
+ cbvDesc.BufferLocation = resourceImpl->m_resource.getResource()->GetGPUVirtualAddress();
+ cbvDesc.SizeInBytes = alignedSizeInBytes;
+
+ auto& rangeInfo = m_layout->m_ranges[range];
+
+#ifdef _DEBUG
+ switch(rangeInfo.type)
+ {
+ default:
+ assert(!"incorrect slot type");
+ break;
+
+ case DescriptorSlotType::UniformBuffer:
+ case DescriptorSlotType::DynamicUniformBuffer:
+ break;
+ }
+#endif
+
+ auto arrayIndex = rangeInfo.arrayIndex + index;
+ auto descriptorIndex = m_resourceTable + arrayIndex;
+
+ m_resourceObjects[arrayIndex] = resourceImpl;
+ dxDevice->CreateConstantBufferView(
+ &cbvDesc,
+ m_resourceHeap->getCpuHandle(descriptorIndex));
+}
+
+void D3D12Renderer::DescriptorSetImpl::setResource(UInt range, UInt index, ResourceView* view)
+{
+ auto dxDevice = m_renderer->m_device;
+
+ auto viewImpl = (ResourceViewImpl*) view;
+
+ auto& rangeInfo = m_layout->m_ranges[range];
+
+ // TODO: validation that slot type matches view
+
+ auto arrayIndex = rangeInfo.arrayIndex + index;
+ auto descriptorIndex = m_resourceTable + arrayIndex;
+
+ m_resourceObjects[arrayIndex] = viewImpl;
+ dxDevice->CopyDescriptorsSimple(
+ 1,
+ m_resourceHeap->getCpuHandle(descriptorIndex),
+ viewImpl->m_descriptor.cpuHandle,
+ D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
+}
+
+void D3D12Renderer::DescriptorSetImpl::setSampler(UInt range, UInt index, SamplerState* sampler)
+{
+ auto dxDevice = m_renderer->m_device;
+
+ auto samplerImpl = (SamplerStateImpl*) sampler;
+
+ auto& rangeInfo = m_layout->m_ranges[range];
+
+#ifdef _DEBUG
+ switch(rangeInfo.type)
+ {
+ default:
+ assert(!"incorrect slot type");
+ break;
+
+ case DescriptorSlotType::Sampler:
+ break;
+ }
+#endif
+
+ auto arrayIndex = rangeInfo.arrayIndex + index;
+ auto descriptorIndex = m_resourceTable + arrayIndex;
+
+ m_samplerObjects[arrayIndex] = samplerImpl;
+ dxDevice->CopyDescriptorsSimple(
+ 1,
+ m_samplerHeap->getCpuHandle(descriptorIndex),
+ samplerImpl->m_cpuHandle,
+ D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
+}
-ShaderProgram* D3D12Renderer::createProgram(const ShaderProgram::Desc& desc)
+void D3D12Renderer::DescriptorSetImpl::setCombinedTextureSampler(
+ UInt range,
+ UInt index,
+ ResourceView* textureView,
+ SamplerState* sampler)
+{
+ auto dxDevice = m_renderer->m_device;
+
+ auto viewImpl = (ResourceViewImpl*) textureView;
+ auto samplerImpl = (SamplerStateImpl*) sampler;
+
+ auto& rangeInfo = m_layout->m_ranges[range];
+
+#ifdef _DEBUG
+ switch(rangeInfo.type)
+ {
+ default:
+ assert(!"incorrect slot type");
+ break;
+
+ case DescriptorSlotType::CombinedImageSampler:
+ break;
+ }
+#endif
+
+ auto arrayIndex = rangeInfo.arrayIndex + index;
+ auto resourceDescriptorIndex = m_resourceTable + arrayIndex;
+ auto samplerDescriptorIndex = m_samplerTable + arrayIndex;
+
+ m_resourceObjects[arrayIndex] = viewImpl;
+ dxDevice->CopyDescriptorsSimple(
+ 1,
+ m_resourceHeap->getCpuHandle(resourceDescriptorIndex),
+ viewImpl->m_descriptor.cpuHandle,
+ D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
+
+ m_samplerObjects[arrayIndex] = samplerImpl;
+ dxDevice->CopyDescriptorsSimple(
+ 1,
+ m_samplerHeap->getCpuHandle(samplerDescriptorIndex),
+ samplerImpl->m_cpuHandle,
+ D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
+}
+
+void D3D12Renderer::setDescriptorSet(PipelineType pipelineType, PipelineLayout* layout, UInt index, DescriptorSet* descriptorSet)
+{
+ // In D3D12, unlike Vulkan, binding a root signature invalidates *all* descriptor table
+ // bindings (rather than preserving those that are part of the longest common prefix
+ // between the old and new layout).
+ //
+ // In order to accomodate having descriptor-set bindings that persist across changes
+ // in pipeline state (which may also change pipeline layout), we will shadow the
+ // descriptor-set bindings and only flush them on-demand at draw tiume once the final
+ // pipline layout is known.
+ //
+
+ auto descriptorSetImpl = (DescriptorSetImpl*) descriptorSet;
+ m_boundDescriptorSets[int(pipelineType)][index] = descriptorSetImpl;
+}
+
+Result D3D12Renderer::createProgram(const ShaderProgram::Desc& desc, ShaderProgram** outProgram)
{
RefPtr<ShaderProgramImpl> program(new ShaderProgramImpl());
program->m_pipelineType = desc.pipelineType;
@@ -2460,8 +2962,596 @@ ShaderProgram* D3D12Renderer::createProgram(const ShaderProgram::Desc& desc)
program->m_pixelShader.InsertRange(0, (const uint8_t*) fragmentKernel->codeBegin, fragmentKernel->getCodeSize());
}
- return program.detach();
+ *outProgram = program.detach();
+ return SLANG_OK;
+}
+
+Result D3D12Renderer::createDescriptorSetLayout(const DescriptorSetLayout::Desc& desc, DescriptorSetLayout** outLayout)
+{
+ Int rangeCount = desc.slotRangeCount;
+
+ // For our purposes, there are three main cases of descriptor ranges to consider:
+ //
+ // 1. Resources: CBV, SRV, UAV
+ //
+ // 2. Samplers
+ //
+ // 3. Combined texture/sampler pairs
+ //
+ // The combined case presents challenges, because we will implement
+ // them as both a resource slot and a sampler slot, and for conveience
+ // in the indexing logic, it would be nice it they "lined up."
+ //
+ // We will start by counting how many ranges, and how many
+ // descriptors, of each type we have.
+ //
+
+ Int dedicatedResourceCount = 0;
+ Int dedicatedSamplerCount = 0;
+ Int combinedCount = 0;
+
+ Int dedicatedResourceRangeCount = 0;
+ Int dedicatedSamplerRangeCount = 0;
+ Int combinedRangeCount = 0;
+
+ for(Int rr = 0; rr < rangeCount; ++rr)
+ {
+ auto rangeDesc = desc.slotRanges[rr];
+ switch(rangeDesc.type)
+ {
+ case DescriptorSlotType::Sampler:
+ dedicatedSamplerCount += rangeDesc.count;
+ dedicatedSamplerRangeCount++;
+ break;
+
+ case DescriptorSlotType::CombinedImageSampler:
+ combinedCount += rangeDesc.count;
+ combinedRangeCount++;
+ break;
+
+ default:
+ dedicatedResourceCount += rangeDesc.count;
+ dedicatedResourceRangeCount++;
+ break;
+ }
+ }
+
+ // Now we know how many ranges we have to allocate space for,
+ // and also how they need to be arranged.
+ //
+ // Each "combined" range will map to two ranges in the D3D
+ // descriptor tables.
+
+ RefPtr<DescriptorSetLayoutImpl> descriptorSetLayoutImpl = new DescriptorSetLayoutImpl();
+
+ // We know the total number of resource and sampler "slots" that an instance
+ // of this decriptor-set layout would need:
+ //
+ descriptorSetLayoutImpl->m_resourceCount = combinedCount + dedicatedResourceCount;
+ descriptorSetLayoutImpl->m_samplerCount = combinedCount + dedicatedSamplerCount;
+
+ // We can start by allocating the D3D root parameter info needed for the
+ // descriptor set, based on the total number or ranges we need, which
+ // we can compute from the combined and dedicated counts:
+ //
+ Int totalResourceRangeCount = combinedRangeCount + dedicatedResourceRangeCount;
+ Int totalSamplerRangeCount = combinedRangeCount + dedicatedSamplerRangeCount;
+
+ if( totalResourceRangeCount )
+ {
+ D3D12_ROOT_PARAMETER dxRootParameter = {};
+ dxRootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
+ dxRootParameter.DescriptorTable.NumDescriptorRanges = totalResourceRangeCount;
+ descriptorSetLayoutImpl->m_dxRootParameters.Add(dxRootParameter);
+ }
+ if( totalSamplerRangeCount )
+ {
+ D3D12_ROOT_PARAMETER dxRootParameter = {};
+ dxRootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
+ dxRootParameter.DescriptorTable.NumDescriptorRanges = totalSamplerRangeCount;
+ descriptorSetLayoutImpl->m_dxRootParameters.Add(dxRootParameter);
+ }
+
+ // Next we can allocate space for all the D3D register ranges we need,
+ // again based on totals that we can compute easily:
+ //
+ Int totalRangeCount = totalResourceRangeCount + totalSamplerRangeCount;
+ descriptorSetLayoutImpl->m_dxRanges.SetSize(totalRangeCount);
+
+ // Now we will walk through the ranges in the order they were
+ // specified, so that we can fill in the "range info" required for
+ // binding parameters into descriptor sets allocated with this layout.
+ //
+ // This effectively determines the space required in two arrays
+ // in each descriptor set: one for resources, and one for samplers.
+ // A "combined" descriptor requires space in both arrays. The entries
+ // for "dedicated" samplers/resources always come after those for
+ // "combined" descriptors in the same array, so that a single index
+ // can be used for both arrays in the combined case.
+ //
+
+ {
+ Int samplerCounter = 0;
+ Int resourceCounter = 0;
+ Int combinedCounter = 0;
+ for(Int rr = 0; rr < rangeCount; ++rr)
+ {
+ auto rangeDesc = desc.slotRanges[rr];
+
+ DescriptorSetLayoutImpl::RangeInfo rangeInfo;
+
+ rangeInfo.type = rangeDesc.type;
+ rangeInfo.count = rangeDesc.count;
+
+ switch(rangeDesc.type)
+ {
+ default:
+ // Default case is a dedicated resource, and its index in the
+ // resource array will come after all the combined entries.
+ rangeInfo.arrayIndex = combinedCount + resourceCounter;
+ resourceCounter += rangeInfo.count;
+ break;
+
+ case DescriptorSlotType::Sampler:
+ // A dedicated sampler comes after all the entries for
+ // combined texture/samplers in the sampler array.
+ rangeInfo.arrayIndex = combinedCount + samplerCounter;
+ samplerCounter += rangeInfo.count;
+ break;
+
+ case DescriptorSlotType::CombinedImageSampler:
+ // Combined descriptors take entries at the front of
+ // the resource and sampler arrays.
+ rangeInfo.arrayIndex = combinedCounter;
+ combinedCounter += rangeInfo.count;
+ break;
+ }
+
+ descriptorSetLayoutImpl->m_ranges.Add(rangeInfo);
+ }
+ }
+
+ // Finally, we will go through and fill in ready-to-go D3D
+ // register range information.
+ {
+ UInt cbvCounter = 0;
+ UInt srvCounter = 0;
+ UInt uavCounter = 0;
+ UInt samplerCounter = 0;
+
+ Int resourceRangeCounter = 0;
+ Int samplerRangeCounter = 0;
+ Int combinedRangeCounter = 0;
+
+ for(Int rr = 0; rr < rangeCount; ++rr)
+ {
+ auto rangeDesc = desc.slotRanges[rr];
+ Int bindingCount = rangeDesc.count;
+
+ // All of these descriptor ranges will be initialized
+ // with a "space" of zero, with the assumption that
+ // the actual space number will come from when they are
+ // used as part of a pipeline layout.
+ //
+ Int bindingSpace = 0;
+
+ Int dxRangeIndex = -1;
+ Int dxPairedSamplerRangeIndex = -1;
+
+ switch(rangeDesc.type)
+ {
+ default:
+ // Default case is a dedicated resource, and its index in the
+ // resource array will come after all the combined entries.
+ dxRangeIndex = combinedRangeCount + resourceRangeCounter;
+ resourceRangeCounter++;
+ break;
+
+ case DescriptorSlotType::Sampler:
+ // A dedicated sampler comes after all the entries for
+ // combined texture/samplers in the sampler array.
+ dxRangeIndex = totalResourceRangeCount + combinedRangeCount + samplerRangeCounter;
+ samplerRangeCounter++;
+ break;
+
+ case DescriptorSlotType::CombinedImageSampler:
+ // Combined descriptors take entries at the front of
+ // the resource and sampler arrays.
+ dxRangeIndex = combinedRangeCounter;
+ dxPairedSamplerRangeIndex = totalResourceRangeCount + combinedRangeCounter;
+ combinedRangeCounter++;
+ break;
+ }
+
+ D3D12_DESCRIPTOR_RANGE& dxRange = descriptorSetLayoutImpl->m_dxRanges[dxRangeIndex];
+ memset(&dxRange, 0, sizeof(dxRange));
+
+ switch(rangeDesc.type)
+ {
+ default:
+ // ERROR: unsupported slot type.
+ break;
+
+ case DescriptorSlotType::Sampler:
+ {
+ UInt bindingIndex = samplerCounter; samplerCounter += bindingCount;
+
+ dxRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
+ dxRange.NumDescriptors = bindingCount;
+ dxRange.BaseShaderRegister = bindingIndex;
+ dxRange.RegisterSpace = bindingSpace;
+ dxRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
+ }
+ break;
+
+ case DescriptorSlotType::SampledImage:
+ case DescriptorSlotType::UniformTexelBuffer:
+ {
+ UInt bindingIndex = srvCounter; srvCounter += bindingCount;
+
+ dxRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
+ dxRange.NumDescriptors = bindingCount;
+ dxRange.BaseShaderRegister = bindingIndex;
+ dxRange.RegisterSpace = bindingSpace;
+ dxRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
+ }
+ break;
+
+ case DescriptorSlotType::CombinedImageSampler:
+ {
+ // The combined texture/sampler case basically just
+ // does the work of both the SRV and sampler cases above.
+
+ {
+ // Here's the SRV logic:
+
+ UInt bindingIndex = srvCounter; srvCounter += bindingCount;
+
+ dxRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
+ dxRange.NumDescriptors = bindingCount;
+ dxRange.BaseShaderRegister = bindingIndex;
+ dxRange.RegisterSpace = bindingSpace;
+ dxRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
+ }
+
+ {
+ // And here we do the sampler logic at the "paired" index.
+ D3D12_DESCRIPTOR_RANGE& dxPairedSamplerRange = descriptorSetLayoutImpl->m_dxRanges[dxPairedSamplerRangeIndex];
+ memset(&dxPairedSamplerRange, 0, sizeof(dxPairedSamplerRange));
+
+ UInt pairedSamplerBindingIndex = srvCounter; srvCounter += bindingCount;
+
+ dxPairedSamplerRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
+ dxPairedSamplerRange.NumDescriptors = bindingCount;
+ dxPairedSamplerRange.BaseShaderRegister = pairedSamplerBindingIndex;
+ dxPairedSamplerRange.RegisterSpace = bindingSpace;
+ dxPairedSamplerRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
+ }
+
+ }
+ break;
+
+
+ case DescriptorSlotType::InputAttachment:
+ case DescriptorSlotType::StorageImage:
+ case DescriptorSlotType::StorageTexelBuffer:
+ case DescriptorSlotType::StorageBuffer:
+ case DescriptorSlotType::DynamicStorageBuffer:
+ {
+ UInt bindingIndex = uavCounter; uavCounter += bindingCount;
+
+ dxRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
+ dxRange.NumDescriptors = bindingCount;
+ dxRange.BaseShaderRegister = bindingIndex;
+ dxRange.RegisterSpace = bindingSpace;
+ dxRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
+ }
+ break;
+
+ case DescriptorSlotType::UniformBuffer:
+ case DescriptorSlotType::DynamicUniformBuffer:
+ {
+ UInt bindingIndex = cbvCounter; cbvCounter += bindingCount;
+
+ dxRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV;
+ dxRange.NumDescriptors = bindingCount;
+ dxRange.BaseShaderRegister = bindingIndex;
+ dxRange.RegisterSpace = bindingSpace;
+ dxRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
+ }
+ break;
+ }
+ }
+ }
+
+ *outLayout = descriptorSetLayoutImpl.detach();
+ return SLANG_OK;
+}
+
+Result D3D12Renderer::createPipelineLayout(const PipelineLayout::Desc& desc, PipelineLayout** outLayout)
+{
+ static const UInt kMaxRanges = 16;
+ static const UInt kMaxRootParameters = 32;
+
+ D3D12_DESCRIPTOR_RANGE ranges[kMaxRanges];
+ D3D12_ROOT_PARAMETER rootParameters[kMaxRootParameters];
+
+ UInt rangeCount = 0;
+ UInt rootParameterCount = 0;
+
+ auto descriptorSetCount = desc.descriptorSetCount;
+
+ // We are going to make two passes over the descriptor set layouts
+ // that are being used to build the pipeline layout. In the first
+ // pass we will collect all the descriptor ranges that have been
+ // specified, applying an offset to their register spaces as needed.
+ //
+ for(UInt dd = 0; dd < descriptorSetCount; ++dd)
+ {
+ auto& descriptorSetInfo = desc.descriptorSets[dd];
+ auto descriptorSetLayout = (DescriptorSetLayoutImpl*) descriptorSetInfo.layout;
+
+ // For now we assume that the register space used for
+ // logical descriptor set #N will be space N.
+ //
+ // TODO: This might need to be revisited in the future because
+ // a single logical descriptor set might need to encompass stuff
+ // that comes from multiple spaces (e.g., if it contains an unbounded
+ // array).
+ //
+ UInt bindingSpace = dd;
+
+ // Copy descriptor range infromation from the set layout into our
+ // temporary copy (this is required because the same set layout
+ // might be applied to different ranges).
+ //
+ // API design note: this copy step could be avoided if the D3D
+ // API allowed for a "space offset" to be applied as part of
+ // a descriptor-table root parameter.
+ //
+ for(auto setDescriptorRange : descriptorSetLayout->m_dxRanges)
+ {
+ auto& range = ranges[rangeCount++];
+ range = setDescriptorRange;
+ range.RegisterSpace = bindingSpace;
+
+ // HACK: in order to deal with SM5.0 shaders, `u` registers
+ // in `space0` need to start with a number *after* the number
+ // of `SV_Target` outputs that will be used.
+ //
+ // TODO: This is clearly a mess, and doing this behavior here
+ // means it *won't* work for SM5.1 where the restriction is
+ // lifted. The only real alternative is to rely on explicit
+ // register numbers (e.g., from shader reflection) but that
+ // goes against the simplicity that this API layer strives for
+ // (everything so far has been set up to work correctly with
+ // automatic assignment of bindings).
+ //
+ if( range.RegisterSpace == 0
+ && range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_UAV )
+ {
+ range.BaseShaderRegister += desc.renderTargetCount;
+ }
+ }
+ }
+
+ // In our second pass, we will copy over root parameters, which
+ // may end up pointing into the list of ranges from the first step.
+ //
+ auto rangePtr = &ranges[0];
+ for(UInt dd = 0; dd < descriptorSetCount; ++dd)
+ {
+ auto& descriptorSetInfo = desc.descriptorSets[dd];
+ auto descriptorSetLayout = (DescriptorSetLayoutImpl*) descriptorSetInfo.layout;
+
+ // Copy root parameter information from the set layout to our
+ // overall pipeline layout.
+ for( auto setRootParameter : descriptorSetLayout->m_dxRootParameters )
+ {
+ auto& rootParameter = rootParameters[rootParameterCount++];
+ rootParameter = setRootParameter;
+
+ // In the case where this parameter is a descriptor table, it
+ // needs to point into our array of ranges (with offsets applied),
+ // so we will fix up those pointers here.
+ //
+ if(rootParameter.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE)
+ {
+ rootParameter.DescriptorTable.pDescriptorRanges = rangePtr;
+ rangePtr += rootParameter.DescriptorTable.NumDescriptorRanges;
+ }
+ }
+ }
+
+ D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc = {};
+ rootSignatureDesc.NumParameters = rootParameterCount;
+ rootSignatureDesc.pParameters = rootParameters;
+
+ // TODO: static samplers should be reasonably easy to support...
+ rootSignatureDesc.NumStaticSamplers = 0;
+ rootSignatureDesc.pStaticSamplers = nullptr;
+
+ // TODO: only set this flag if needed (requires creating root
+ // signature at same time as pipeline state...).
+ //
+ rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
+
+ ComPtr<ID3DBlob> signature;
+ ComPtr<ID3DBlob> error;
+ if( SLANG_FAILED(m_D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, signature.writeRef(), error.writeRef())) )
+ {
+ fprintf(stderr, "error: D3D12SerializeRootSignature failed");
+ if( error )
+ {
+ fprintf(stderr, ": %s\n", (const char*) error->GetBufferPointer());
+ }
+ return SLANG_FAIL;
+ }
+
+ ComPtr<ID3D12RootSignature> rootSignature;
+ SLANG_RETURN_ON_FAIL(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(rootSignature.writeRef())));
+
+
+ RefPtr<PipelineLayoutImpl> pipelineLayoutImpl = new PipelineLayoutImpl();
+ pipelineLayoutImpl->m_rootSignature = rootSignature;
+ pipelineLayoutImpl->m_descriptorSetCount = descriptorSetCount;
+ *outLayout = pipelineLayoutImpl.detach();
+ return SLANG_OK;
+}
+
+Result D3D12Renderer::createDescriptorSet(DescriptorSetLayout* layout, DescriptorSet** outDescriptorSet)
+{
+ auto layoutImpl = (DescriptorSetLayoutImpl*) layout;
+
+ RefPtr<DescriptorSetImpl> descriptorSetImpl = new DescriptorSetImpl();
+ descriptorSetImpl->m_renderer = this;
+ descriptorSetImpl->m_layout = layoutImpl;
+
+ // We allocate CPU-visible descriptor tables to providing the
+ // backing storage for each descriptor set. GPU-visible storage
+ // will only be allocated as needed during per-frame logic in
+ // order to ensure that a descriptor set it available for use
+ // in rendering.
+ //
+ Int resourceCount = layoutImpl->m_resourceCount;
+ if( resourceCount )
+ {
+ auto resourceHeap = &m_cpuViewHeap;
+ descriptorSetImpl->m_resourceHeap = resourceHeap;
+ descriptorSetImpl->m_resourceTable = resourceHeap->allocate(resourceCount);
+ descriptorSetImpl->m_resourceObjects.SetSize(resourceCount);
+ }
+
+ Int samplerCount = layoutImpl->m_samplerCount;
+ if( samplerCount )
+ {
+ auto samplerHeap = &m_cpuSamplerHeap;
+ descriptorSetImpl->m_samplerHeap = samplerHeap;
+ descriptorSetImpl->m_samplerTable = samplerHeap->allocate(samplerCount);
+ descriptorSetImpl->m_samplerObjects.SetSize(samplerCount);
+ }
+
+ *outDescriptorSet = descriptorSetImpl.detach();
+ return SLANG_OK;
+}
+
+Result D3D12Renderer::createGraphicsPipelineState(const GraphicsPipelineStateDesc& desc, PipelineState** outState)
+{
+ auto pipelineLayoutImpl = (PipelineLayoutImpl*) desc.pipelineLayout;
+ auto programImpl = (ShaderProgramImpl*) desc.program;
+ auto inputLayoutImpl = (InputLayoutImpl*) desc.inputLayout;
+
+ // Describe and create the graphics pipeline state object (PSO)
+ D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
+
+ psoDesc.pRootSignature = pipelineLayoutImpl->m_rootSignature;
+
+ psoDesc.VS = { programImpl->m_vertexShader.Buffer(), programImpl->m_vertexShader.Count() };
+ psoDesc.PS = { programImpl->m_pixelShader .Buffer(), programImpl->m_pixelShader .Count() };
+
+ psoDesc.InputLayout = { inputLayoutImpl->m_elements.Buffer(), UINT(inputLayoutImpl->m_elements.Count()) };
+ psoDesc.PrimitiveTopologyType = m_primitiveTopologyType;
+
+ {
+ const int numRenderTargets = desc.renderTargetCount;
+
+ psoDesc.DSVFormat = m_depthStencilFormat;
+ psoDesc.NumRenderTargets = numRenderTargets;
+ for (Int i = 0; i < numRenderTargets; i++)
+ {
+ psoDesc.RTVFormats[i] = m_targetFormat;
+ }
+
+ psoDesc.SampleDesc.Count = 1;
+ psoDesc.SampleDesc.Quality = 0;
+
+ psoDesc.SampleMask = UINT_MAX;
+ }
+
+ {
+ auto& rs = psoDesc.RasterizerState;
+ rs.FillMode = D3D12_FILL_MODE_SOLID;
+ rs.CullMode = D3D12_CULL_MODE_NONE;
+ rs.FrontCounterClockwise = FALSE;
+ rs.DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
+ rs.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
+ rs.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
+ rs.DepthClipEnable = TRUE;
+ rs.MultisampleEnable = FALSE;
+ rs.AntialiasedLineEnable = FALSE;
+ rs.ForcedSampleCount = 0;
+ rs.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
+ }
+
+ {
+ D3D12_BLEND_DESC& blend = psoDesc.BlendState;
+
+ blend.AlphaToCoverageEnable = FALSE;
+ blend.IndependentBlendEnable = FALSE;
+ const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc =
+ {
+ FALSE,FALSE,
+ D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD,
+ D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD,
+ D3D12_LOGIC_OP_NOOP,
+ D3D12_COLOR_WRITE_ENABLE_ALL,
+ };
+ for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i)
+ {
+ blend.RenderTarget[i] = defaultRenderTargetBlendDesc;
+ }
+ }
+
+ {
+ auto& ds = psoDesc.DepthStencilState;
+
+ ds.DepthEnable = FALSE;
+ ds.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
+ ds.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
+ //ds.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
+ ds.StencilEnable = FALSE;
+ ds.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK;
+ ds.StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK;
+ const D3D12_DEPTH_STENCILOP_DESC defaultStencilOp =
+ {
+ D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_COMPARISON_FUNC_ALWAYS
+ };
+ ds.FrontFace = defaultStencilOp;
+ ds.BackFace = defaultStencilOp;
+ }
+
+ psoDesc.PrimitiveTopologyType = m_primitiveTopologyType;
+
+ ComPtr<ID3D12PipelineState> pipelineState;
+ SLANG_RETURN_ON_FAIL(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(pipelineState.writeRef())));
+
+ RefPtr<PipelineStateImpl> pipelineStateImpl = new PipelineStateImpl();
+ pipelineStateImpl->m_pipelineType = PipelineType::Graphics;
+ pipelineStateImpl->m_pipelineLayout = pipelineLayoutImpl;
+ pipelineStateImpl->m_pipelineState = pipelineState;
+ *outState = pipelineStateImpl.detach();
+ return SLANG_OK;
}
+Result D3D12Renderer::createComputePipelineState(const ComputePipelineStateDesc& desc, PipelineState** outState)
+{
+ auto pipelineLayoutImpl = (PipelineLayoutImpl*) desc.pipelineLayout;
+ auto programImpl = (ShaderProgramImpl*) desc.program;
+
+ // Describe and create the compute pipeline state object
+ D3D12_COMPUTE_PIPELINE_STATE_DESC computeDesc = {};
+ computeDesc.pRootSignature = pipelineLayoutImpl->m_rootSignature;
+ computeDesc.CS = { programImpl->m_computeShader.Buffer(), programImpl->m_computeShader.Count() };
+
+ ComPtr<ID3D12PipelineState> pipelineState;
+ SLANG_RETURN_ON_FAIL(m_device->CreateComputePipelineState(&computeDesc, IID_PPV_ARGS(pipelineState.writeRef())));
+
+ RefPtr<PipelineStateImpl> pipelineStateImpl = new PipelineStateImpl();
+ pipelineStateImpl->m_pipelineType = PipelineType::Compute;
+ pipelineStateImpl->m_pipelineLayout = pipelineLayoutImpl;
+ pipelineStateImpl->m_pipelineState = pipelineState;
+ *outState = pipelineStateImpl.detach();
+ return SLANG_OK;
+}
} // renderer_test
diff --git a/tools/slang-graphics/render-d3d12.h b/tools/gfx/render-d3d12.h
index 5f0eea4d2..b8a3104c0 100644
--- a/tools/slang-graphics/render-d3d12.h
+++ b/tools/gfx/render-d3d12.h
@@ -1,10 +1,10 @@
// render-d3d12.h
#pragma once
-namespace slang_graphics {
+namespace gfx {
class Renderer;
Renderer* createD3D12Renderer();
-} // slang_graphics
+} // gfx
diff --git a/tools/slang-graphics/render-gl.cpp b/tools/gfx/render-gl.cpp
index f85a81ca4..3ab818fdd 100644
--- a/tools/slang-graphics/render-gl.cpp
+++ b/tools/gfx/render-gl.cpp
@@ -73,7 +73,7 @@
using namespace Slang;
-namespace slang_graphics {
+namespace gfx {
class GLRenderer : public Renderer
{
@@ -84,20 +84,39 @@ public:
virtual void setClearColor(const float color[4]) override;
virtual void clearFrame() override;
virtual void presentFrame() override;
- virtual TextureResource* createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData) override;
- virtual BufferResource* createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& descIn, const void* initData) override;
+ TextureResource::Desc getSwapChainTextureDesc() override;
+
+ Result createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData, TextureResource** outResource) override;
+ Result createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& desc, const void* initData, BufferResource** outResource) override;
+ Result createSamplerState(SamplerState::Desc const& desc, SamplerState** outSampler) override;
+
+ Result createTextureView(TextureResource* texture, ResourceView::Desc const& desc, ResourceView** outView) override;
+ Result createBufferView(BufferResource* buffer, ResourceView::Desc const& desc, ResourceView** outView) override;
+
+ Result createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount, InputLayout** outLayout) override;
+
+ Result createDescriptorSetLayout(const DescriptorSetLayout::Desc& desc, DescriptorSetLayout** outLayout) override;
+ Result createPipelineLayout(const PipelineLayout::Desc& desc, PipelineLayout** outLayout) override;
+ Result createDescriptorSet(DescriptorSetLayout* layout, DescriptorSet** outDescriptorSet) override;
+
+ Result createProgram(const ShaderProgram::Desc& desc, ShaderProgram** outProgram) override;
+ Result createGraphicsPipelineState(const GraphicsPipelineStateDesc& desc, PipelineState** outState) override;
+ Result createComputePipelineState(const ComputePipelineStateDesc& desc, PipelineState** outState) override;
+
virtual SlangResult captureScreenSurface(Surface& surfaceOut) override;
- virtual InputLayout* createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount) override;
- virtual BindingState* createBindingState(const BindingState::Desc& bindingStateDesc) override;
- virtual ShaderProgram* createProgram(const ShaderProgram::Desc& desc) override;
+
virtual void* map(BufferResource* buffer, MapFlavor flavor) override;
virtual void unmap(BufferResource* buffer) override;
- virtual void setInputLayout(InputLayout* inputLayout) override;
virtual void setPrimitiveTopology(PrimitiveTopology topology) override;
- virtual void setBindingState(BindingState* state);
+
+ virtual void setDescriptorSet(PipelineType pipelineType, PipelineLayout* layout, UInt index, DescriptorSet* descriptorSet) override;
+
virtual void setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) override;
- virtual void setShaderProgram(ShaderProgram* inProgram) override;
+ virtual void setIndexBuffer(BufferResource* buffer, Format indexFormat, UInt offset) override;
+ virtual void setDepthStencilTarget(ResourceView* depthStencilView) override;
+ virtual void setPipelineState(PipelineType pipelineType, PipelineState* state) override;
virtual void draw(UInt vertexCount, UInt startVertex) override;
+ virtual void drawIndexed(UInt indexCount, UInt startIndex, UInt baseVertex) override;
virtual void dispatchCompute(int x, int y, int z) override;
virtual void submitGpuWork() override {}
virtual void waitForGpu() override {}
@@ -107,6 +126,7 @@ public:
enum
{
kMaxVertexStreams = 16,
+ kMaxDescriptorSetCount = 8,
};
struct VertexAttributeFormat
@@ -184,33 +204,78 @@ public:
GLuint m_handle;
};
- struct BindingDetail
+ class SamplerStateImpl : public SamplerState
{
- GLuint m_samplerHandle = 0;
+ public:
+ GLuint m_samplerID;
};
- class BindingStateImpl: public BindingState
+ class ResourceViewImpl : public ResourceView
{
- public:
- typedef BindingState Parent;
+ };
- /// Ctor
- BindingStateImpl(const Desc& desc, GLRenderer* renderer):
- Parent(desc),
- m_renderer(renderer)
- {
- }
+ class TextureViewImpl : public ResourceViewImpl
+ {
+ public:
+ RefPtr<TextureResourceImpl> m_resource;
+ GLuint m_textureID;
+ };
- ~BindingStateImpl()
- {
- if (m_renderer)
- {
- m_renderer->destroyBindingEntries(getDesc(), m_bindingDetails.Buffer());
- }
- }
+ class BufferViewImpl : public ResourceViewImpl
+ {
+ public:
+ RefPtr<BufferResourceImpl> m_resource;
+ GLuint m_bufferID;
+ };
- GLRenderer* m_renderer;
- List<BindingDetail> m_bindingDetails;
+ enum class GLDescriptorSlotType
+ {
+ ConstantBuffer,
+ CombinedTextureSampler,
+
+ CountOf,
+ };
+
+ class DescriptorSetLayoutImpl : public DescriptorSetLayout
+ {
+ public:
+ struct RangeInfo
+ {
+ GLDescriptorSlotType type;
+ UInt arrayIndex;
+ };
+ List<RangeInfo> m_ranges;
+ Int m_counts[int(GLDescriptorSlotType::CountOf)];
+ };
+
+ class PipelineLayoutImpl : public PipelineLayout
+ {
+ public:
+ struct DescriptorSetInfo
+ {
+ RefPtr<DescriptorSetLayoutImpl> layout;
+ UInt baseArrayIndex[int(GLDescriptorSlotType::CountOf)];
+ };
+
+ List<DescriptorSetInfo> m_sets;
+ };
+
+ class DescriptorSetImpl : public DescriptorSet
+ {
+ public:
+ virtual void setConstantBuffer(UInt range, UInt index, BufferResource* buffer) override;
+ virtual void setResource(UInt range, UInt index, ResourceView* view) override;
+ virtual void setSampler(UInt range, UInt index, SamplerState* sampler) override;
+ virtual void setCombinedTextureSampler(
+ UInt range,
+ UInt index,
+ ResourceView* textureView,
+ SamplerState* sampler) override;
+
+ RefPtr<DescriptorSetLayoutImpl> m_layout;
+ List<RefPtr<BufferResourceImpl>> m_constantBuffers;
+ List<RefPtr<TextureViewImpl>> m_textures;
+ List<RefPtr<SamplerStateImpl>> m_samplers;
};
class ShaderProgramImpl : public ShaderProgram
@@ -233,6 +298,14 @@ public:
GLRenderer* m_renderer;
};
+ class PipelineStateImpl : public PipelineState
+ {
+ public:
+ RefPtr<ShaderProgramImpl> m_program;
+ RefPtr<PipelineLayoutImpl> m_pipelineLayout;
+ RefPtr<InputLayoutImpl> m_inputLayout;
+ };
+
enum class GlPixelFormat
{
Unknown,
@@ -247,7 +320,7 @@ public:
GLenum formatType; // such as GL_UNSIGNED_BYTE
};
- void destroyBindingEntries(const BindingState::Desc& desc, const BindingDetail* details);
+// void destroyBindingEntries(const BindingState::Desc& desc, const BindingDetail* details);
void bindBufferImpl(int target, UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* offsets);
void flushStateForDraw();
@@ -266,8 +339,11 @@ public:
HGLRC m_glContext;
float m_clearColor[4] = { 0, 0, 0, 0 };
- RefPtr<ShaderProgramImpl> m_boundShaderProgram;
- RefPtr<InputLayoutImpl> m_boundInputLayout;
+ RefPtr<PipelineStateImpl> m_currentPipelineState;
+// RefPtr<ShaderProgramImpl> m_boundShaderProgram;
+// RefPtr<InputLayoutImpl> m_boundInputLayout;
+
+ RefPtr<DescriptorSetImpl> m_boundDescriptorSets[kMaxDescriptorSetCount];
GLenum m_boundPrimitiveTopology = GL_TRIANGLES;
GLuint m_boundVertexStreamBuffers[kMaxVertexStreams];
@@ -365,11 +441,11 @@ void GLRenderer::bindBufferImpl(int target, UInt startSlot, UInt slotCount, Buff
void GLRenderer::flushStateForDraw()
{
- auto layout = m_boundInputLayout.Ptr();
- auto attrCount = layout->m_attributeCount;
+ auto inputLayout = m_currentPipelineState->m_inputLayout.Ptr();
+ auto attrCount = inputLayout->m_attributeCount;
for (UInt ii = 0; ii < attrCount; ++ii)
{
- auto& attr = layout->m_attributes[ii];
+ auto& attr = inputLayout->m_attributes[ii];
auto streamIndex = attr.streamIndex;
@@ -389,6 +465,57 @@ void GLRenderer::flushStateForDraw()
{
glDisableVertexAttribArray((GLuint)ii);
}
+
+ // Next bind the descriptor sets as required by the layout
+ auto pipelineLayout = m_currentPipelineState->m_pipelineLayout;
+ auto descriptorSetCount = pipelineLayout->m_sets.Count();
+ for(UInt ii = 0; ii < descriptorSetCount; ++ii)
+ {
+ auto descriptorSet = m_boundDescriptorSets[ii];
+ auto descriptorSetInfo = pipelineLayout->m_sets[ii];
+ auto descriptorSetLayout = descriptorSetInfo.layout;
+
+ // TODO: need to validate that `descriptorSet->m_layout` matches
+ // `descriptorSetLayout`.
+
+ {
+ // First we will bind any uniform buffers that were specified.
+
+ auto slotTypeIndex = int(GLDescriptorSlotType::ConstantBuffer);
+ auto count = descriptorSetLayout->m_counts[slotTypeIndex];
+ auto baseIndex = descriptorSetInfo.baseArrayIndex[slotTypeIndex];
+
+ for(Int ii = 0; ii < count; ++ii)
+ {
+ auto bufferImpl = descriptorSet->m_constantBuffers[ii];
+ glBindBufferBase(GL_UNIFORM_BUFFER, ii, bufferImpl->m_handle);
+ }
+ }
+
+
+ {
+ // Next we will bind any combined texture/sampler slots.
+
+ auto slotTypeIndex = int(GLDescriptorSlotType::CombinedTextureSampler);
+ auto count = descriptorSetLayout->m_counts[slotTypeIndex];
+ auto baseIndex = descriptorSetInfo.baseArrayIndex[slotTypeIndex];
+
+ // TODO: We should be able to use a single call to glBindTextures here,
+ // rather than a loop. This would also eliminate the need to retain
+ // the appropriate target (e.g., `GL_TEXTURE_2D` for binding).
+
+ for(Int ii = 0; ii < count; ++ii)
+ {
+ auto textureViewImpl = descriptorSet->m_textures[ii];
+ auto samplerImpl = descriptorSet->m_samplers[ii];
+
+ glActiveTexture(GL_TEXTURE0 + ii);
+ glBindTexture(GL_TEXTURE_2D, textureViewImpl->m_textureID);
+
+ glBindSampler(baseIndex + ii, samplerImpl->m_samplerID);
+ }
+ }
+ }
}
GLuint GLRenderer::loadShader(GLenum stage, const char* source)
@@ -502,6 +629,7 @@ GLuint GLRenderer::loadShader(GLenum stage, const char* source)
return shaderID;
}
+#if 0
void GLRenderer::destroyBindingEntries(const BindingState::Desc& desc, const BindingDetail* details)
{
const auto& bindings = desc.m_bindings;
@@ -517,6 +645,7 @@ void GLRenderer::destroyBindingEntries(const BindingState::Desc& desc, const Bin
}
}
}
+#endif
// !!!!!!!!!!!!!!!!!!!!!!!!!!!! Renderer interface !!!!!!!!!!!!!!!!!!!!!!!!!!
@@ -581,6 +710,13 @@ void GLRenderer::presentFrame()
::SwapBuffers(m_hdc);
}
+TextureResource::Desc GLRenderer::getSwapChainTextureDesc()
+{
+ TextureResource::Desc desc;
+ desc.init2D(Resource::Type::Texture2D, Format::Unknown, m_desc.width, m_desc.height, 1);
+ return desc;
+}
+
SlangResult GLRenderer::captureScreenSurface(Surface& surfaceOut)
{
SLANG_RETURN_ON_FAIL(surfaceOut.allocate(m_desc.width, m_desc.height, Format::RGBA_Unorm_UInt8, 1, SurfaceAllocator::getMallocAllocator()));
@@ -589,7 +725,7 @@ SlangResult GLRenderer::captureScreenSurface(Surface& surfaceOut)
return SLANG_OK;
}
-TextureResource* GLRenderer::createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& descIn, const TextureResource::Data* initData)
+Result GLRenderer::createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& descIn, const TextureResource::Data* initData, TextureResource** outResource)
{
TextureResource::Desc srcDesc(descIn);
srcDesc.setDefaults(initialUsage);
@@ -597,7 +733,7 @@ TextureResource* GLRenderer::createTextureResource(Resource::Usage initialUsage,
GlPixelFormat pixelFormat = _getGlPixelFormat(srcDesc.format);
if (pixelFormat == GlPixelFormat::Unknown)
{
- return nullptr;
+ return SLANG_FAIL;
}
const GlPixelFormatInfo& info = s_pixelFormatInfos[int(pixelFormat)];
@@ -713,7 +849,8 @@ TextureResource* GLRenderer::createTextureResource(Resource::Usage initialUsage,
}
break;
}
- default: return nullptr;
+ default:
+ return SLANG_FAIL;
}
glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_REPEAT);
@@ -727,7 +864,8 @@ TextureResource* GLRenderer::createTextureResource(Resource::Usage initialUsage,
texture->m_target = target;
- return texture.detach();
+ *outResource = texture.detach();
+ return SLANG_OK;
}
static GLenum _calcUsage(Resource::Usage usage)
@@ -750,7 +888,7 @@ static GLenum _calcTarget(Resource::Usage usage)
}
}
-BufferResource* GLRenderer::createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& descIn, const void* initData)
+Result GLRenderer::createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& descIn, const void* initData, BufferResource** outResource)
{
BufferResource::Desc desc(descIn);
desc.setDefaults(initialUsage);
@@ -765,12 +903,51 @@ BufferResource* GLRenderer::createBufferResource(Resource::Usage initialUsage, c
glBufferData(target, descIn.sizeInBytes, initData, usage);
- return new BufferResourceImpl(initialUsage, desc, this, bufferID, target);
+ RefPtr<BufferResourceImpl> resourceImpl = new BufferResourceImpl(initialUsage, desc, this, bufferID, target);
+ *outResource = resourceImpl.detach();
+ return SLANG_OK;
+}
+
+Result GLRenderer::createSamplerState(SamplerState::Desc const& desc, SamplerState** outSampler)
+{
+ GLuint samplerID;
+ glCreateSamplers(1, &samplerID);
+
+ RefPtr<SamplerStateImpl> samplerImpl = new SamplerStateImpl();
+ samplerImpl->m_samplerID = samplerID;
+ *outSampler = samplerImpl.detach();
+ return SLANG_OK;
+}
+
+Result GLRenderer::createTextureView(TextureResource* texture, ResourceView::Desc const& desc, ResourceView** outView)
+{
+ auto resourceImpl = (TextureResourceImpl*) texture;
+
+ // TODO: actually do something?
+
+ RefPtr<TextureViewImpl> viewImpl = new TextureViewImpl();
+ viewImpl->m_resource = resourceImpl;
+ viewImpl->m_textureID = resourceImpl->m_handle;
+ *outView = viewImpl;
+ return SLANG_OK;
+}
+
+Result GLRenderer::createBufferView(BufferResource* buffer, ResourceView::Desc const& desc, ResourceView** outView)
+{
+ auto resourceImpl = (BufferResourceImpl*) buffer;
+
+ // TODO: actually do something?
+
+ RefPtr<BufferViewImpl> viewImpl = new BufferViewImpl();
+ viewImpl->m_resource = resourceImpl;
+ viewImpl->m_bufferID = resourceImpl->m_handle;
+ *outView = viewImpl.detach();
+ return SLANG_OK;
}
-InputLayout* GLRenderer::createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount)
+Result GLRenderer::createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount, InputLayout** outLayout)
{
- InputLayoutImpl* inputLayout = new InputLayoutImpl;
+ RefPtr<InputLayoutImpl> inputLayout = new InputLayoutImpl;
inputLayout->m_attributeCount = inputElementCount;
for (UInt ii = 0; ii < inputElementCount; ++ii)
@@ -783,7 +960,8 @@ InputLayout* GLRenderer::createInputLayout(const InputElementDesc* inputElements
glAttr.offset = (GLsizei)inputAttr.offset;
}
- return (InputLayout*)inputLayout;
+ *outLayout = inputLayout.detach();
+ return SLANG_OK;
}
void* GLRenderer::map(BufferResource* bufferIn, MapFlavor flavor)
@@ -815,11 +993,6 @@ void GLRenderer::unmap(BufferResource* bufferIn)
glUnmapBuffer(buffer->m_target);
}
-void GLRenderer::setInputLayout(InputLayout* inputLayout)
-{
- m_boundInputLayout = static_cast<InputLayoutImpl*>(inputLayout);
-}
-
void GLRenderer::setPrimitiveTopology(PrimitiveTopology topology)
{
GLenum glTopology = 0;
@@ -849,12 +1022,23 @@ void GLRenderer::setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource
}
}
-void GLRenderer::setShaderProgram(ShaderProgram* programIn)
+void GLRenderer::setIndexBuffer(BufferResource* buffer, Format indexFormat, UInt offset)
+{
+}
+
+void GLRenderer::setDepthStencilTarget(ResourceView* depthStencilView)
{
- ShaderProgramImpl* program = static_cast<ShaderProgramImpl*>(programIn);
- m_boundShaderProgram = program;
+}
+
+void GLRenderer::setPipelineState(PipelineType pipelineType, PipelineState* state)
+{
+ auto pipelineStateImpl = (PipelineStateImpl*) state;
+
+ m_currentPipelineState = pipelineStateImpl;
+
+ auto program = pipelineStateImpl->m_program;
GLuint programID = program ? program->m_id : 0;
- glUseProgram(programID);
+ glUseProgram(programID);
}
void GLRenderer::draw(UInt vertexCount, UInt startVertex = 0)
@@ -864,11 +1048,17 @@ void GLRenderer::draw(UInt vertexCount, UInt startVertex = 0)
glDrawArrays(m_boundPrimitiveTopology, (GLint)startVertex, (GLsizei)vertexCount);
}
+void GLRenderer::drawIndexed(UInt indexCount, UInt startIndex, UInt baseVertex)
+{
+ assert(!"unimplemented");
+}
+
void GLRenderer::dispatchCompute(int x, int y, int z)
{
glDispatchCompute(x, y, z);
}
+#if 0
BindingState* GLRenderer::createBindingState(const BindingState::Desc& bindingStateDesc)
{
RefPtr<BindingStateImpl> bindingState(new BindingStateImpl(bindingStateDesc, this));
@@ -990,8 +1180,168 @@ void GLRenderer::setBindingState(BindingState* stateIn)
}
}
}
+#endif
+
+void GLRenderer::DescriptorSetImpl::setConstantBuffer(UInt range, UInt index, BufferResource* buffer)
+{
+ auto resourceImpl = (BufferResourceImpl*) buffer;
+
+ auto layout = m_layout;
+ auto rangeInfo = layout->m_ranges[range];
+ auto arrayIndex = rangeInfo.arrayIndex + index;
+
+ m_constantBuffers[arrayIndex] = resourceImpl;
+}
+
+void GLRenderer::DescriptorSetImpl::setResource(UInt range, UInt index, ResourceView* view)
+{
+ auto viewImpl = (ResourceViewImpl*) view;
+
+ auto layout = m_layout;
+ auto rangeInfo = layout->m_ranges[range];
+ auto arrayIndex = rangeInfo.arrayIndex + index;
+
+ assert(!"unimplemented");
+}
+
+void GLRenderer::DescriptorSetImpl::setSampler(UInt range, UInt index, SamplerState* sampler)
+{
+ assert(!"unsupported");
+}
+
+void GLRenderer::DescriptorSetImpl::setCombinedTextureSampler(
+ UInt range,
+ UInt index,
+ ResourceView* textureView,
+ SamplerState* sampler)
+{
+ auto viewImpl = (TextureViewImpl*) textureView;
+ auto samplerImpl = (SamplerStateImpl*) sampler;
+
+ auto layout = m_layout;
+ auto rangeInfo = layout->m_ranges[range];
+ auto arrayIndex = rangeInfo.arrayIndex + index;
+
+ m_textures[arrayIndex] = viewImpl;
+ m_samplers[arrayIndex] = samplerImpl;
+}
+
+void GLRenderer::setDescriptorSet(PipelineType pipelineType, PipelineLayout* layout, UInt index, DescriptorSet* descriptorSet)
+{
+ auto descriptorSetImpl = (DescriptorSetImpl*)descriptorSet;
+
+ // TODO: can we just bind things immediately here, rather than shadowing the state?
+
+ m_boundDescriptorSets[index] = descriptorSetImpl;
+}
-ShaderProgram* GLRenderer::createProgram(const ShaderProgram::Desc& desc)
+Result GLRenderer::createDescriptorSetLayout(const DescriptorSetLayout::Desc& desc, DescriptorSetLayout** outLayout)
+{
+ RefPtr<DescriptorSetLayoutImpl> layoutImpl = new DescriptorSetLayoutImpl();
+
+ Int counts[int(GLDescriptorSlotType::CountOf)] = { 0, };
+
+ Int rangeCount = desc.slotRangeCount;
+ for(Int rr = 0; rr < rangeCount; ++rr)
+ {
+ auto rangeDesc = desc.slotRanges[rr];
+ DescriptorSetLayoutImpl::RangeInfo rangeInfo;
+
+ GLDescriptorSlotType glSlotType;
+ switch( rangeDesc.type )
+ {
+ default:
+ assert(!"unsupported");
+ break;
+
+ // TODO: There are many other slot types we could support here,
+ // in particular including storage buffers.
+
+ case DescriptorSlotType::CombinedImageSampler:
+ glSlotType = GLDescriptorSlotType::CombinedTextureSampler;
+ break;
+
+ case DescriptorSlotType::UniformBuffer:
+ case DescriptorSlotType::DynamicUniformBuffer:
+ glSlotType = GLDescriptorSlotType::ConstantBuffer;
+ break;
+ }
+
+ rangeInfo.type = glSlotType;
+ rangeInfo.arrayIndex = counts[int(glSlotType)];
+ counts[int(glSlotType)] += rangeDesc.count;
+
+ layoutImpl->m_ranges.Add(rangeInfo);
+ }
+
+ for( Int ii = 0; ii < int(GLDescriptorSlotType::CountOf); ++ii )
+ {
+ layoutImpl->m_counts[ii] = counts[ii];
+ }
+
+ *outLayout = layoutImpl.detach();
+ return SLANG_OK;
+}
+
+Result GLRenderer::createPipelineLayout(const PipelineLayout::Desc& desc, PipelineLayout** outLayout)
+{
+ RefPtr<PipelineLayoutImpl> layoutImpl = new PipelineLayoutImpl();
+
+ static const int kSlotTypeCount = int(GLDescriptorSlotType::CountOf);
+ Int counts[kSlotTypeCount] = { 0, };
+
+ Int setCount = desc.descriptorSetCount;
+ for( Int ii = 0; ii < setCount; ++ii )
+ {
+ auto setLayout = (DescriptorSetLayoutImpl*) desc.descriptorSets[ii].layout;
+
+ PipelineLayoutImpl::DescriptorSetInfo setInfo;
+ setInfo.layout = setLayout;
+
+ for( Int ii = 0; ii < int(GLDescriptorSlotType::CountOf); ++ii )
+ {
+ setInfo.baseArrayIndex[ii] = counts[ii];
+ counts[ii] += setLayout->m_counts[ii];
+ }
+
+ layoutImpl->m_sets.Add(setInfo);
+ }
+
+ *outLayout = layoutImpl.detach();
+ return SLANG_OK;
+}
+
+Result GLRenderer::createDescriptorSet(DescriptorSetLayout* layout, DescriptorSet** outDescriptorSet)
+{
+ auto layoutImpl = (DescriptorSetLayoutImpl*) layout;
+
+ RefPtr<DescriptorSetImpl> descriptorSetImpl = new DescriptorSetImpl();
+
+ descriptorSetImpl->m_layout = layoutImpl;
+
+ // TODO: storage for the arrays of bound objects could be tail allocated
+ // as part of the descriptor set, with offsets pre-computed in the
+ // descriptor set layout.
+
+ {
+ auto slotTypeIndex = int(GLDescriptorSlotType::ConstantBuffer);
+ auto slotCount = layoutImpl->m_counts[slotTypeIndex];
+ descriptorSetImpl->m_constantBuffers.SetSize(slotCount);
+ }
+
+ {
+ auto slotTypeIndex = int(GLDescriptorSlotType::CombinedTextureSampler);
+ auto slotCount = layoutImpl->m_counts[slotTypeIndex];
+
+ descriptorSetImpl->m_textures.SetSize(slotCount);
+ descriptorSetImpl->m_samplers.SetSize(slotCount);
+ }
+
+ *outDescriptorSet = descriptorSetImpl.detach();
+ return SLANG_OK;
+}
+
+Result GLRenderer::createProgram(const ShaderProgram::Desc& desc, ShaderProgram** outProgram)
{
auto programID = glCreateProgram();
if(desc.pipelineType == PipelineType::Compute )
@@ -1039,10 +1389,37 @@ ShaderProgram* GLRenderer::createProgram(const ShaderProgram::Desc& desc)
::free(infoBuffer);
glDeleteProgram(programID);
- return nullptr;
+ return SLANG_FAIL;
}
- return new ShaderProgramImpl(this, programID);
+ *outProgram = new ShaderProgramImpl(this, programID);
+ return SLANG_OK;
+}
+
+Result GLRenderer::createGraphicsPipelineState(const GraphicsPipelineStateDesc& desc, PipelineState** outState)
+{
+ auto programImpl = (ShaderProgramImpl*) desc.program;
+ auto pipelineLayoutImpl = (PipelineLayoutImpl*) desc.pipelineLayout;
+ auto inputLayoutImpl = (InputLayoutImpl*) desc.inputLayout;
+
+ RefPtr<PipelineStateImpl> pipelineStateImpl = new PipelineStateImpl();
+ pipelineStateImpl->m_program = programImpl;
+ pipelineStateImpl->m_pipelineLayout = pipelineLayoutImpl;
+ pipelineStateImpl->m_inputLayout = inputLayoutImpl;
+ *outState = pipelineStateImpl.detach();
+ return SLANG_OK;
+}
+
+Result GLRenderer::createComputePipelineState(const ComputePipelineStateDesc& desc, PipelineState** outState)
+{
+ auto programImpl = (ShaderProgramImpl*) desc.program;
+ auto pipelineLayoutImpl = (PipelineLayoutImpl*) desc.pipelineLayout;
+
+ RefPtr<PipelineStateImpl> pipelineStateImpl = new PipelineStateImpl();
+ pipelineStateImpl->m_program = programImpl;
+ pipelineStateImpl->m_pipelineLayout = pipelineLayoutImpl;
+ *outState = pipelineStateImpl.detach();
+ return SLANG_OK;
}
diff --git a/tools/slang-graphics/render-gl.h b/tools/gfx/render-gl.h
index 2b211cda4..055031d38 100644
--- a/tools/slang-graphics/render-gl.h
+++ b/tools/gfx/render-gl.h
@@ -1,10 +1,10 @@
// render-d3d11.h
#pragma once
-namespace slang_graphics {
+namespace gfx {
class Renderer;
Renderer* createGLRenderer();
-} // slang_graphics
+} // gfx
diff --git a/tools/slang-graphics/render-vk.cpp b/tools/gfx/render-vk.cpp
index d7cd93e67..27926e0e6 100644
--- a/tools/slang-graphics/render-vk.cpp
+++ b/tools/gfx/render-vk.cpp
@@ -26,33 +26,58 @@
# endif
#endif
-namespace slang_graphics {
+namespace gfx {
using namespace Slang;
class VKRenderer : public Renderer
{
public:
- enum { kMaxRenderTargets = 8, kMaxAttachments = kMaxRenderTargets + 1 };
+ enum
+ {
+ kMaxRenderTargets = 8,
+ kMaxAttachments = kMaxRenderTargets + 1,
+
+ kMaxDescriptorSets = 4,
+ };
// Renderer implementation
virtual SlangResult initialize(const Desc& desc, void* inWindowHandle) override;
virtual void setClearColor(const float color[4]) override;
virtual void clearFrame() override;
virtual void presentFrame() override;
- virtual TextureResource* createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData) override;
- virtual BufferResource* createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& bufferDesc, const void* initData) override;
+ TextureResource::Desc getSwapChainTextureDesc() override;
+
+ Result createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData, TextureResource** outResource) override;
+ Result createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& desc, const void* initData, BufferResource** outResource) override;
+ Result createSamplerState(SamplerState::Desc const& desc, SamplerState** outSampler) override;
+
+ Result createTextureView(TextureResource* texture, ResourceView::Desc const& desc, ResourceView** outView) override;
+ Result createBufferView(BufferResource* buffer, ResourceView::Desc const& desc, ResourceView** outView) override;
+
+ Result createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount, InputLayout** outLayout) override;
+
+ Result createDescriptorSetLayout(const DescriptorSetLayout::Desc& desc, DescriptorSetLayout** outLayout) override;
+ Result createPipelineLayout(const PipelineLayout::Desc& desc, PipelineLayout** outLayout) override;
+ Result createDescriptorSet(DescriptorSetLayout* layout, DescriptorSet** outDescriptorSet) override;
+
+ Result createProgram(const ShaderProgram::Desc& desc, ShaderProgram** outProgram) override;
+ Result createGraphicsPipelineState(const GraphicsPipelineStateDesc& desc, PipelineState** outState) override;
+ Result createComputePipelineState(const ComputePipelineStateDesc& desc, PipelineState** outState) override;
+
virtual SlangResult captureScreenSurface(Surface& surface) override;
- virtual InputLayout* createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount) override;
- virtual BindingState* createBindingState(const BindingState::Desc& bindingStateDesc) override;
- virtual ShaderProgram* createProgram(const ShaderProgram::Desc& desc) override;
+
virtual void* map(BufferResource* buffer, MapFlavor flavor) override;
virtual void unmap(BufferResource* buffer) override;
- virtual void setInputLayout(InputLayout* inputLayout) override;
virtual void setPrimitiveTopology(PrimitiveTopology topology) override;
- virtual void setBindingState(BindingState* state);
+
+ virtual void setDescriptorSet(PipelineType pipelineType, PipelineLayout* layout, UInt index, DescriptorSet* descriptorSet) override;
+
virtual void setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) override;
- virtual void setShaderProgram(ShaderProgram* inProgram) override;
+ virtual void setIndexBuffer(BufferResource* buffer, Format indexFormat, UInt offset) override;
+ virtual void setDepthStencilTarget(ResourceView* depthStencilView) override;
+ virtual void setPipelineState(PipelineType pipelineType, PipelineState* state) override;
virtual void draw(UInt vertexCount, UInt startVertex) override;
+ virtual void drawIndexed(UInt indexCount, UInt startIndex, UInt baseVertex) override;
virtual void dispatchCompute(int x, int y, int z) override;
virtual void submitGpuWork() override;
virtual void waitForGpu() override;
@@ -155,7 +180,63 @@ public:
const VulkanApi* m_api;
};
- class ShaderProgramImpl: public ShaderProgram
+ class SamplerStateImpl : public SamplerState
+ {
+ public:
+ VkSampler m_sampler;
+ };
+
+ class ResourceViewImpl : public ResourceView
+ {
+ public:
+ enum class ViewType
+ {
+ Texture,
+ TexelBuffer,
+ PlainBuffer,
+ };
+ ViewType m_type;
+ };
+
+ class TextureResourceViewImpl : public ResourceViewImpl
+ {
+ public:
+ TextureResourceViewImpl()
+ {
+ m_type = ViewType::Texture;
+ }
+
+ RefPtr<TextureResourceImpl> m_texture;
+ VkImageView m_view;
+ VkImageLayout m_layout;
+ };
+
+ class TexelBufferResourceViewImpl : public ResourceViewImpl
+ {
+ public:
+ TexelBufferResourceViewImpl()
+ {
+ m_type = ViewType::TexelBuffer;
+ }
+
+ RefPtr<BufferResourceImpl> m_buffer;
+ VkBufferView m_view;
+ };
+
+ class PlainBufferResourceViewImpl : public ResourceViewImpl
+ {
+ public:
+ PlainBufferResourceViewImpl()
+ {
+ m_type = ViewType::PlainBuffer;
+ }
+
+ RefPtr<BufferResourceImpl> m_buffer;
+ VkDeviceSize offset;
+ VkDeviceSize size;
+ };
+
+ class ShaderProgramImpl: public ShaderProgram
{
public:
@@ -172,6 +253,85 @@ public:
List<char> m_buffers[2]; //< To keep storage of code in scope
};
+ class DescriptorSetLayoutImpl : public DescriptorSetLayout
+ {
+ public:
+ DescriptorSetLayoutImpl(const VulkanApi& api)
+ : m_api(&api)
+ {
+ }
+
+ ~DescriptorSetLayoutImpl()
+ {
+ if(m_descriptorSetLayout != VK_NULL_HANDLE)
+ {
+ m_api->vkDestroyDescriptorSetLayout(m_api->m_device, m_descriptorSetLayout, nullptr);
+ }
+ if (m_descriptorPool != VK_NULL_HANDLE)
+ {
+ m_api->vkDestroyDescriptorPool(m_api->m_device, m_descriptorPool, nullptr);
+ }
+ }
+
+ VulkanApi const* m_api;
+ VkDescriptorSetLayout m_descriptorSetLayout = VK_NULL_HANDLE;
+ VkDescriptorPool m_descriptorPool = VK_NULL_HANDLE;
+
+ struct RangeInfo
+ {
+ VkDescriptorType descriptorType;
+ };
+ List<RangeInfo> m_ranges;
+ };
+
+ class PipelineLayoutImpl : public PipelineLayout
+ {
+ public:
+ PipelineLayoutImpl(const VulkanApi& api)
+ : m_api(&api)
+ {
+ }
+
+ ~PipelineLayoutImpl()
+ {
+ if (m_pipelineLayout != VK_NULL_HANDLE)
+ {
+ m_api->vkDestroyPipelineLayout(m_api->m_device, m_pipelineLayout, nullptr);
+ }
+ }
+
+ VulkanApi const* m_api;
+ VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;
+ UInt m_descriptorSetCount = 0;
+ };
+
+ class DescriptorSetImpl : public DescriptorSet
+ {
+ public:
+ DescriptorSetImpl(VKRenderer* renderer)
+ : m_renderer(renderer)
+ {
+ }
+
+ ~DescriptorSetImpl()
+ {
+ }
+
+ virtual void setConstantBuffer(UInt range, UInt index, BufferResource* buffer) override;
+ virtual void setResource(UInt range, UInt index, ResourceView* view) override;
+ virtual void setSampler(UInt range, UInt index, SamplerState* sampler) override;
+ virtual void setCombinedTextureSampler(
+ UInt range,
+ UInt index,
+ ResourceView* textureView,
+ SamplerState* sampler) override;
+
+ RefPtr<VKRenderer> m_renderer;
+ RefPtr<DescriptorSetLayoutImpl> m_layout;
+ VkDescriptorSet m_descriptorSet = VK_NULL_HANDLE;
+ };
+
+#if 0
struct BindingDetail
{
VkImageView m_srv = VK_NULL_HANDLE;
@@ -212,6 +372,7 @@ public:
const VulkanApi* m_api;
List<BindingDetail> m_bindingDetails;
};
+#endif
struct BoundVertexBuffer
{
@@ -220,44 +381,30 @@ public:
int m_offset;
};
- class Pipeline : public RefObject
+ class PipelineStateImpl : public PipelineState
{
public:
- Pipeline(const VulkanApi& api):
+ PipelineStateImpl(const VulkanApi& api):
m_api(&api)
{
}
- ~Pipeline()
+ ~PipelineStateImpl()
{
if (m_pipeline != VK_NULL_HANDLE)
{
m_api->vkDestroyPipeline(m_api->m_device, m_pipeline, nullptr);
}
- if (m_descriptorPool != VK_NULL_HANDLE)
- {
- m_api->vkDestroyDescriptorPool(m_api->m_device, m_descriptorPool, nullptr);
- }
- if (m_pipelineLayout != VK_NULL_HANDLE)
- {
- m_api->vkDestroyPipelineLayout(m_api->m_device, m_pipelineLayout, nullptr);
- }
- if(m_descriptorSetLayout != VK_NULL_HANDLE)
- {
- m_api->vkDestroyDescriptorSetLayout(m_api->m_device, m_descriptorSetLayout, nullptr);
- }
}
const VulkanApi* m_api;
- VkPrimitiveTopology m_primitiveTopology;
- RefPtr<BindingStateImpl> m_bindingState;
- RefPtr<InputLayoutImpl> m_inputLayout;
+// VkPrimitiveTopology m_primitiveTopology;
+
+ RefPtr<PipelineLayoutImpl> m_pipelineLayout;
+
+// RefPtr<InputLayoutImpl> m_inputLayout;
RefPtr<ShaderProgramImpl> m_shaderProgram;
- VkDescriptorSetLayout m_descriptorSetLayout = VK_NULL_HANDLE;
- VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;
- VkDescriptorPool m_descriptorPool = VK_NULL_HANDLE;
- VkDescriptorSet m_descriptorSet = VK_NULL_HANDLE;
VkPipeline m_pipeline = VK_NULL_HANDLE;
};
@@ -273,9 +420,9 @@ public:
size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg, void* pUserData);
/// Returns true if m_currentPipeline matches the current configuration
- Pipeline* _getPipeline();
- bool _isEqual(const Pipeline& pipeline) const;
- Slang::Result _createPipeline(RefPtr<Pipeline>& pipelineOut);
+// Pipeline* _getPipeline();
+// bool _isEqual(const Pipeline& pipeline) const;
+// Slang::Result _createPipeline(RefPtr<Pipeline>& pipelineOut);
void _beginRender();
void _endRender();
@@ -285,12 +432,18 @@ public:
VkDebugReportCallbackEXT m_debugReportCallback;
- RefPtr<InputLayoutImpl> m_currentInputLayout;
- RefPtr<BindingStateImpl> m_currentBindingState;
- RefPtr<ShaderProgramImpl> m_currentProgram;
+// RefPtr<InputLayoutImpl> m_currentInputLayout;
+
+// RefPtr<BindingStateImpl> m_currentBindingState;
+ RefPtr<PipelineLayoutImpl> m_currentPipelineLayout;
+
+ RefPtr<DescriptorSetImpl> m_currentDescriptorSetImpls [kMaxDescriptorSets];
+ VkDescriptorSet m_currentDescriptorSets [kMaxDescriptorSets];
+
+// RefPtr<ShaderProgramImpl> m_currentProgram;
- List<RefPtr<Pipeline> > m_pipelineCache;
- Pipeline* m_currentPipeline = nullptr;
+// List<RefPtr<Pipeline> > m_pipelineCache;
+ RefPtr<PipelineStateImpl> m_currentPipeline;
List<BoundVertexBuffer> m_boundVertexBuffers;
@@ -349,10 +502,11 @@ Result VKRenderer::Buffer::init(const VulkanApi& api, size_t bufferSize, VkBuffe
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! VkRenderer !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+#if 0
bool VKRenderer::_isEqual(const Pipeline& pipeline) const
{
return
- pipeline.m_bindingState == m_currentBindingState &&
+ pipeline.m_pipelineLayout == m_currentPipelineLayout &&
pipeline.m_primitiveTopology == m_primitiveTopology &&
pipeline.m_inputLayout == m_currentInputLayout &&
pipeline.m_shaderProgram == m_currentProgram;
@@ -389,266 +543,13 @@ Slang::Result VKRenderer::_createPipeline(RefPtr<Pipeline>& pipelineOut)
// Initialize the state
pipeline->m_primitiveTopology = m_primitiveTopology;
- pipeline->m_bindingState = m_currentBindingState;
+ pipeline->m_pipelineLayout = m_currentPipelineLayout;
pipeline->m_shaderProgram = m_currentProgram;
pipeline->m_inputLayout = m_currentInputLayout;
// Must be equal at this point if all the items are correctly set in pipeline
assert(_isEqual(*pipeline));
- // First create a pipeline layout based on what is bound
-
- const auto& srcDetails = m_currentBindingState->m_bindingDetails;
- const auto& srcBindings = m_currentBindingState->getDesc().m_bindings;
-
- const int numBindings = int(srcBindings.Count());
-
- int numBuffers = 0;
- int numImages = 0;
-
- int numDescriptorByType[VK_DESCRIPTOR_TYPE_RANGE_SIZE] = { 0, };
-
- Slang::List<VkDescriptorSetLayoutBinding> dstBindings;
- for (int i = 0; i < numBindings; ++i)
- {
- const auto& srcDetail = srcDetails[i];
- const auto& srcBinding = srcBindings[i];
-
- VkDescriptorSetLayoutBinding dstBinding = {};
-
- dstBinding.descriptorCount = 1;
-
- switch (srcBinding.bindingType)
- {
- case BindingType::Buffer:
- {
- BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(srcBinding.resource.Ptr());
- const BufferResource::Desc& bufferResourceDesc = bufferResource->getDesc();
-
- if (bufferResourceDesc.bindFlags & Resource::BindFlag::UnorderedAccess)
- {
- dstBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
- dstBinding.stageFlags = VK_SHADER_STAGE_ALL;
- dstBindings.Add(dstBinding);
-
- numDescriptorByType[dstBinding.descriptorType] ++;
- numBuffers++;
- }
- else if (bufferResourceDesc.bindFlags & Resource::BindFlag::ConstantBuffer)
- {
- dstBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- dstBinding.stageFlags = VK_SHADER_STAGE_ALL;
- dstBindings.Add(dstBinding);
-
- numDescriptorByType[dstBinding.descriptorType] ++;
- numBuffers++;
- }
- break;
- }
- case BindingType::Texture:
- {
- dstBinding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
- dstBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
- dstBindings.Add(dstBinding);
-
- numDescriptorByType[dstBinding.descriptorType] ++;
- numImages++;
- break;
- }
- case BindingType::Sampler:
- {
- dstBinding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
- dstBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
- dstBindings.Add(dstBinding);
-
- numDescriptorByType[dstBinding.descriptorType] ++;
- numImages++;
- break;
- }
-
- case BindingType::CombinedTextureSampler:
- {
- dstBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
- dstBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
- dstBindings.Add(dstBinding);
-
- numDescriptorByType[dstBinding.descriptorType] ++;
- numImages++;
- break;
- }
- default:
- {
- assert(!"Unhandled type");
- return SLANG_FAIL;
- }
- }
- }
-
- // Create a descriptor pool for allocating sets
- {
-#if 0
- VkDescriptorPoolSize poolSizes[] =
- {
- { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 128 },
- { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 128 },
- { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 128 },
- };
-#endif
-
- List<VkDescriptorPoolSize> poolSizes;
- for (int i = 0; i < SLANG_COUNT_OF(numDescriptorByType); ++i)
- {
- int numDescriptors = numDescriptorByType[i];
- if (numDescriptors > 0)
- {
- const VkDescriptorPoolSize poolSize = { VkDescriptorType(i), uint32_t(numDescriptors) };
- poolSizes.Add(poolSize);
- }
- }
- VkDescriptorPoolCreateInfo descriptorPoolInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
-
- descriptorPoolInfo.maxSets = 128; // TODO: actually pick a size.
- descriptorPoolInfo.poolSizeCount = uint32_t(poolSizes.Count());
- descriptorPoolInfo.pPoolSizes = poolSizes.Buffer();
-
- SLANG_VK_CHECK(m_api.vkCreateDescriptorPool(m_device, &descriptorPoolInfo, nullptr, &pipeline->m_descriptorPool));
- }
-
- // Create the layout
- {
- VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
- descriptorSetLayoutInfo.bindingCount = uint32_t(dstBindings.Count());
- descriptorSetLayoutInfo.pBindings = dstBindings.Buffer();
-
- SLANG_VK_CHECK(m_api.vkCreateDescriptorSetLayout(m_device, &descriptorSetLayoutInfo, nullptr, &pipeline->m_descriptorSetLayout));
- }
-
- // Create a descriptor set based on our layout
- {
- VkDescriptorSetAllocateInfo descriptorSetAllocInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
- descriptorSetAllocInfo.descriptorPool = pipeline->m_descriptorPool;
- descriptorSetAllocInfo.descriptorSetCount = 1;
- descriptorSetAllocInfo.pSetLayouts = &pipeline->m_descriptorSetLayout;
-
- SLANG_VK_CHECK(m_api.vkAllocateDescriptorSets(m_device, &descriptorSetAllocInfo, &pipeline->m_descriptorSet));
- }
-
- // Fill in the descriptor set, using our binding information
-
- List<VkDescriptorImageInfo> imageInfos;
- List<VkDescriptorBufferInfo> bufferInfos;
- List<VkWriteDescriptorSet> writes;
-
- // Make sure there is enough space...
- imageInfos.Reserve(numImages);
- bufferInfos.Reserve(numBuffers);
-
- int elementIndex = 0;
-
- for (int i = 0; i < numBindings; ++i)
- {
- const auto& srcDetail = srcDetails[i];
- const auto& srcBinding = srcBindings[i];
-
- const int bindingIndex = srcBinding.registerRange.getSingleIndex();
-
- VkWriteDescriptorSet writeInfo = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
- writeInfo.descriptorCount = 1;
- writeInfo.dstSet = pipeline->m_descriptorSet;
- writeInfo.dstBinding = bindingIndex;
- writeInfo.dstArrayElement = 0;
-
- switch (srcBinding.bindingType)
- {
- case BindingType::Buffer:
- {
- assert(srcBinding.resource && srcBinding.resource->isBuffer());
- BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(srcBinding.resource.Ptr());
- const BufferResource::Desc& bufferResourceDesc = bufferResource->getDesc();
-
- {
- VkDescriptorBufferInfo bufferInfo;
- bufferInfo.buffer = bufferResource->m_buffer.m_buffer;
- bufferInfo.offset = 0;
- bufferInfo.range = bufferResourceDesc.sizeInBytes;
-
- bufferInfos.Add(bufferInfo);
- }
-
- writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
- if (bufferResource->m_initialUsage == Resource::Usage::UnorderedAccess)
- {
- writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
- }
- else if (bufferResource->m_initialUsage == Resource::Usage::ConstantBuffer)
- {
- writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- }
-
- writeInfo.pBufferInfo = &bufferInfos.Last();
-
- writes.Add(writeInfo);
- break;
- }
- case BindingType::Texture:
- {
- assert(srcBinding.resource && srcBinding.resource->isTexture());
-
- TextureResourceImpl* textureResource = static_cast<TextureResourceImpl*>(srcBinding.resource.Ptr());
- const TextureResource::Desc& textureResourceDesc = textureResource->getDesc();
-
- {
- VkDescriptorImageInfo imageInfo = {};
- imageInfo.imageView = srcDetail.m_srv;
- imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- imageInfos.Add(imageInfo);
- }
-
- writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
- writeInfo.pImageInfo = &imageInfos.Last();
-
- writes.Add(writeInfo);
- break;
- }
- case BindingType::Sampler:
- {
- {
- VkDescriptorImageInfo imageInfo = {};
- imageInfo.sampler = srcDetail.m_sampler;
- //imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- imageInfos.Add(imageInfo);
- }
-
- writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
- writeInfo.pImageInfo = &imageInfos.Last();
-
- writes.Add(writeInfo);
- break;
- }
- default:
- {
- assert(!"Binding not currently handled");
- return SLANG_FAIL;
- }
- }
- }
-
- assert(imageInfos.Count() == numImages);
- assert(bufferInfos.Count() == numBuffers);
-
- // Write into the descriptor set
- {
- m_api.vkUpdateDescriptorSets(m_device, uint32_t(writes.Count()), writes.Buffer(), 0, nullptr);
- }
-
- // 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 = &pipeline->m_descriptorSetLayout;
-
- SLANG_VK_CHECK(m_api.vkCreatePipelineLayout(m_device, &pipelineLayoutInfo, nullptr, &pipeline->m_pipelineLayout));
-
VkPipelineCache pipelineCache = VK_NULL_HANDLE;
if (m_currentProgram->m_pipelineType == PipelineType::Compute)
@@ -657,7 +558,7 @@ Slang::Result VKRenderer::_createPipeline(RefPtr<Pipeline>& pipelineOut)
VkComputePipelineCreateInfo computePipelineInfo = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO };
computePipelineInfo.stage = m_currentProgram->m_compute;
- computePipelineInfo.layout = pipeline->m_pipelineLayout;
+ computePipelineInfo.layout = pipeline->m_pipelineLayout->m_pipelineLayout;
SLANG_VK_CHECK(m_api.vkCreateComputePipelines(m_device, pipelineCache, 1, &computePipelineInfo, nullptr, &pipeline->m_pipeline));
}
@@ -762,7 +663,7 @@ Slang::Result VKRenderer::_createPipeline(RefPtr<Pipeline>& pipelineOut)
pipelineInfo.pRasterizationState = &rasterizer;
pipelineInfo.pMultisampleState = &multisampling;
pipelineInfo.pColorBlendState = &colorBlending;
- pipelineInfo.layout = pipeline->m_pipelineLayout;
+ pipelineInfo.layout = pipeline->m_pipelineLayout->m_pipelineLayout;
pipelineInfo.renderPass = m_renderPass;
pipelineInfo.subpass = 0;
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
@@ -778,6 +679,7 @@ Slang::Result VKRenderer::_createPipeline(RefPtr<Pipeline>& pipelineOut)
pipelineOut = pipeline;
return SLANG_OK;
}
+#endif
Result VKRenderer::_beginPass()
{
@@ -1190,6 +1092,13 @@ void VKRenderer::presentFrame()
_beginRender();
}
+TextureResource::Desc VKRenderer::getSwapChainTextureDesc()
+{
+ TextureResource::Desc desc;
+ desc.init2D(Resource::Type::Texture2D, Format::Unknown, m_desc.width, m_desc.height, 1);
+ return desc;
+}
+
SlangResult VKRenderer::captureScreenSurface(Surface& surfaceOut)
{
return SLANG_FAIL;
@@ -1345,7 +1254,7 @@ void VKRenderer::_transitionImageLayout(VkImage image, VkFormat format, const Te
m_api.vkCmdPipelineBarrier(commandBuffer, sourceStage, destinationStage, 0, 0, nullptr, 0, nullptr, 1, &barrier);
}
-TextureResource* VKRenderer::createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& descIn, const TextureResource::Data* initData)
+Result VKRenderer::createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& descIn, const TextureResource::Data* initData, TextureResource** outResource)
{
TextureResource::Desc desc(descIn);
desc.setDefaults(initialUsage);
@@ -1354,7 +1263,7 @@ TextureResource* VKRenderer::createTextureResource(Resource::Usage initialUsage,
if (format == VK_FORMAT_UNDEFINED)
{
assert(!"Unhandled image format");
- return nullptr;
+ return SLANG_FAIL;
}
const int arraySize = desc.calcEffectiveArraySize();
@@ -1397,7 +1306,7 @@ TextureResource* VKRenderer::createTextureResource(Resource::Usage initialUsage,
default:
{
assert(!"Unhandled type");
- return nullptr;
+ return SLANG_FAIL;
}
}
@@ -1413,7 +1322,7 @@ TextureResource* VKRenderer::createTextureResource(Resource::Usage initialUsage,
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageInfo.flags = 0; // Optional
- SLANG_VK_RETURN_NULL_ON_FAIL(m_api.vkCreateImage(m_device, &imageInfo, nullptr, &texture->m_image));
+ SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateImage(m_device, &imageInfo, nullptr, &texture->m_image));
}
VkMemoryRequirements memRequirements;
@@ -1433,7 +1342,7 @@ TextureResource* VKRenderer::createTextureResource(Resource::Usage initialUsage,
allocInfo.allocationSize = memRequirements.size;
allocInfo.memoryTypeIndex = memoryTypeIndex;
- SLANG_VK_RETURN_NULL_ON_FAIL(m_api.vkAllocateMemory(m_device, &allocInfo, nullptr, &texture->m_imageMemory));
+ SLANG_VK_RETURN_ON_FAIL(m_api.vkAllocateMemory(m_device, &allocInfo, nullptr, &texture->m_imageMemory));
}
// Bind the memory to the image
@@ -1468,7 +1377,7 @@ TextureResource* VKRenderer::createTextureResource(Resource::Usage initialUsage,
bufferSize *= arraySize;
Buffer uploadBuffer;
- SLANG_RETURN_NULL_ON_FAIL(uploadBuffer.init(m_api, bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT));
+ SLANG_RETURN_ON_FAIL(uploadBuffer.init(m_api, bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT));
assert(mipSizes.Count() == numMipMaps);
@@ -1554,10 +1463,11 @@ TextureResource* VKRenderer::createTextureResource(Resource::Usage initialUsage,
m_deviceQueue.flushAndWait();
}
- return texture.detach();
+ *outResource = texture.detach();
+ return SLANG_OK;
}
-BufferResource* VKRenderer::createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& descIn, const void* initData)
+Result VKRenderer::createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& descIn, const void* initData, BufferResource** outResource)
{
BufferResource::Desc desc(descIn);
desc.setDefaults(initialUsage);
@@ -1579,11 +1489,11 @@ BufferResource* VKRenderer::createBufferResource(Resource::Usage initialUsage, c
}
RefPtr<BufferResourceImpl> buffer(new BufferResourceImpl(initialUsage, desc, this));
- SLANG_RETURN_NULL_ON_FAIL(buffer->m_buffer.init(m_api, desc.sizeInBytes, usage, reqMemoryProperties));
+ SLANG_RETURN_ON_FAIL(buffer->m_buffer.init(m_api, desc.sizeInBytes, usage, reqMemoryProperties));
if ((desc.cpuAccessFlags & Resource::AccessFlag::Write) || initData)
{
- SLANG_RETURN_NULL_ON_FAIL(buffer->m_uploadBuffer.init(m_api, bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT));
+ SLANG_RETURN_ON_FAIL(buffer->m_uploadBuffer.init(m_api, bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT));
}
if (initData)
@@ -1607,10 +1517,200 @@ BufferResource* VKRenderer::createBufferResource(Resource::Usage initialUsage, c
//flushCommandBuffer(commandBuffer);
}
- return buffer.detach();
+ *outResource = buffer.detach();
+ return SLANG_OK;
+}
+
+
+VkFilter translateFilterMode(TextureFilteringMode mode)
+{
+ switch (mode)
+ {
+ default:
+ return VkFilter(0);
+
+#define CASE(SRC, DST) \
+ case TextureFilteringMode::SRC: return VK_FILTER_##DST
+
+ CASE(Point, NEAREST);
+ CASE(Linear, LINEAR);
+
+#undef CASE
+ }
+}
+
+VkSamplerMipmapMode translateMipFilterMode(TextureFilteringMode mode)
+{
+ switch (mode)
+ {
+ default:
+ return VkSamplerMipmapMode(0);
+
+#define CASE(SRC, DST) \
+ case TextureFilteringMode::SRC: return VK_SAMPLER_MIPMAP_MODE_##DST
+
+ CASE(Point, NEAREST);
+ CASE(Linear, LINEAR);
+
+#undef CASE
+ }
+}
+
+VkSamplerAddressMode translateAddressingMode(TextureAddressingMode mode)
+{
+ switch (mode)
+ {
+ default:
+ return VkSamplerAddressMode(0);
+
+#define CASE(SRC, DST) \
+ case TextureAddressingMode::SRC: return VK_SAMPLER_ADDRESS_MODE_##DST
+
+ CASE(Wrap, REPEAT);
+ CASE(ClampToEdge, CLAMP_TO_EDGE);
+ CASE(ClampToBorder, CLAMP_TO_BORDER);
+ CASE(MirrorRepeat, MIRRORED_REPEAT);
+ CASE(MirrorOnce, MIRROR_CLAMP_TO_EDGE);
+
+#undef CASE
+ }
+}
+
+static VkCompareOp translateComparisonFunc(ComparisonFunc func)
+{
+ switch (func)
+ {
+ default:
+ // TODO: need to report failures
+ return VK_COMPARE_OP_ALWAYS;
+
+#define CASE(FROM, TO) \
+ case ComparisonFunc::FROM: return VK_COMPARE_OP_##TO
+
+ CASE(Never, NEVER);
+ CASE(Less, LESS);
+ CASE(Equal, EQUAL);
+ CASE(LessEqual, LESS_OR_EQUAL);
+ CASE(Greater, GREATER);
+ CASE(NotEqual, NOT_EQUAL);
+ CASE(GreaterEqual, GREATER_OR_EQUAL);
+ CASE(Always, ALWAYS);
+#undef CASE
+ }
+}
+
+Result VKRenderer::createSamplerState(SamplerState::Desc const& desc, SamplerState** outSampler)
+{
+ VkSamplerCreateInfo samplerInfo = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
+
+ samplerInfo.magFilter = translateFilterMode(desc.minFilter);
+ samplerInfo.minFilter = translateFilterMode(desc.magFilter);
+
+ samplerInfo.addressModeU = translateAddressingMode(desc.addressU);
+ samplerInfo.addressModeV = translateAddressingMode(desc.addressV);
+ samplerInfo.addressModeW = translateAddressingMode(desc.addressW);
+
+ samplerInfo.anisotropyEnable = desc.maxAnisotropy > 1;
+ samplerInfo.maxAnisotropy = (float) desc.maxAnisotropy;
+
+ // TODO: support translation of border color...
+ samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
+
+ samplerInfo.unnormalizedCoordinates = VK_FALSE;
+ samplerInfo.compareEnable = desc.reductionOp == TextureReductionOp::Comparison;
+ samplerInfo.compareOp = translateComparisonFunc(desc.comparisonFunc);
+ samplerInfo.mipmapMode = translateMipFilterMode(desc.mipFilter);
+
+ VkSampler sampler;
+ SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateSampler(m_device, &samplerInfo, nullptr, &sampler));
+
+ RefPtr<SamplerStateImpl> samplerImpl = new SamplerStateImpl();
+ samplerImpl->m_sampler = sampler;
+ *outSampler = samplerImpl.detach();
+ return SLANG_OK;
+}
+
+Result VKRenderer::createTextureView(TextureResource* texture, ResourceView::Desc const& desc, ResourceView** outView)
+{
+ assert(!"unimplemented");
+ return SLANG_FAIL;
+}
+
+Result VKRenderer::createBufferView(BufferResource* buffer, ResourceView::Desc const& desc, ResourceView** outView)
+{
+ auto resourceImpl = (BufferResourceImpl*) buffer;
+
+ // TODO: These should come from the `ResourceView::Desc`
+ VkDeviceSize offset = 0;
+ VkDeviceSize size = resourceImpl->getDesc().sizeInBytes;
+
+ // There are two different cases we need to think about for buffers.
+ //
+ // One is when we have a "uniform texel buffer" or "storage texel buffer,"
+ // in which case we need to construct a `VkBufferView` to represent the
+ // formatting that is applied to the buffer. This case would correspond
+ // to a `textureBuffer` or `imageBuffer` in GLSL, and more or less to
+ // `Buffer<..>` or `RWBuffer<...>` in HLSL.
+ //
+ // The other case is a `storage buffer` which is the catch-all for any
+ // non-formatted R/W access to a buffer. In GLSL this is a `buffer { ... }`
+ // declaration, while in HLSL it covers a bunch of different `RW*Buffer`
+ // cases. In these cases we do *not* need a `VkBufferView`, but in
+ // order to be compatible with other APIs that require views for any
+ // potentially writable access, we will have to create one anyway.
+ //
+ // We will distinguish the two cases by looking at whether the view
+ // is being requested with a format or not.
+ //
+
+ switch(desc.type)
+ {
+ default:
+ assert(!"unhandled");
+ return SLANG_FAIL;
+
+ case ResourceView::Type::UnorderedAccess:
+ // Is this a formatted view?
+ //
+ if(desc.format == Format::Unknown)
+ {
+ // Buffer usage that doesn't involve formatting doesn't
+ // require a view in Vulkan.
+ RefPtr<PlainBufferResourceViewImpl> viewImpl = new PlainBufferResourceViewImpl();
+ viewImpl->m_buffer = resourceImpl;
+ viewImpl->offset = 0;
+ viewImpl->size = size;
+ *outView = viewImpl.detach();
+ return SLANG_OK;
+ }
+ //
+ // If the view is formatted, then we need to handle
+ // it just like we would for a "sampled" buffer:
+ //
+ // FALLTHROUGH
+ case ResourceView::Type::ShaderResource:
+ {
+ VkBufferViewCreateInfo info = { VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO };
+
+ info.format = VulkanUtil::getVkFormat(desc.format);
+ info.buffer = resourceImpl->m_buffer.m_buffer;
+ info.offset = offset;
+ info.range = size;
+
+ VkBufferView view;
+ SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateBufferView(m_device, &info, nullptr, &view));
+
+ RefPtr<TexelBufferResourceViewImpl> viewImpl = new TexelBufferResourceViewImpl();
+ viewImpl->m_buffer = resourceImpl;
+ viewImpl->m_view = view;
+ *outView = viewImpl.detach();
+ return SLANG_OK;
+ }
+ break;
+ }
}
-InputLayout* VKRenderer::createInputLayout(const InputElementDesc* elements, UInt numElements)
+Result VKRenderer::createInputLayout(const InputElementDesc* elements, UInt numElements, InputLayout** outLayout)
{
RefPtr<InputLayoutImpl> layout(new InputLayoutImpl);
@@ -1629,7 +1729,7 @@ InputLayout* VKRenderer::createInputLayout(const InputElementDesc* elements, UIn
dstDesc.format = VulkanUtil::getVkFormat(srcDesc.format);
if (dstDesc.format == VK_FORMAT_UNDEFINED)
{
- return nullptr;
+ return SLANG_FAIL;
}
dstDesc.offset = uint32_t(srcDesc.offset);
@@ -1643,7 +1743,8 @@ InputLayout* VKRenderer::createInputLayout(const InputElementDesc* elements, UIn
// Work out the overall size
layout->m_vertexSize = int(vertexSize);
- return layout.detach();
+ *outLayout = layout.detach();
+ return SLANG_OK;
}
void* VKRenderer::map(BufferResource* bufferIn, MapFlavor flavor)
@@ -1738,11 +1839,6 @@ void VKRenderer::unmap(BufferResource* bufferIn)
buffer->m_mapFlavor = MapFlavor::Unknown;
}
-void VKRenderer::setInputLayout(InputLayout* inputLayout)
-{
- m_currentInputLayout = static_cast<InputLayoutImpl*>(inputLayout);
-}
-
void VKRenderer::setPrimitiveTopology(PrimitiveTopology topology)
{
m_primitiveTopology = VulkanUtil::getVkPrimitiveTopology(topology);
@@ -1773,14 +1869,22 @@ void VKRenderer::setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource
}
}
-void VKRenderer::setShaderProgram(ShaderProgram* program)
+void VKRenderer::setIndexBuffer(BufferResource* buffer, Format indexFormat, UInt offset)
{
- m_currentProgram = (ShaderProgramImpl*)program;
+}
+
+void VKRenderer::setDepthStencilTarget(ResourceView* depthStencilView)
+{
+}
+
+void VKRenderer::setPipelineState(PipelineType pipelineType, PipelineState* state)
+{
+ m_currentPipeline = (PipelineStateImpl*)state;
}
void VKRenderer::draw(UInt vertexCount, UInt startVertex = 0)
{
- Pipeline* pipeline = _getPipeline();
+ auto pipeline = m_currentPipeline;
if (!pipeline || pipeline->m_shaderProgram->m_pipelineType != PipelineType::Graphics)
{
assert(!"Invalid render pipeline");
@@ -1793,8 +1897,12 @@ void VKRenderer::draw(UInt vertexCount, UInt startVertex = 0)
VkCommandBuffer commandBuffer = m_deviceQueue.getCommandBuffer();
m_api.vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->m_pipeline);
- m_api.vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->m_pipelineLayout,
- 0, 1, &pipeline->m_descriptorSet, 0, nullptr);
+
+ auto pipelineLayoutImpl = pipeline->m_pipelineLayout.Ptr();
+ m_api.vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayoutImpl->m_pipelineLayout,
+ 0, pipelineLayoutImpl->m_descriptorSetCount,
+ &m_currentDescriptorSets[0],
+ 0, nullptr);
// Bind the vertex buffer
if (m_boundVertexBuffers.Count() > 0 && m_boundVertexBuffers[0].m_buffer)
@@ -1812,12 +1920,16 @@ void VKRenderer::draw(UInt vertexCount, UInt startVertex = 0)
_endPass();
}
+void VKRenderer::drawIndexed(UInt indexCount, UInt startIndex, UInt baseVertex)
+{
+}
+
void VKRenderer::dispatchCompute(int x, int y, int z)
{
- Pipeline* pipeline = _getPipeline();
+ auto pipeline = m_currentPipeline;
if (!pipeline || pipeline->m_shaderProgram->m_pipelineType != PipelineType::Compute)
{
- assert(!"Invalid render pipeline");
+ assert(!"Invalid compute pipeline");
return;
}
@@ -1826,8 +1938,11 @@ void VKRenderer::dispatchCompute(int x, int y, int z)
m_api.vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->m_pipeline);
- m_api.vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->m_pipelineLayout,
- 0, 1, &pipeline->m_descriptorSet, 0, nullptr);
+ auto pipelineLayoutImpl = pipeline->m_pipelineLayout.Ptr();
+ m_api.vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayoutImpl->m_pipelineLayout,
+ 0, pipelineLayoutImpl->m_descriptorSetCount,
+ &m_currentDescriptorSets[0],
+ 0, nullptr);
m_api.vkCmdDispatch(commandBuffer, x, y, z);
}
@@ -1855,7 +1970,7 @@ static VkImageViewType _calcImageViewType(TextureResource::Type type, const Text
return VK_IMAGE_VIEW_TYPE_MAX_ENUM;
}
-
+#if 0
BindingState* VKRenderer::createBindingState(const BindingState::Desc& bindingStateDesc)
{
RefPtr<BindingStateImpl> bindingState(new BindingStateImpl(bindingStateDesc, &m_api));
@@ -1991,13 +2106,268 @@ BindingState* VKRenderer::createBindingState(const BindingState::Desc& bindingSt
return bindingState.detach();;
}
+#endif
+
+static VkDescriptorType translateDescriptorType(DescriptorSlotType type)
+{
+ switch(type)
+ {
+ default:
+ return VK_DESCRIPTOR_TYPE_MAX_ENUM;
+
+#define CASE(SRC, DST) \
+ case DescriptorSlotType::SRC: return VK_DESCRIPTOR_TYPE_##DST
+
+ CASE(Sampler, SAMPLER);
+ CASE(CombinedImageSampler, COMBINED_IMAGE_SAMPLER);
+ CASE(SampledImage, SAMPLED_IMAGE);
+ CASE(StorageImage, STORAGE_IMAGE);
+ CASE(UniformTexelBuffer, UNIFORM_TEXEL_BUFFER);
+ CASE(StorageTexelBuffer, STORAGE_TEXEL_BUFFER);
+ CASE(UniformBuffer, UNIFORM_BUFFER);
+ CASE(StorageBuffer, STORAGE_BUFFER);
+ CASE(DynamicUniformBuffer, UNIFORM_BUFFER_DYNAMIC);
+ CASE(DynamicStorageBuffer, STORAGE_BUFFER_DYNAMIC);
+ CASE(InputAttachment, INPUT_ATTACHMENT);
+
+#undef CASE
+ }
+}
+
+Result VKRenderer::createDescriptorSetLayout(const DescriptorSetLayout::Desc& desc, DescriptorSetLayout** outLayout)
+{
+ RefPtr<DescriptorSetLayoutImpl> descriptorSetLayoutImpl = new DescriptorSetLayoutImpl(m_api);
+
+ Slang::List<VkDescriptorSetLayoutBinding> dstBindings;
+
+ uint32_t descriptorCountForTypes[VK_DESCRIPTOR_TYPE_RANGE_SIZE] = { 0, };
+
+ UInt rangeCount = desc.slotRangeCount;
+ for(UInt rr = 0; rr < rangeCount; ++rr)
+ {
+ auto& srcRange = desc.slotRanges[rr];
+
+ VkDescriptorType dstDescriptorType = translateDescriptorType(srcRange.type);
+
+ VkDescriptorSetLayoutBinding dstBinding;
+ dstBinding.binding = rr;
+ dstBinding.descriptorType = dstDescriptorType;
+ dstBinding.descriptorCount = srcRange.count;
+ dstBinding.stageFlags = VK_SHADER_STAGE_ALL;
+ dstBinding.pImmutableSamplers = nullptr;
+
+ descriptorCountForTypes[dstDescriptorType] += srcRange.count;
+
+ dstBindings.Add(dstBinding);
+
+ DescriptorSetLayoutImpl::RangeInfo rangeInfo;
+ rangeInfo.descriptorType = dstDescriptorType;
+ descriptorSetLayoutImpl->m_ranges.Add(rangeInfo);
+ }
+
+ VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
+ descriptorSetLayoutInfo.bindingCount = uint32_t(dstBindings.Count());
+ descriptorSetLayoutInfo.pBindings = dstBindings.Buffer();
+
+ VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE;
+ SLANG_VK_CHECK(m_api.vkCreateDescriptorSetLayout(m_device, &descriptorSetLayoutInfo, nullptr, &descriptorSetLayout));
+
+ // Create a pool while we are at it, to allocate descriptor sets of this type.
+
+ VkDescriptorPoolSize poolSizes[VK_DESCRIPTOR_TYPE_RANGE_SIZE];
+ uint32_t poolSizeCount = 0;
+ for (int ii = 0; ii < SLANG_COUNT_OF(descriptorCountForTypes); ++ii)
+ {
+ auto descriptorCount = descriptorCountForTypes[ii];
+ if (descriptorCount > 0)
+ {
+ poolSizes[poolSizeCount].type = VkDescriptorType(ii);
+ poolSizes[poolSizeCount].descriptorCount = descriptorCount;
+ poolSizeCount++;
+ }
+ }
+
+ VkDescriptorPoolCreateInfo descriptorPoolInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
+ descriptorPoolInfo.maxSets = 128; // TODO: actually pick a size.
+ descriptorPoolInfo.poolSizeCount = poolSizeCount;
+ descriptorPoolInfo.pPoolSizes = &poolSizes[0];
+
+ VkDescriptorPool descriptorPool = VK_NULL_HANDLE;
+ SLANG_VK_CHECK(m_api.vkCreateDescriptorPool(m_device, &descriptorPoolInfo, nullptr, &descriptorPool));
+
+ descriptorSetLayoutImpl->m_descriptorSetLayout = descriptorSetLayout;
+ descriptorSetLayoutImpl->m_descriptorPool = descriptorPool;
+
+ *outLayout = descriptorSetLayoutImpl.detach();
+ return SLANG_OK;
+}
+
+Result VKRenderer::createPipelineLayout(const PipelineLayout::Desc& desc, PipelineLayout** outLayout)
+{
+ UInt descriptorSetCount = desc.descriptorSetCount;
+
+ VkDescriptorSetLayout descriptorSetLayouts[kMaxDescriptorSets];
+ for(UInt ii = 0; ii < descriptorSetCount; ++ii)
+ {
+ descriptorSetLayouts[ii] = ((DescriptorSetLayoutImpl*) desc.descriptorSets[ii].layout)->m_descriptorSetLayout;
+ }
+
+ VkPipelineLayoutCreateInfo pipelineLayoutInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
+ pipelineLayoutInfo.setLayoutCount = desc.descriptorSetCount;
+ pipelineLayoutInfo.pSetLayouts = &descriptorSetLayouts[0];
+
+ VkPipelineLayout pipelineLayout;
+ SLANG_VK_CHECK(m_api.vkCreatePipelineLayout(m_device, &pipelineLayoutInfo, nullptr, &pipelineLayout));
+
+ RefPtr<PipelineLayoutImpl> pipelineLayoutImpl = new PipelineLayoutImpl(m_api);
+ pipelineLayoutImpl->m_pipelineLayout = pipelineLayout;
+ pipelineLayoutImpl->m_descriptorSetCount = descriptorSetCount;
+
+ *outLayout = pipelineLayoutImpl.detach();
+ return SLANG_OK;
+}
+
+Result VKRenderer::createDescriptorSet(DescriptorSetLayout* layout, DescriptorSet** outDescriptorSet)
+{
+ auto layoutImpl = (DescriptorSetLayoutImpl*)layout;
+
+ VkDescriptorSetAllocateInfo descriptorSetAllocInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
+ descriptorSetAllocInfo.descriptorPool = layoutImpl->m_descriptorPool;
+ descriptorSetAllocInfo.descriptorSetCount = 1;
+ descriptorSetAllocInfo.pSetLayouts = &layoutImpl->m_descriptorSetLayout;
+
+ VkDescriptorSet descriptorSet;
+ SLANG_VK_CHECK(m_api.vkAllocateDescriptorSets(m_device, &descriptorSetAllocInfo, &descriptorSet));
+
+ RefPtr<DescriptorSetImpl> descriptorSetImpl = new DescriptorSetImpl(this);
+ descriptorSetImpl->m_layout = layoutImpl;
+ descriptorSetImpl->m_descriptorSet = descriptorSet;
+ *outDescriptorSet = descriptorSetImpl.detach();
+ return SLANG_OK;
+}
+
+void VKRenderer::DescriptorSetImpl::setConstantBuffer(UInt range, UInt index, BufferResource* buffer)
+{
+ auto bufferImpl = (BufferResourceImpl*)buffer;
+
+ VkDescriptorBufferInfo bufferInfo = {};
+ bufferInfo.buffer = bufferImpl->m_buffer.m_buffer;
+ bufferInfo.offset = 0;
+ bufferInfo.range = bufferImpl->getDesc().sizeInBytes;
+
+ VkWriteDescriptorSet writeInfo = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
+ writeInfo.dstSet = m_descriptorSet;
+ writeInfo.dstBinding = range;
+ writeInfo.dstArrayElement = index;
+ writeInfo.descriptorCount = 1;
+ writeInfo.descriptorType = m_layout->m_ranges[range].descriptorType;
+ writeInfo.pBufferInfo = &bufferInfo;
+
+ m_renderer->m_api.vkUpdateDescriptorSets(m_renderer->m_device, 1, &writeInfo, 0, nullptr);
+}
+
+void VKRenderer::DescriptorSetImpl::setResource(UInt range, UInt index, ResourceView* view)
+{
+ auto viewImpl = (ResourceViewImpl*)view;
+ switch (viewImpl->m_type)
+ {
+ case ResourceViewImpl::ViewType::Texture:
+ {
+ auto textureViewImpl = (TextureResourceViewImpl*)viewImpl;
+ VkDescriptorImageInfo imageInfo = {};
+ imageInfo.imageView = textureViewImpl->m_view;
+ imageInfo.imageLayout = textureViewImpl->m_layout;
+ // imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+
+ VkWriteDescriptorSet writeInfo = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
+ writeInfo.dstSet = m_descriptorSet;
+ writeInfo.dstBinding = range;
+ writeInfo.dstArrayElement = index;
+ writeInfo.descriptorCount = 1;
+ writeInfo.descriptorType = m_layout->m_ranges[range].descriptorType;
+ writeInfo.pImageInfo = &imageInfo;
+
+ m_renderer->m_api.vkUpdateDescriptorSets(m_renderer->m_device, 1, &writeInfo, 0, nullptr);
+ }
+ break;
+
+ case ResourceViewImpl::ViewType::TexelBuffer:
+ {
+ auto bufferViewImpl = (TexelBufferResourceViewImpl*)viewImpl;
+
+ VkWriteDescriptorSet writeInfo = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
+ writeInfo.dstSet = m_descriptorSet;
+ writeInfo.dstBinding = range;
+ writeInfo.dstArrayElement = index;
+ writeInfo.descriptorCount = 1;
+ writeInfo.descriptorType = m_layout->m_ranges[range].descriptorType;
+ writeInfo.pTexelBufferView = &bufferViewImpl->m_view;
+
+ m_renderer->m_api.vkUpdateDescriptorSets(m_renderer->m_device, 1, &writeInfo, 0, nullptr);
+ }
+ break;
+
+ case ResourceViewImpl::ViewType::PlainBuffer:
+ {
+ auto bufferViewImpl = (PlainBufferResourceViewImpl*) viewImpl;
+
+ VkDescriptorBufferInfo bufferInfo = {};
+ bufferInfo.buffer = bufferViewImpl->m_buffer->m_buffer.m_buffer;
+ bufferInfo.offset = bufferViewImpl->offset;
+ bufferInfo.range = bufferViewImpl->size;
+
+ VkWriteDescriptorSet writeInfo = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
+ writeInfo.dstSet = m_descriptorSet;
+ writeInfo.dstBinding = range;
+ writeInfo.dstArrayElement = index;
+ writeInfo.descriptorCount = 1;
+ writeInfo.descriptorType = m_layout->m_ranges[range].descriptorType;
+ writeInfo.pBufferInfo = &bufferInfo;
+
+ m_renderer->m_api.vkUpdateDescriptorSets(m_renderer->m_device, 1, &writeInfo, 0, nullptr);
+ }
+ break;
+
+ }
+}
+
+void VKRenderer::DescriptorSetImpl::setSampler(UInt range, UInt index, SamplerState* sampler)
+{
+}
+
+void VKRenderer::DescriptorSetImpl::setCombinedTextureSampler(
+ UInt range,
+ UInt index,
+ ResourceView* textureView,
+ SamplerState* sampler)
+{
+}
-void VKRenderer::setBindingState(BindingState* state)
+void VKRenderer::setDescriptorSet(PipelineType pipelineType, PipelineLayout* layout, UInt index, DescriptorSet* descriptorSet)
{
- m_currentBindingState = static_cast<BindingStateImpl*>(state);
+ // Ideally this should eventually be as simple as:
+ //
+ // m_api.vkCmdBindDescriptorSets(
+ // commandBuffer,
+ // translatePipelineBindPoint(pipelineType),
+ // layout->m_pipelineLayout,
+ // index,
+ // 1,
+ // ((DescriptorSetImpl*) descriptorSet)->m_descriptorSet,
+ // 0,
+ // nullptr);
+ //
+ // For now we are lazily flushing state right before drawing, so
+ // we will hang onto the parameters that were passed in and then
+ // use them later.
+ //
+
+ auto descriptorSetImpl = (DescriptorSetImpl*)descriptorSet;
+ m_currentDescriptorSetImpls[index] = descriptorSetImpl;
+ m_currentDescriptorSets[index] = descriptorSetImpl->m_descriptorSet;
}
-ShaderProgram* VKRenderer::createProgram(const ShaderProgram::Desc& desc)
+Result VKRenderer::createProgram(const ShaderProgram::Desc& desc, ShaderProgram** outProgram)
{
ShaderProgramImpl* impl = new ShaderProgramImpl(desc.pipelineType);
if( desc.pipelineType == PipelineType::Compute)
@@ -2013,7 +2383,187 @@ ShaderProgram* VKRenderer::createProgram(const ShaderProgram::Desc& desc)
impl->m_vertex = compileEntryPoint(*vertexKernel, VK_SHADER_STAGE_VERTEX_BIT, impl->m_buffers[0]);
impl->m_fragment = compileEntryPoint(*fragmentKernel, VK_SHADER_STAGE_FRAGMENT_BIT, impl->m_buffers[1]);
}
- return impl;
+ *outProgram = impl;
+ return SLANG_OK;
+}
+
+Result VKRenderer::createGraphicsPipelineState(const GraphicsPipelineStateDesc& desc, PipelineState** outState)
+{
+ VkPipelineCache pipelineCache = VK_NULL_HANDLE;
+
+ auto programImpl = (ShaderProgramImpl*) desc.program;
+ auto pipelineLayoutImpl = (PipelineLayoutImpl*) desc.pipelineLayout;
+ auto inputLayoutImpl = (InputLayoutImpl*) desc.inputLayout;
+
+ int width = desc.framebufferWidth;
+ int height = desc.framebufferHeight;
+
+ // Shader Stages
+ //
+ // Currently only handles vertex/fragment.
+
+ static const uint32_t kMaxShaderStages = 2;
+ VkPipelineShaderStageCreateInfo shaderStages[kMaxShaderStages];
+
+ uint32_t shaderStageCount = 0;
+ shaderStages[shaderStageCount++] = programImpl->m_vertex;
+ shaderStages[shaderStageCount++] = programImpl->m_fragment;
+
+ // VertexBuffer/s
+ // Currently only handles one
+
+ VkPipelineVertexInputStateCreateInfo vertexInputInfo = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
+ vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+ vertexInputInfo.vertexBindingDescriptionCount = 0;
+ vertexInputInfo.vertexAttributeDescriptionCount = 0;
+
+ VkVertexInputBindingDescription vertexInputBindingDescription;
+
+ if (inputLayoutImpl)
+ {
+ vertexInputBindingDescription.binding = 0;
+ vertexInputBindingDescription.stride = inputLayoutImpl->m_vertexSize;
+ vertexInputBindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
+
+ const auto& srcAttributeDescs = inputLayoutImpl->m_vertexDescs;
+
+ vertexInputInfo.vertexBindingDescriptionCount = 1;
+ vertexInputInfo.pVertexBindingDescriptions = &vertexInputBindingDescription;
+
+ vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(srcAttributeDescs.Count());
+ vertexInputInfo.pVertexAttributeDescriptions = srcAttributeDescs.Buffer();
+ }
+
+ VkPipelineInputAssemblyStateCreateInfo inputAssembly = {};
+ inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+ inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+ inputAssembly.primitiveRestartEnable = VK_FALSE;
+
+ VkViewport viewport = {};
+ viewport.x = 0.0f;
+ viewport.y = 0.0f;
+ viewport.width = (float)width;
+ viewport.height = (float)height;
+ viewport.minDepth = 0.0f;
+ viewport.maxDepth = 1.0f;
+
+ VkRect2D scissor = {};
+ scissor.offset = { 0, 0 };
+ scissor.extent = { uint32_t(width), uint32_t(height) };
+
+ VkPipelineViewportStateCreateInfo viewportState = {};
+ viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
+ viewportState.viewportCount = 1;
+ viewportState.pViewports = &viewport;
+ viewportState.scissorCount = 1;
+ viewportState.pScissors = &scissor;
+
+ VkPipelineRasterizationStateCreateInfo rasterizer = {};
+ rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+ rasterizer.depthClampEnable = VK_FALSE;
+ rasterizer.rasterizerDiscardEnable = VK_FALSE;
+ rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
+ rasterizer.lineWidth = 1.0f;
+ rasterizer.cullMode = VK_CULL_MODE_NONE;
+ rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
+ rasterizer.depthBiasEnable = VK_FALSE;
+
+ VkPipelineMultisampleStateCreateInfo multisampling = {};
+ multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+ multisampling.sampleShadingEnable = VK_FALSE;
+ multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
+
+ VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
+ colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
+ colorBlendAttachment.blendEnable = VK_FALSE;
+
+ VkPipelineColorBlendStateCreateInfo colorBlending = {};
+ colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+ colorBlending.logicOpEnable = VK_FALSE;
+ colorBlending.logicOp = VK_LOGIC_OP_COPY;
+ colorBlending.attachmentCount = 1;
+ colorBlending.pAttachments = &colorBlendAttachment;
+ colorBlending.blendConstants[0] = 0.0f;
+ colorBlending.blendConstants[1] = 0.0f;
+ colorBlending.blendConstants[2] = 0.0f;
+ colorBlending.blendConstants[3] = 0.0f;
+
+ VkGraphicsPipelineCreateInfo pipelineInfo = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };
+
+ pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+ pipelineInfo.stageCount = 2;
+ pipelineInfo.pStages = shaderStages;
+ pipelineInfo.pVertexInputState = &vertexInputInfo;
+ pipelineInfo.pInputAssemblyState = &inputAssembly;
+ pipelineInfo.pViewportState = &viewportState;
+ pipelineInfo.pRasterizationState = &rasterizer;
+ pipelineInfo.pMultisampleState = &multisampling;
+ pipelineInfo.pColorBlendState = &colorBlending;
+ pipelineInfo.layout = pipelineLayoutImpl->m_pipelineLayout;
+ pipelineInfo.renderPass = m_renderPass;
+ pipelineInfo.subpass = 0;
+ pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
+
+ VkPipeline pipeline = VK_NULL_HANDLE;
+ SLANG_VK_CHECK(m_api.vkCreateGraphicsPipelines(m_device, pipelineCache, 1, &pipelineInfo, nullptr, &pipeline));
+
+ RefPtr<PipelineStateImpl> pipelineStateImpl;
+ pipelineStateImpl->m_pipeline = pipeline;
+ pipelineStateImpl->m_pipelineLayout = pipelineLayoutImpl;
+ pipelineStateImpl->m_shaderProgram = programImpl;
+ *outState = pipelineStateImpl.detach();
+ return SLANG_OK;
+}
+
+Result VKRenderer::createComputePipelineState(const ComputePipelineStateDesc& desc, PipelineState** outState)
+{
+ VkPipelineCache pipelineCache = VK_NULL_HANDLE;
+
+ auto programImpl = (ShaderProgramImpl*) desc.program;
+ auto pipelineLayoutImpl = (PipelineLayoutImpl*) desc.pipelineLayout;
+
+ VkComputePipelineCreateInfo computePipelineInfo = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO };
+ computePipelineInfo.stage = programImpl->m_compute;
+ computePipelineInfo.layout = pipelineLayoutImpl->m_pipelineLayout;
+
+ VkPipeline pipeline = VK_NULL_HANDLE;
+ SLANG_VK_CHECK(m_api.vkCreateComputePipelines(m_device, pipelineCache, 1, &computePipelineInfo, nullptr, &pipeline));
+
+ RefPtr<PipelineStateImpl> pipelineStateImpl = new PipelineStateImpl(m_api);
+ pipelineStateImpl->m_pipeline = pipeline;
+ pipelineStateImpl->m_pipelineLayout = pipelineLayoutImpl;
+ pipelineStateImpl->m_shaderProgram = programImpl;
+ *outState = pipelineStateImpl.detach();
+ return SLANG_OK;
}
+
+#if 0
+ else if (m_currentProgram->m_pipelineType == PipelineType::Graphics)
+ {
+ // Create the graphics pipeline
+
+ const int width = m_swapChain.getWidth();
+ const int height = m_swapChain.getHeight();
+
+
+
+
+
+ //
+
+
+ }
+ else
+ {
+ assert(!"Unhandled program type");
+ return SLANG_FAIL;
+ }
+
+ pipelineOut = pipeline;
+ return SLANG_OK;
+
+
+#endif
+
} // renderer_test
diff --git a/tools/slang-graphics/render-vk.h b/tools/gfx/render-vk.h
index 720f35a2c..14a8e403a 100644
--- a/tools/slang-graphics/render-vk.h
+++ b/tools/gfx/render-vk.h
@@ -1,10 +1,10 @@
// render-vk.h
#pragma once
-namespace slang_graphics {
+namespace gfx {
class Renderer;
Renderer* createVKRenderer();
-} // slang_graphics
+} // gfx
diff --git a/tools/slang-graphics/render.cpp b/tools/gfx/render.cpp
index 3595f73c1..8f887b491 100644
--- a/tools/slang-graphics/render.cpp
+++ b/tools/gfx/render.cpp
@@ -3,7 +3,7 @@
#include "../../source/core/slang-math.h"
-namespace slang_graphics {
+namespace gfx {
using namespace Slang;
/* static */const Resource::BindFlag::Enum Resource::s_requiredBinding[] =
@@ -77,7 +77,7 @@ const Resource::DescBase& Resource::getDescBase() const
}
/* !!!!!!!!!!!!!!!!!!!!!!!!!!! BindingState::Desc !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
-
+#if 0
void BindingState::Desc::addSampler(const SamplerDesc& desc, const RegisterRange& registerRange)
{
int descIndex = int(m_samplerDescs.Count());
@@ -143,6 +143,7 @@ int BindingState::Desc::findBindingIndex(Resource::BindFlag::Enum bindFlag, int
return -1;
}
+#endif
/* !!!!!!!!!!!!!!!!!!!!!!!!!!! TextureResource::Size !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
@@ -290,7 +291,7 @@ void TextureResource::Desc::init1D(Format formatIn, int widthIn, int numMipMapsI
this->type = Type::Texture1D;
this->size.init(widthIn);
- this->format = format;
+ this->format = formatIn;
this->arraySize = 0;
this->numMipLevels = numMipMapsIn;
this->sampleDesc.init();
@@ -303,10 +304,10 @@ void TextureResource::Desc::init2D(Type typeIn, Format formatIn, int widthIn, in
{
assert(typeIn == Type::Texture2D || typeIn == Type::TextureCube);
- this->type = type;
+ this->type = typeIn;
this->size.init(widthIn, heightIn);
- this->format = format;
+ this->format = formatIn;
this->arraySize = 0;
this->numMipLevels = numMipMapsIn;
this->sampleDesc.init();
@@ -320,7 +321,7 @@ void TextureResource::Desc::init3D(Format formatIn, int widthIn, int heightIn, i
this->type = Type::Texture3D;
this->size.init(widthIn, heightIn, depthIn);
- this->format = format;
+ this->format = formatIn;
this->arraySize = 0;
this->numMipLevels = numMipMapsIn;
this->sampleDesc.init();
diff --git a/tools/slang-graphics/render.h b/tools/gfx/render.h
index 92e9c0930..b43152b68 100644
--- a/tools/slang-graphics/render.h
+++ b/tools/gfx/render.h
@@ -1,4 +1,4 @@
-// render.h
+// render.h
#pragma once
#include "window.h"
@@ -9,8 +9,18 @@
#include "../../source/core/smart-pointer.h"
#include "../../source/core/list.h"
+#include "../../source/core/dictionary.h"
-namespace slang_graphics {
+namespace gfx {
+
+using Slang::RefObject;
+using Slang::RefPtr;
+using Slang::Dictionary;
+using Slang::GetHashCode;
+using Slang::combineHash;
+using Slang::List;
+
+typedef SlangResult Result;
// Had to move here, because Options needs types defined here
typedef intptr_t Int;
@@ -413,90 +423,251 @@ class TextureResource: public Resource
Desc m_desc;
};
-enum class BindingType
+enum class ComparisonFunc : uint8_t
+{
+ Never = 0,
+ Less = 0x01,
+ Equal = 0x02,
+ LessEqual = 0x03,
+ Greater = 0x04,
+ NotEqual = 0x05,
+ GreaterEqual = 0x06,
+ Always = 0x07,
+};
+
+enum class TextureFilteringMode
+{
+ Point,
+ Linear,
+};
+
+enum class TextureAddressingMode
+{
+ Wrap,
+ ClampToEdge,
+ ClampToBorder,
+ MirrorRepeat,
+ MirrorOnce,
+};
+
+enum class TextureReductionOp
+{
+ Average,
+ Comparison,
+ Minimum,
+ Maximum,
+};
+
+class SamplerState : public Slang::RefObject
+{
+public:
+ struct Desc
+ {
+ TextureFilteringMode minFilter = TextureFilteringMode::Linear;
+ TextureFilteringMode magFilter = TextureFilteringMode::Linear;
+ TextureFilteringMode mipFilter = TextureFilteringMode::Linear;
+ TextureReductionOp reductionOp = TextureReductionOp::Average;
+ TextureAddressingMode addressU = TextureAddressingMode::Wrap;
+ TextureAddressingMode addressV = TextureAddressingMode::Wrap;
+ TextureAddressingMode addressW = TextureAddressingMode::Wrap;
+ float mipLODBias = 0.0f;
+ uint32_t maxAnisotropy = 1;
+ ComparisonFunc comparisonFunc = ComparisonFunc::Never;
+ float borderColor[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
+ float minLOD = -FLT_MAX;
+ float maxLOD = FLT_MAX;
+ };
+};
+
+enum class DescriptorSlotType
{
Unknown,
+
Sampler,
- Buffer,
- Texture,
- CombinedTextureSampler,
- CountOf,
+ CombinedImageSampler,
+ SampledImage,
+ StorageImage,
+ UniformTexelBuffer,
+ StorageTexelBuffer,
+ UniformBuffer,
+ StorageBuffer,
+ DynamicUniformBuffer,
+ DynamicStorageBuffer,
+ InputAttachment,
};
-class BindingState : public Slang::RefObject
+class DescriptorSetLayout : public Slang::RefObject
{
public:
- /// A register set consists of one or more contiguous indices.
- /// To be valid index >= 0 and size >= 1
- struct RegisterRange
- {
- /// True if contains valid contents
- bool isValid() const { return size > 0; }
- /// True if valid single value
- bool isSingle() const { return size == 1; }
- /// Get as a single index (must be at least one index)
- int getSingleIndex() const { return (size == 1) ? index : -1; }
- /// Return the first index
- int getFirstIndex() const { return (size > 0) ? index : -1; }
- /// True if contains register index
- bool hasRegister(int registerIndex) const { return registerIndex >= index && registerIndex < index + size; }
-
- static RegisterRange makeInvalid() { return RegisterRange{ -1, 0 }; }
- static RegisterRange makeSingle(int index) { return RegisterRange{ int16_t(index), 1 }; }
- static RegisterRange makeRange(int index, int size) { return RegisterRange{ int16_t(index), uint16_t(size) }; }
-
- int16_t index; ///< The base index
- uint16_t size; ///< The amount of register indices
+ struct SlotRangeDesc
+ {
+ DescriptorSlotType type = DescriptorSlotType::Unknown;
+ UInt count = 1;
+
+ SlotRangeDesc()
+ {}
+
+ SlotRangeDesc(
+ DescriptorSlotType type,
+ UInt count = 1)
+ : type(type)
+ , count(count)
+ {}
};
- struct SamplerDesc
+ struct Desc
{
- bool isCompareSampler;
+ UInt slotRangeCount = 0;
+ SlotRangeDesc const* slotRanges = nullptr;
};
+};
- struct Binding
+class PipelineLayout : public Slang::RefObject
+{
+public:
+ struct DescriptorSetDesc
{
- BindingType bindingType; ///< Type of binding
- int descIndex; ///< The description index associated with type. -1 if not used. For example if bindingType is Sampler, the descIndex is into m_samplerDescs.
- Slang::RefPtr<Resource> resource; ///< Associated resource. nullptr if not used
- RegisterRange registerRange; /// Defines the registers for binding
+ DescriptorSetLayout* layout = nullptr;
+
+ DescriptorSetDesc()
+ {}
+
+ DescriptorSetDesc(
+ DescriptorSetLayout* layout)
+ : layout(layout)
+ {}
};
struct Desc
{
- /// Add a resource - assumed that the binding will match the Desc of the resource
- void addResource(BindingType bindingType, Resource* resource, const RegisterRange& registerRange);
- /// Add a sampler
- void addSampler(const SamplerDesc& desc, const RegisterRange& registerRange);
- /// Add a BufferResource
- void addBufferResource(BufferResource* resource, const RegisterRange& registerRange) { addResource(BindingType::Buffer, resource, registerRange); }
- /// Add a texture
- void addTextureResource(TextureResource* resource, const RegisterRange& registerRange) { addResource(BindingType::Texture, resource, registerRange); }
- /// Add combined texture a
- void addCombinedTextureSampler(TextureResource* resource, const SamplerDesc& samplerDesc, const RegisterRange& registerRange);
-
- /// Returns the bind index, that has the bind flag, and indexes the specified register
- int findBindingIndex(Resource::BindFlag::Enum bindFlag, int registerIndex) const;
+ UInt renderTargetCount = 0;
+ UInt descriptorSetCount = 0;
+ DescriptorSetDesc const* descriptorSets = nullptr;
+ };
+};
- /// Clear the contents
- void clear();
+class ResourceView : public Slang::RefObject
+{
+public:
+ enum class Type
+ {
+ Unknown,
- Slang::List<Binding> m_bindings; ///< All of the bindings in order
- Slang::List<SamplerDesc> m_samplerDescs; ///< Holds the SamplerDesc for the binding - indexed by the descIndex member of Binding
+ RenderTarget,
+ DepthStencil,
+ ShaderResource,
+ UnorderedAccess,
+ };
- int m_numRenderTargets = 1;
+ struct Desc
+ {
+ Type type;
+ Format format;
};
+};
- /// Get the Desc used to create this binding
- SLANG_FORCE_INLINE const Desc& getDesc() const { return m_desc; }
+class DescriptorSet : public Slang::RefObject
+{
+public:
+ virtual void setConstantBuffer(UInt range, UInt index, BufferResource* buffer) = 0;
+ virtual void setResource(UInt range, UInt index, ResourceView* view) = 0;
+ virtual void setSampler(UInt range, UInt index, SamplerState* sampler) = 0;
+ virtual void setCombinedTextureSampler(
+ UInt range,
+ UInt index,
+ ResourceView* textureView,
+ SamplerState* sampler) = 0;
+};
- protected:
- BindingState(const Desc& desc):
- m_desc(desc)
- {
- }
+enum class StencilOp : uint8_t
+{
+ Keep,
+ Zero,
+ Replace,
+ IncrementSaturate,
+ DecrementSaturate,
+ Invert,
+ IncrementWrap,
+ DecrementWrap,
+};
- Desc m_desc;
+enum class FillMode : uint8_t
+{
+ Solid,
+ Wireframe,
+};
+
+enum class CullMode : uint8_t
+{
+ None,
+ Front,
+ Back,
+};
+
+enum class FrontFaceMode : uint8_t
+{
+ CounterClockwise,
+ Clockwise,
+};
+
+struct DepthStencilOpDesc
+{
+ StencilOp stencilFailOp = StencilOp::Keep;
+ StencilOp stencilDepthFailOp = StencilOp::Keep;
+ StencilOp stencilPassOp = StencilOp::Keep;
+ ComparisonFunc stencilFunc = ComparisonFunc::Always;
+};
+
+struct DepthStencilDesc
+{
+ bool depthTestEnable = true;
+ bool depthWriteEnable = true;
+ ComparisonFunc depthFunc = ComparisonFunc::Less;
+
+ bool stencilEnable = false;
+ uint32_t stencilReadMask = 0xFFFFFFFF;
+ uint32_t stencilWriteMask = 0xFFFFFFFF;
+ DepthStencilOpDesc frontFace;
+ DepthStencilOpDesc backFace;
+
+ uint32_t stencilRef = 0;
+};
+
+struct RasterizerDesc
+{
+ FillMode fillMode = FillMode::Solid;
+ CullMode cullMode = CullMode::Back;
+ FrontFaceMode frontFace = FrontFaceMode::CounterClockwise;
+ int32_t depthBias = 0;
+ float depthBiasClamp = 0.0f;
+ float slopeScaledDepthBias = 0.0f;
+ bool depthClipEnable = true;
+ bool scissorEnable = false;
+ bool multisampleEnable = false;
+ bool antialiasedLineEnable = false;
+};
+
+struct GraphicsPipelineStateDesc
+{
+ ShaderProgram* program;
+ PipelineLayout* pipelineLayout;
+ InputLayout* inputLayout;
+ UInt framebufferWidth;
+ UInt framebufferHeight;
+ UInt renderTargetCount;
+ DepthStencilDesc depthStencil;
+ RasterizerDesc rasterizer;
+};
+
+struct ComputePipelineStateDesc
+{
+ ShaderProgram* program;
+ PipelineLayout* pipelineLayout;
+};
+
+class PipelineState : public Slang::RefObject
+{
+public:
};
class Renderer: public Slang::RefObject
@@ -516,32 +687,147 @@ public:
virtual void presentFrame() = 0;
+ virtual TextureResource::Desc getSwapChainTextureDesc() = 0;
+
/// Create a texture resource. initData holds the initialize data to set the contents of the texture when constructed.
- virtual TextureResource* createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData = nullptr) { return nullptr; }
+ virtual Result createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData, TextureResource** outResource) = 0;
+
+ /// Create a texture resource. initData holds the initialize data to set the contents of the texture when constructed.
+ inline RefPtr<TextureResource> createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData = nullptr)
+ {
+ RefPtr<TextureResource> resource;
+ SLANG_RETURN_NULL_ON_FAIL(createTextureResource(initialUsage, desc, initData, resource.writeRef()));
+ return resource;
+ }
+
/// Create a buffer resource
- virtual BufferResource* createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& desc, const void* initData = nullptr) { return nullptr; }
+ virtual Result createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& desc, const void* initData, BufferResource** outResource) = 0;
- /// Captures the back buffer and stores the result in surfaceOut. If the surface contains data - it will either be overwritten (if same size and format), or freed and a re-allocated.
- virtual SlangResult captureScreenSurface(Surface& surfaceOut) = 0;
+ inline RefPtr<BufferResource> createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& desc, const void* initData = nullptr)
+ {
+ RefPtr<BufferResource> resource;
+ SLANG_RETURN_NULL_ON_FAIL(createBufferResource(initialUsage, desc, initData, resource.writeRef()));
+ return resource;
+ }
- virtual InputLayout* createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount) = 0;
- virtual BindingState* createBindingState(const BindingState::Desc& desc) { return nullptr; }
+ virtual Result createSamplerState(SamplerState::Desc const& desc, SamplerState** outSampler) = 0;
- virtual ShaderProgram* createProgram(const ShaderProgram::Desc& desc) = 0;
+ inline RefPtr<SamplerState> createSamplerState(SamplerState::Desc const& desc)
+ {
+ RefPtr<SamplerState> sampler;
+ SLANG_RETURN_NULL_ON_FAIL(createSamplerState(desc, sampler.writeRef()));
+ return sampler;
+ }
+
+ virtual Result createTextureView(TextureResource* texture, ResourceView::Desc const& desc, ResourceView** outView) = 0;
+
+ inline RefPtr<ResourceView> createTextureView(TextureResource* texture, ResourceView::Desc const& desc)
+ {
+ RefPtr<ResourceView> view;
+ SLANG_RETURN_NULL_ON_FAIL(createTextureView(texture, desc, view.writeRef()));
+ return view;
+ }
+
+ virtual Result createBufferView(BufferResource* buffer, ResourceView::Desc const& desc, ResourceView** outView) = 0;
+
+ inline RefPtr<ResourceView> createBufferView(BufferResource* buffer, ResourceView::Desc const& desc)
+ {
+ RefPtr<ResourceView> view;
+ SLANG_RETURN_NULL_ON_FAIL(createBufferView(buffer, desc, view.writeRef()));
+ return view;
+ }
+
+ virtual Result createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount, InputLayout** outLayout) = 0;
+
+ inline RefPtr<InputLayout> createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount)
+ {
+ RefPtr<InputLayout> layout;
+ SLANG_RETURN_NULL_ON_FAIL(createInputLayout(inputElements, inputElementCount, layout.writeRef()));
+ return layout;
+ }
+
+ virtual Result createDescriptorSetLayout(const DescriptorSetLayout::Desc& desc, DescriptorSetLayout** outLayout) = 0;
+
+ inline RefPtr<DescriptorSetLayout> createDescriptorSetLayout(const DescriptorSetLayout::Desc& desc)
+ {
+ RefPtr<DescriptorSetLayout> layout;
+ SLANG_RETURN_NULL_ON_FAIL(createDescriptorSetLayout(desc, layout.writeRef()));
+ return layout;
+ }
+
+ virtual Result createPipelineLayout(const PipelineLayout::Desc& desc, PipelineLayout** outLayout) = 0;
+
+ inline RefPtr<PipelineLayout> createPipelineLayout(const PipelineLayout::Desc& desc)
+ {
+ RefPtr<PipelineLayout> layout;
+ SLANG_RETURN_NULL_ON_FAIL(createPipelineLayout(desc, layout.writeRef()));
+ return layout;
+ }
+
+ virtual Result createDescriptorSet(DescriptorSetLayout* layout, DescriptorSet** outDescriptorSet) = 0;
+
+ inline RefPtr<DescriptorSet> createDescriptorSet(DescriptorSetLayout* layout)
+ {
+ RefPtr<DescriptorSet> descriptorSet;
+ SLANG_RETURN_NULL_ON_FAIL(createDescriptorSet(layout, descriptorSet.writeRef()));
+ return descriptorSet;
+ }
+
+ virtual Result createProgram(const ShaderProgram::Desc& desc, ShaderProgram** outProgram) = 0;
+
+ inline RefPtr<ShaderProgram> createProgram(const ShaderProgram::Desc& desc)
+ {
+ RefPtr<ShaderProgram> program;
+ SLANG_RETURN_NULL_ON_FAIL(createProgram(desc, program.writeRef()));
+ return program;
+ }
+
+ virtual Result createGraphicsPipelineState(
+ const GraphicsPipelineStateDesc& desc,
+ PipelineState** outState) = 0;
+
+ inline RefPtr<PipelineState> createGraphicsPipelineState(
+ const GraphicsPipelineStateDesc& desc)
+ {
+ RefPtr<PipelineState> state;
+ SLANG_RETURN_NULL_ON_FAIL(createGraphicsPipelineState(desc, state.writeRef()));
+ return state;
+ }
+
+ virtual Result createComputePipelineState(
+ const ComputePipelineStateDesc& desc,
+ PipelineState** outState) = 0;
+
+ inline RefPtr<PipelineState> createComputePipelineState(
+ const ComputePipelineStateDesc& desc)
+ {
+ RefPtr<PipelineState> state;
+ SLANG_RETURN_NULL_ON_FAIL(createComputePipelineState(desc, state.writeRef()));
+ return state;
+ }
+
+ /// Captures the back buffer and stores the result in surfaceOut. If the surface contains data - it will either be overwritten (if same size and format), or freed and a re-allocated.
+ virtual SlangResult captureScreenSurface(Surface& surfaceOut) = 0;
virtual void* map(BufferResource* buffer, MapFlavor flavor) = 0;
virtual void unmap(BufferResource* buffer) = 0;
- virtual void setInputLayout(InputLayout* inputLayout) = 0;
virtual void setPrimitiveTopology(PrimitiveTopology topology) = 0;
- virtual void setBindingState(BindingState* state) = 0;
- virtual void setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) = 0;
+ virtual void setDescriptorSet(PipelineType pipelineType, PipelineLayout* layout, UInt index, DescriptorSet* descriptorSet) = 0;
+
+ virtual void setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) = 0;
inline void setVertexBuffer(UInt slot, BufferResource* buffer, UInt stride, UInt offset = 0);
- virtual void setShaderProgram(ShaderProgram* program) = 0;
+ virtual void setIndexBuffer(BufferResource* buffer, Format indexFormat, UInt offset = 0) = 0;
+
+ virtual void setDepthStencilTarget(ResourceView* depthStencilView) = 0;
+
+ virtual void setPipelineState(PipelineType pipelineType, PipelineState* state) = 0;
virtual void draw(UInt vertexCount, UInt startVertex = 0) = 0;
+ virtual void drawIndexed(UInt indexCount, UInt startIndex = 0, UInt baseVertex = 0) = 0;
+
virtual void dispatchCompute(int x, int y, int z) = 0;
/// Commit any buffered state changes or draw calls.
diff --git a/tools/slang-graphics/resource-d3d12.cpp b/tools/gfx/resource-d3d12.cpp
index bb39d2529..2e0f78371 100644
--- a/tools/slang-graphics/resource-d3d12.cpp
+++ b/tools/gfx/resource-d3d12.cpp
@@ -1,7 +1,7 @@
// resource-d3d12.cpp
#include "resource-d3d12.h"
-namespace slang_graphics {
+namespace gfx {
using namespace Slang;
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! D3D12BarrierSubmitter !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
diff --git a/tools/slang-graphics/resource-d3d12.h b/tools/gfx/resource-d3d12.h
index 6040291cc..1764adf9d 100644
--- a/tools/slang-graphics/resource-d3d12.h
+++ b/tools/gfx/resource-d3d12.h
@@ -13,7 +13,7 @@
#include "../../slang-com-ptr.h"
#include "d3d-util.h"
-namespace slang_graphics {
+namespace gfx {
// Enables more conservative barriers - restoring the state of resources after they are used.
// Should not need to be enabled in normal builds, as the barriers should correctly sync resources
diff --git a/tools/slang-graphics/surface.cpp b/tools/gfx/surface.cpp
index 9d91f8778..4b53d278a 100644
--- a/tools/slang-graphics/surface.cpp
+++ b/tools/gfx/surface.cpp
@@ -6,7 +6,7 @@
#include "../../source/core/list.h"
-namespace slang_graphics {
+namespace gfx {
using namespace Slang;
class MallocSurfaceAllocator: public SurfaceAllocator
diff --git a/tools/slang-graphics/surface.h b/tools/gfx/surface.h
index 026ba25ed..3e0f6f0aa 100644
--- a/tools/slang-graphics/surface.h
+++ b/tools/gfx/surface.h
@@ -3,7 +3,7 @@
#include "render.h"
-namespace slang_graphics {
+namespace gfx {
class Surface;
diff --git a/tools/gfx/vector-math.h b/tools/gfx/vector-math.h
new file mode 100644
index 000000000..88cb0c1d9
--- /dev/null
+++ b/tools/gfx/vector-math.h
@@ -0,0 +1,14 @@
+// vector-math.h
+#pragma once
+
+// We will use the GLM library for our vector math types, just for simplicity.
+
+#include "../../external/glm/glm/glm.hpp"
+#include "../../external/glm/glm/gtc/matrix_transform.hpp"
+#include "../../external/glm/glm/gtc/constants.hpp"
+
+namespace gfx {
+
+using namespace glm;
+
+} // gfx
diff --git a/tools/slang-graphics/vk-api.cpp b/tools/gfx/vk-api.cpp
index 0ffbf46eb..4030e43ba 100644
--- a/tools/slang-graphics/vk-api.cpp
+++ b/tools/gfx/vk-api.cpp
@@ -3,7 +3,7 @@
#include "../../source/core/list.h"
-namespace slang_graphics {
+namespace gfx {
using namespace Slang;
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! VulkanApi !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
diff --git a/tools/slang-graphics/vk-api.h b/tools/gfx/vk-api.h
index 0cbd3faf7..5ec28ef6e 100644
--- a/tools/slang-graphics/vk-api.h
+++ b/tools/gfx/vk-api.h
@@ -3,7 +3,7 @@
#include "vk-module.h"
-namespace slang_graphics {
+namespace gfx {
#define VK_API_GLOBAL_PROCS(x) \
x(vkGetInstanceProcAddr) \
diff --git a/tools/slang-graphics/vk-device-queue.cpp b/tools/gfx/vk-device-queue.cpp
index 9e978117f..10a3d0e3b 100644
--- a/tools/slang-graphics/vk-device-queue.cpp
+++ b/tools/gfx/vk-device-queue.cpp
@@ -5,7 +5,7 @@
#include <stdio.h>
#include <assert.h>
-namespace slang_graphics {
+namespace gfx {
using namespace Slang;
VulkanDeviceQueue::~VulkanDeviceQueue()
diff --git a/tools/slang-graphics/vk-device-queue.h b/tools/gfx/vk-device-queue.h
index 01ed16f5d..d57483ec0 100644
--- a/tools/slang-graphics/vk-device-queue.h
+++ b/tools/gfx/vk-device-queue.h
@@ -3,7 +3,7 @@
#include "vk-api.h"
-namespace slang_graphics {
+namespace gfx {
struct VulkanDeviceQueue
{
diff --git a/tools/slang-graphics/vk-module.cpp b/tools/gfx/vk-module.cpp
index 460e6550c..4e92a3d2c 100644
--- a/tools/slang-graphics/vk-module.cpp
+++ b/tools/gfx/vk-module.cpp
@@ -11,7 +11,7 @@
# include <dlfcn.h>
#endif
-namespace slang_graphics {
+namespace gfx {
using namespace Slang;
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! VulkanModule !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
diff --git a/tools/slang-graphics/vk-module.h b/tools/gfx/vk-module.h
index c72334db5..55e26f335 100644
--- a/tools/slang-graphics/vk-module.h
+++ b/tools/gfx/vk-module.h
@@ -14,7 +14,7 @@
#define VK_NO_PROTOTYPES
#include <vulkan/vulkan.h>
-namespace slang_graphics {
+namespace gfx {
struct VulkanModule
{
diff --git a/tools/slang-graphics/vk-swap-chain.cpp b/tools/gfx/vk-swap-chain.cpp
index a6704e9d7..6e89c946c 100644
--- a/tools/slang-graphics/vk-swap-chain.cpp
+++ b/tools/gfx/vk-swap-chain.cpp
@@ -8,7 +8,7 @@
#include <stdlib.h>
#include <stdio.h>
-namespace slang_graphics {
+namespace gfx {
using namespace Slang;
static int _indexOf(List<VkSurfaceFormatKHR>& formatsIn, VkFormat format)
diff --git a/tools/slang-graphics/vk-swap-chain.h b/tools/gfx/vk-swap-chain.h
index 7c04af70c..12feb0ed5 100644
--- a/tools/slang-graphics/vk-swap-chain.h
+++ b/tools/gfx/vk-swap-chain.h
@@ -8,7 +8,7 @@
#include "../../source/core/list.h"
-namespace slang_graphics {
+namespace gfx {
struct VulkanSwapChain
{
diff --git a/tools/slang-graphics/vk-util.cpp b/tools/gfx/vk-util.cpp
index 374a3876d..e8940d1b2 100644
--- a/tools/slang-graphics/vk-util.cpp
+++ b/tools/gfx/vk-util.cpp
@@ -4,7 +4,7 @@
#include <stdlib.h>
#include <stdio.h>
-namespace slang_graphics {
+namespace gfx {
/* static */VkFormat VulkanUtil::getVkFormat(Format format)
{
diff --git a/tools/slang-graphics/vk-util.h b/tools/gfx/vk-util.h
index 420c0a57a..edba3a7d2 100644
--- a/tools/slang-graphics/vk-util.h
+++ b/tools/gfx/vk-util.h
@@ -15,7 +15,7 @@
/// Is similar to SLANG_VK_RETURN_ON_FAIL, but does not return. Will call checkFail on failure - which asserts on debug builds.
#define SLANG_VK_CHECK(x) { VkResult _res = x; if (_res != VK_SUCCESS) { VulkanUtil::checkFail(_res); } }
-namespace slang_graphics {
+namespace gfx {
// Utility functions for Vulkan
struct VulkanUtil
diff --git a/tools/slang-graphics/window.cpp b/tools/gfx/window.cpp
index 7aef88c12..ee9f50813 100644
--- a/tools/slang-graphics/window.cpp
+++ b/tools/gfx/window.cpp
@@ -11,6 +11,8 @@
#endif
#endif
+#include <stdint.h>
+
#if _WIN32
#include <Windows.h>
@@ -18,7 +20,7 @@
#error "The slang-graphics library currently only supports Windows platforms"
#endif
-namespace slang_graphics {
+namespace gfx {
#if _WIN32
@@ -70,6 +72,16 @@ struct ApplicationContext
int resultCode = 0;
};
+static uint64_t gTimerFrequency;
+
+
+static void initApplication(ApplicationContext* context)
+{
+ LARGE_INTEGER timerFrequency;
+ QueryPerformanceFrequency(&timerFrequency);
+ gTimerFrequency = timerFrequency.QuadPart;
+}
+
/// Run an application given the specified callback and command-line arguments.
int runApplication(
ApplicationFunc func,
@@ -78,6 +90,7 @@ int runApplication(
{
ApplicationContext context;
context.instance = (HINSTANCE) GetModuleHandle(0);
+ initApplication(&context);
func(&context);
return context.resultCode;
}
@@ -90,6 +103,7 @@ int runWindowsApplication(
ApplicationContext context;
context.instance = (HINSTANCE) instance;
context.showCommand = showCommand;
+ initApplication(&context);
func(&context);
return context.resultCode;
}
@@ -216,6 +230,24 @@ void exitApplication(ApplicationContext* context, int resultCode)
ExitProcess(resultCode);
}
+void log(char const* message, ...)
+{
+ va_list args;
+ va_start(args, message);
+
+ static const int kBufferSize = 1024;
+ char messageBuffer[kBufferSize];
+ vsnprintf(messageBuffer, kBufferSize - 1, message, args);
+ messageBuffer[kBufferSize - 1] = 0;
+
+ va_end(args);
+
+ fputs(messageBuffer, stderr);
+
+ OSString wideMessageBuffer(messageBuffer);
+ OutputDebugStringW(wideMessageBuffer);
+}
+
int reportError(char const* message, ...)
{
va_list args;
@@ -236,10 +268,22 @@ int reportError(char const* message, ...)
return 1;
}
+uint64_t getCurrentTime()
+{
+ LARGE_INTEGER counter;
+ QueryPerformanceCounter(&counter);
+ return counter.QuadPart;
+}
+
+uint64_t getTimerFrequency()
+{
+ return gTimerFrequency;
+}
+
#else
// TODO: put an SDL version here
#endif
-} // slang_graphics
+} // gfx
diff --git a/tools/slang-graphics/window.h b/tools/gfx/window.h
index 91c8286d5..6e557d26c 100644
--- a/tools/slang-graphics/window.h
+++ b/tools/gfx/window.h
@@ -1,7 +1,9 @@
// window.h
#pragma once
-namespace slang_graphics {
+#include <stdint.h>
+
+namespace gfx {
struct WindowDesc
{
@@ -30,18 +32,25 @@ bool dispatchEvents(ApplicationContext* context);
/// Exit the application with a given result code
void exitApplication(ApplicationContext* context, int resultCode);
+/// Log a message to an appropriate logging destination.
+void log(char const* message, ...);
+
/// Report an error to an appropriate logging destination.
int reportError(char const* message, ...);
+uint64_t getCurrentTime();
+
+uint64_t getTimerFrequency();
+
/// Run an application given the specified callback and command-line arguments.
int runApplication(
ApplicationFunc func,
int argc,
char const* const* argv);
-#define SG_CONSOLE_MAIN(APPLICATION_ENTRY) \
+#define GFX_CONSOLE_MAIN(APPLICATION_ENTRY) \
int main(int argc, char** argv) { \
- return slang_graphics::runApplication(&(APPLIATION_ENTRY), argc, argv); \
+ return gfx::runApplication(&(APPLIATION_ENTRY), argc, argv); \
}
#ifdef _WIN32
@@ -51,19 +60,19 @@ int runWindowsApplication(
void* instance,
int showCommand);
-#define SG_UI_MAIN(APPLICATION_ENTRY) \
+#define GFX_UI_MAIN(APPLICATION_ENTRY) \
int __stdcall WinMain( \
void* instance, \
void* /* prevInstance */, \
void* /* commandLine */, \
int showCommand) { \
- return slang_graphics::runWindowsApplication(&(APPLICATION_ENTRY), instance, showCommand); \
+ return gfx::runWindowsApplication(&(APPLICATION_ENTRY), instance, showCommand); \
}
#else
-#define SG_UI_MAIN(APPLICATION_ENTRY) SG_CONSOLE_MAIN(APPLICATION_ENTRY)
+#define GFX_UI_MAIN(APPLICATION_ENTRY) GFX_CONSOLE_MAIN(APPLICATION_ENTRY)
#endif
-} // slang_graphics
+} // gfx
diff --git a/tools/render-test/main.cpp b/tools/render-test/main.cpp
index 935b9bc98..4734c2c8f 100644
--- a/tools/render-test/main.cpp
+++ b/tools/render-test/main.cpp
@@ -29,6 +29,8 @@
namespace renderer_test {
+using Slang::Result;
+
int gWindowWidth = 1024;
int gWindowHeight = 768;
@@ -45,7 +47,7 @@ struct Vertex
float uv[2];
};
-static const Vertex kVertexData[] =
+static const Vertex kVertexData[] =
{
{ { 0, 0, 0.5 }, {1, 0, 0} , {0, 0} },
{ { 0, 1, 0.5 }, {0, 0, 1} , {1, 0} },
@@ -61,15 +63,15 @@ class RenderTestApp
// At initialization time, we are going to load and compile our Slang shader
// code, and then create the API objects we need for rendering.
- Result initialize(Renderer* renderer, ShaderCompiler* shaderCompiler);
+ Result initialize(Renderer* renderer, ShaderCompiler* shaderCompiler);
void runCompute();
void renderFrame();
void finalize();
- BindingState* getBindingState() const { return m_bindingState; }
+ BindingStateImpl* getBindingState() const { return m_bindingState; }
Result writeBindingOutput(const char* fileName);
-
+
Result writeScreen(const char* filename);
protected:
@@ -85,7 +87,8 @@ class RenderTestApp
RefPtr<InputLayout> m_inputLayout;
RefPtr<BufferResource> m_vertexBuffer;
RefPtr<ShaderProgram> m_shaderProgram;
- RefPtr<BindingState> m_bindingState;
+ RefPtr<PipelineState> m_pipelineState;
+ RefPtr<BindingStateImpl> m_bindingState;
ShaderInputLayout m_shaderInputLayout; ///< The binding layout
int m_numAddedConstantBuffers; ///< Constant buffers can be added to the binding directly. Will be added at the end.
@@ -117,22 +120,26 @@ SlangResult RenderTestApp::initialize(Renderer* renderer, ShaderCompiler* shader
}
{
- BindingState::Desc bindingStateDesc;
- SLANG_RETURN_ON_FAIL(ShaderRendererUtil::createBindingStateDesc(m_shaderInputLayout, m_renderer, bindingStateDesc));
-
- //! Hack -> if bindings are specified, just set up the constant buffer binding
- // Should probably be more sophisticated than this - with 'dynamic' constant buffer/s binding always being specified
- // in the test file
-
- if ((gOptions.shaderType == Options::ShaderProgramType::Graphics || gOptions.shaderType == Options::ShaderProgramType::GraphicsCompute)
- && bindingStateDesc.findBindingIndex(Resource::BindFlag::ConstantBuffer, 0) < 0)
+ //! Hack -> if doing a graphics test, add an extra binding for our dynamic constant buffer
+ //
+ // TODO: Should probably be more sophisticated than this - with 'dynamic' constant buffer/s binding always being specified
+ // in the test file
+ RefPtr<BufferResource> addedConstantBuffer;
+ switch(gOptions.shaderType)
{
- bindingStateDesc.addResource(BindingType::Buffer, m_constantBuffer, BindingState::RegisterRange::makeSingle(0) );
+ default:
+ break;
+ case Options::ShaderProgramType::Graphics:
+ case Options::ShaderProgramType::GraphicsCompute:
+ addedConstantBuffer = m_constantBuffer;
m_numAddedConstantBuffers++;
+ break;
}
- m_bindingState = m_renderer->createBindingState(bindingStateDesc);
+ BindingStateImpl* bindingState = nullptr;
+ SLANG_RETURN_ON_FAIL(ShaderRendererUtil::createBindingState(m_shaderInputLayout, m_renderer, addedConstantBuffer, &bindingState));
+ m_bindingState = bindingState;
}
// Do other initialization that doesn't depend on the source language.
@@ -156,6 +163,38 @@ SlangResult RenderTestApp::initialize(Renderer* renderer, ShaderCompiler* shader
if(!m_vertexBuffer)
return SLANG_FAIL;
+ {
+ switch(gOptions.shaderType)
+ {
+ default:
+ assert(!"unexpected test shader type");
+ return SLANG_FAIL;
+
+ case Options::ShaderProgramType::Compute:
+ {
+ ComputePipelineStateDesc desc;
+ desc.pipelineLayout = m_bindingState->pipelineLayout;
+ desc.program = m_shaderProgram;
+
+ m_pipelineState = renderer->createComputePipelineState(desc);
+ }
+ break;
+
+ case Options::ShaderProgramType::Graphics:
+ case Options::ShaderProgramType::GraphicsCompute:
+ {
+ GraphicsPipelineStateDesc desc;
+ desc.pipelineLayout = m_bindingState->pipelineLayout;
+ desc.program = m_shaderProgram;
+ desc.inputLayout = m_inputLayout;
+ desc.renderTargetCount = m_bindingState->m_numRenderTargets;
+
+ m_pipelineState = renderer->createGraphicsPipelineState(desc);
+ }
+ break;
+ }
+ }
+
return SLANG_OK;
}
@@ -182,6 +221,16 @@ Result RenderTestApp::initializeShaders(ShaderCompiler* shaderCompiler)
fclose(sourceFile);
sourceText[sourceSize] = 0;
+ switch( gOptions.shaderType )
+ {
+ default:
+ m_shaderInputLayout.numRenderTargets = 1;
+ break;
+
+ case Options::ShaderProgramType::Compute:
+ m_shaderInputLayout.numRenderTargets = 0;
+ break;
+ }
m_shaderInputLayout.Parse(sourceText);
ShaderCompileRequest::SourceInfo sourceInfo;
@@ -220,31 +269,27 @@ void RenderTestApp::renderFrame()
{
const ProjectionStyle projectionStyle = RendererUtil::getProjectionStyle(m_renderer->getRendererType());
RendererUtil::getIdentityProjection(projectionStyle, (float*)mappedData);
-
+
m_renderer->unmap(m_constantBuffer);
}
- // Input Assembler (IA)
+ auto pipelineType = PipelineType::Graphics;
- m_renderer->setInputLayout(m_inputLayout);
- m_renderer->setPrimitiveTopology(PrimitiveTopology::TriangleList);
+ m_renderer->setPipelineState(pipelineType, m_pipelineState);
+ m_renderer->setPrimitiveTopology(PrimitiveTopology::TriangleList);
m_renderer->setVertexBuffer(0, m_vertexBuffer, sizeof(Vertex));
- // Vertex Shader (VS)
- // Pixel Shader (PS)
-
- m_renderer->setShaderProgram(m_shaderProgram);
- m_renderer->setBindingState(m_bindingState);
- //
+ m_bindingState->apply(m_renderer, pipelineType);
m_renderer->draw(3);
}
void RenderTestApp::runCompute()
{
- m_renderer->setShaderProgram(m_shaderProgram);
- m_renderer->setBindingState(m_bindingState);
+ auto pipelineType = PipelineType::Compute;
+ m_renderer->setPipelineState(pipelineType, m_pipelineState);
+ m_bindingState->apply(m_renderer, pipelineType);
m_renderer->dispatchCompute(1, 1, 1);
}
@@ -265,18 +310,12 @@ Result RenderTestApp::writeBindingOutput(const char* fileName)
return SLANG_FAIL;
}
- const BindingState::Desc& bindingStateDesc = m_bindingState->getDesc();
- // Must be the same amount of entries
- assert(bindingStateDesc.m_bindings.Count() == m_shaderInputLayout.entries.Count() + m_numAddedConstantBuffers);
-
- const int numBindings = int(m_shaderInputLayout.entries.Count());
-
- for (int i = 0; i < numBindings; ++i)
+ for(auto binding : m_bindingState->outputBindings)
{
+ auto i = binding.entryIndex;
const auto& layoutBinding = m_shaderInputLayout.entries[i];
- const auto& binding = bindingStateDesc.m_bindings[i];
- if (layoutBinding.isOutput)
+ assert(layoutBinding.isOutput);
{
if (binding.resource && binding.resource->isBuffer())
{
@@ -524,11 +563,11 @@ SlangResult innerMain(int argc, char** argv)
else
{
Result res = app.writeScreen(gOptions.outputPath);
-
+
if (SLANG_FAILED(res))
{
fprintf(stderr, "ERROR: failed to write screen capture to file\n");
- return res;
+ return res;
}
}
return SLANG_OK;
diff --git a/tools/render-test/options.h b/tools/render-test/options.h
index 82c018f66..78f673796 100644
--- a/tools/render-test/options.h
+++ b/tools/render-test/options.h
@@ -9,7 +9,7 @@
namespace renderer_test {
-using namespace slang_graphics;
+using namespace gfx;
struct Options
{
diff --git a/tools/render-test/png-serialize-util.h b/tools/render-test/png-serialize-util.h
index dad17ae74..1ec5204f7 100644
--- a/tools/render-test/png-serialize-util.h
+++ b/tools/render-test/png-serialize-util.h
@@ -5,7 +5,7 @@
namespace renderer_test {
-using namespace slang_graphics;
+using namespace gfx;
struct PngSerializeUtil
{
diff --git a/tools/render-test/render-test.vcxproj b/tools/render-test/render-test.vcxproj
index 66ad9e7ed..91c8bd997 100644
--- a/tools/render-test/render-test.vcxproj
+++ b/tools/render-test/render-test.vcxproj
@@ -99,7 +99,7 @@
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>..\..;..\..\external;..\..\source;..\slang-graphics;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>..\..;..\..\external;..\..\source;..\gfx;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<Optimization>Disabled</Optimization>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
@@ -117,7 +117,7 @@
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>..\..;..\..\external;..\..\source;..\slang-graphics;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>..\..;..\..\external;..\..\source;..\gfx;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<Optimization>Disabled</Optimization>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
@@ -135,7 +135,7 @@
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>..\..;..\..\external;..\..\source;..\slang-graphics;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>..\..;..\..\external;..\..\source;..\gfx;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<Optimization>Full</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
@@ -157,7 +157,7 @@
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>..\..;..\..\external;..\..\source;..\slang-graphics;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>..\..;..\..\external;..\..\source;..\gfx;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<Optimization>Full</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
@@ -196,7 +196,7 @@
<ProjectReference Include="..\..\source\slang\slang.vcxproj">
<Project>{DB00DA62-0533-4AFD-B59F-A67D5B3A0808}</Project>
</ProjectReference>
- <ProjectReference Include="..\slang-graphics\slang-graphics.vcxproj">
+ <ProjectReference Include="..\gfx\gfx.vcxproj">
<Project>{222F7498-B40C-4F3F-A704-DDEB91A4484A}</Project>
</ProjectReference>
</ItemGroup>
diff --git a/tools/render-test/shader-input-layout.h b/tools/render-test/shader-input-layout.h
index 19a7e59d0..92dd516a7 100644
--- a/tools/render-test/shader-input-layout.h
+++ b/tools/render-test/shader-input-layout.h
@@ -7,7 +7,7 @@
namespace renderer_test {
-using namespace slang_graphics;
+using namespace gfx;
enum class ShaderInputType
{
diff --git a/tools/render-test/shader-renderer-util.cpp b/tools/render-test/shader-renderer-util.cpp
index e46c725bc..f6c0366bb 100644
--- a/tools/render-test/shader-renderer-util.cpp
+++ b/tools/render-test/shader-renderer-util.cpp
@@ -5,6 +5,16 @@
namespace renderer_test {
using namespace Slang;
+using Slang::Result;
+
+void BindingStateImpl::apply(Renderer* renderer, PipelineType pipelineType)
+{
+ renderer->setDescriptorSet(
+ pipelineType,
+ pipelineLayout,
+ 0,
+ descriptorSet);
+}
/* static */Result ShaderRendererUtil::generateTextureResource(const InputTextureDesc& inputDesc, int bindFlags, Renderer* renderer, RefPtr<TextureResource>& textureOut)
{
@@ -125,16 +135,27 @@ using namespace Slang;
return SLANG_OK;
}
-static BindingState::SamplerDesc _calcSamplerDesc(const InputSamplerDesc& srcDesc)
+static SamplerState::Desc _calcSamplerDesc(const InputSamplerDesc& srcDesc)
{
- BindingState::SamplerDesc dstDesc;
- dstDesc.isCompareSampler = srcDesc.isCompareSampler;
+ SamplerState::Desc dstDesc;
+ if (srcDesc.isCompareSampler)
+ {
+ dstDesc.reductionOp = TextureReductionOp::Comparison;
+ dstDesc.comparisonFunc = ComparisonFunc::Less;
+ }
return dstDesc;
}
-/* static */BindingState::RegisterRange ShaderRendererUtil::calcRegisterRange(Renderer* renderer, const ShaderInputLayoutEntry& entry)
+static RefPtr<SamplerState> _createSamplerState(
+ Renderer* renderer,
+ const InputSamplerDesc& srcDesc)
{
- typedef BindingState::RegisterRange RegisterRange;
+ return renderer->createSamplerState(_calcSamplerDesc(srcDesc));
+}
+
+/* static */BindingStateImpl::RegisterRange ShaderRendererUtil::calcRegisterRange(Renderer* renderer, const ShaderInputLayoutEntry& entry)
+{
+ typedef BindingStateImpl::RegisterRange RegisterRange;
BindingStyle bindingStyle = RendererUtil::getBindingStyle(renderer->getRendererType());
@@ -179,71 +200,227 @@ static BindingState::SamplerDesc _calcSamplerDesc(const InputSamplerDesc& srcDes
return RegisterRange::makeInvalid();
}
-/* static */Result ShaderRendererUtil::createBindingStateDesc(ShaderInputLayoutEntry* srcEntries, int numEntries, Renderer* renderer, BindingState::Desc& descOut)
+/* static */Result ShaderRendererUtil::createBindingState(const ShaderInputLayout& layout, Renderer* renderer, BufferResource* addedConstantBuffer, BindingStateImpl** outBindingState)
{
+ auto srcEntries = layout.entries.Buffer();
+ auto numEntries = int(layout.entries.Count());
+
const int textureBindFlags = Resource::BindFlag::NonPixelShaderResource | Resource::BindFlag::PixelShaderResource;
- descOut.clear();
+ List<DescriptorSetLayout::SlotRangeDesc> slotRangeDescs;
+
+ if(addedConstantBuffer)
+ {
+ DescriptorSetLayout::SlotRangeDesc slotRangeDesc;
+ slotRangeDesc.type = DescriptorSlotType::UniformBuffer;
+
+ slotRangeDescs.Add(slotRangeDesc);
+ }
+
for (int i = 0; i < numEntries; i++)
{
const ShaderInputLayoutEntry& srcEntry = srcEntries[i];
- const BindingState::RegisterRange registerSet = calcRegisterRange(renderer, srcEntry);
+ const BindingStateImpl::RegisterRange registerSet = calcRegisterRange(renderer, srcEntry);
if (!registerSet.isValid())
{
assert(!"Couldn't find a binding");
return SLANG_FAIL;
}
+ DescriptorSetLayout::SlotRangeDesc slotRangeDesc;
+
switch (srcEntry.type)
{
case ShaderInputType::Buffer:
- {
- const InputBufferDesc& srcBuffer = srcEntry.bufferDesc;
+ {
+ const InputBufferDesc& srcBuffer = srcEntry.bufferDesc;
+
+ switch (srcBuffer.type)
+ {
+ case InputBufferType::ConstantBuffer:
+ slotRangeDesc.type = DescriptorSlotType::UniformBuffer;
+ break;
+
+ case InputBufferType::StorageBuffer:
+ slotRangeDesc.type = DescriptorSlotType::StorageBuffer;
+ break;
+ }
+ }
+ break;
- const size_t bufferSize = srcEntry.bufferData.Count() * sizeof(uint32_t);
+ case ShaderInputType::CombinedTextureSampler:
+ {
+ slotRangeDesc.type = DescriptorSlotType::CombinedImageSampler;
+ }
+ break;
- RefPtr<BufferResource> bufferResource;
- SLANG_RETURN_ON_FAIL(createBufferResource(srcEntry.bufferDesc, srcEntry.isOutput, bufferSize, srcEntry.bufferData.Buffer(), renderer, bufferResource));
+ case ShaderInputType::Texture:
+ {
+ if (srcEntry.textureDesc.isRWTexture)
+ {
+ slotRangeDesc.type = DescriptorSlotType::StorageImage;
+ }
+ else
+ {
+ slotRangeDesc.type = DescriptorSlotType::SampledImage;
+ }
+ }
+ break;
- descOut.addBufferResource(bufferResource, registerSet);
+ case ShaderInputType::Sampler:
+ slotRangeDesc.type = DescriptorSlotType::Sampler;
break;
- }
+
+ default:
+ assert(!"Unhandled type");
+ return SLANG_FAIL;
+ }
+ slotRangeDescs.Add(slotRangeDesc);
+ }
+
+ DescriptorSetLayout::Desc descriptorSetLayoutDesc;
+ descriptorSetLayoutDesc.slotRangeCount = slotRangeDescs.Count();
+ descriptorSetLayoutDesc.slotRanges = slotRangeDescs.Buffer();
+
+ auto descriptorSetLayout = renderer->createDescriptorSetLayout(descriptorSetLayoutDesc);
+ if(!descriptorSetLayout) return SLANG_FAIL;
+
+ List<PipelineLayout::DescriptorSetDesc> pipelineDescriptorSets;
+ pipelineDescriptorSets.Add(PipelineLayout::DescriptorSetDesc(descriptorSetLayout));
+
+ PipelineLayout::Desc pipelineLayoutDesc;
+ pipelineLayoutDesc.renderTargetCount = layout.numRenderTargets;
+ pipelineLayoutDesc.descriptorSetCount = pipelineDescriptorSets.Count();
+ pipelineLayoutDesc.descriptorSets = pipelineDescriptorSets.Buffer();
+
+ auto pipelineLayout = renderer->createPipelineLayout(pipelineLayoutDesc);
+ if(!pipelineLayout) return SLANG_FAIL;
+
+ auto descriptorSet = renderer->createDescriptorSet(descriptorSetLayout);
+ if(!descriptorSet) return SLANG_FAIL;
+
+ List<BindingStateImpl::OutputBinding> outputBindings;
+
+ if(addedConstantBuffer)
+ {
+ descriptorSet->setConstantBuffer(0, 0, addedConstantBuffer);
+ }
+ for (int i = 0; i < numEntries; i++)
+ {
+ const ShaderInputLayoutEntry& srcEntry = srcEntries[i];
+
+ auto rangeIndex = i + (addedConstantBuffer ? 1 : 0);
+
+ switch (srcEntry.type)
+ {
+ case ShaderInputType::Buffer:
+ {
+ const InputBufferDesc& srcBuffer = srcEntry.bufferDesc;
+ const size_t bufferSize = srcEntry.bufferData.Count() * sizeof(uint32_t);
+
+ RefPtr<BufferResource> bufferResource;
+ SLANG_RETURN_ON_FAIL(createBufferResource(srcEntry.bufferDesc, srcEntry.isOutput, bufferSize, srcEntry.bufferData.Buffer(), renderer, bufferResource));
+
+ switch(srcBuffer.type)
+ {
+ case InputBufferType::ConstantBuffer:
+ descriptorSet->setConstantBuffer(rangeIndex, 0, bufferResource);
+ break;
+
+ case InputBufferType::StorageBuffer:
+ {
+ ResourceView::Desc viewDesc;
+ viewDesc.type = ResourceView::Type::UnorderedAccess;
+ viewDesc.format = srcBuffer.format;
+ auto bufferView = renderer->createBufferView(
+ bufferResource,
+ viewDesc);
+ descriptorSet->setResource(rangeIndex, 0, bufferView);
+ }
+ break;
+ }
+
+ if(srcEntry.isOutput)
+ {
+ BindingStateImpl::OutputBinding binding;
+ binding.entryIndex = i;
+ binding.resource = bufferResource;
+ outputBindings.Add(binding);
+ }
+ }
+ break;
+
case ShaderInputType::CombinedTextureSampler:
- {
- RefPtr<TextureResource> texture;
- SLANG_RETURN_ON_FAIL(generateTextureResource(srcEntry.textureDesc, textureBindFlags, renderer, texture));
- descOut.addCombinedTextureSampler(texture, _calcSamplerDesc(srcEntry.samplerDesc), registerSet);
+ {
+ RefPtr<TextureResource> texture;
+ SLANG_RETURN_ON_FAIL(generateTextureResource(srcEntry.textureDesc, textureBindFlags, renderer, texture));
+
+ auto sampler = _createSamplerState(renderer, srcEntry.samplerDesc);
+
+ ResourceView::Desc viewDesc;
+ viewDesc.type = ResourceView::Type::ShaderResource;
+ auto textureView = renderer->createTextureView(
+ texture,
+ viewDesc);
+
+ descriptorSet->setCombinedTextureSampler(rangeIndex, 0, textureView, sampler);
+
+ if(srcEntry.isOutput)
+ {
+ BindingStateImpl::OutputBinding binding;
+ binding.entryIndex = i;
+ binding.resource = texture;
+ outputBindings.Add(binding);
+ }
+ }
break;
- }
- case ShaderInputType::Texture:
- {
- RefPtr<TextureResource> texture;
- SLANG_RETURN_ON_FAIL(generateTextureResource(srcEntry.textureDesc, textureBindFlags, renderer, texture));
- descOut.addTextureResource(texture, registerSet);
+ case ShaderInputType::Texture:
+ {
+ RefPtr<TextureResource> texture;
+ SLANG_RETURN_ON_FAIL(generateTextureResource(srcEntry.textureDesc, textureBindFlags, renderer, texture));
+
+ // TODO: support UAV textures...
+
+ ResourceView::Desc viewDesc;
+ viewDesc.type = ResourceView::Type::ShaderResource;
+ auto textureView = renderer->createTextureView(
+ texture,
+ viewDesc);
+
+ descriptorSet->setResource(rangeIndex, 0, textureView);
+
+ if(srcEntry.isOutput)
+ {
+ BindingStateImpl::OutputBinding binding;
+ binding.entryIndex = i;
+ binding.resource = texture;
+ outputBindings.Add(binding);
+ }
+ }
break;
- }
+
case ShaderInputType::Sampler:
- {
- descOut.addSampler(_calcSamplerDesc(srcEntry.samplerDesc), registerSet);
+ {
+ auto sampler = _createSamplerState(renderer, srcEntry.samplerDesc);
+ descriptorSet->setSampler(rangeIndex, 0, sampler);
+ }
break;
- }
+
default:
- {
assert(!"Unhandled type");
return SLANG_FAIL;
- }
}
}
- return SLANG_OK;
-}
+ BindingStateImpl* bindingState = new BindingStateImpl();
+ bindingState->descriptorSet = descriptorSet;
+ bindingState->pipelineLayout = pipelineLayout;
+ bindingState->outputBindings = outputBindings;
+ bindingState->m_numRenderTargets = layout.numRenderTargets;
-/* static */Result ShaderRendererUtil::createBindingStateDesc(const ShaderInputLayout& layout, Renderer* renderer, BindingState::Desc& descOut)
-{
- SLANG_RETURN_ON_FAIL(createBindingStateDesc(layout.entries.Buffer(), int(layout.entries.Count()), renderer, descOut));
- descOut.m_numRenderTargets = layout.numRenderTargets;
+ *outBindingState = bindingState;
return SLANG_OK;
}
diff --git a/tools/render-test/shader-renderer-util.h b/tools/render-test/shader-renderer-util.h
index 849e68754..bbdea2af6 100644
--- a/tools/render-test/shader-renderer-util.h
+++ b/tools/render-test/shader-renderer-util.h
@@ -6,26 +6,68 @@
namespace renderer_test {
-/// Utility class containing functions that construct items on the renderer using the ShaderInputLayout representation
-struct ShaderRendererUtil
+using namespace Slang;
+
+struct BindingStateImpl : public Slang::RefObject
+{
+ /// A register set consists of one or more contiguous indices.
+ /// To be valid index >= 0 and size >= 1
+ struct RegisterRange
+ {
+ /// True if contains valid contents
+ bool isValid() const { return size > 0; }
+ /// True if valid single value
+ bool isSingle() const { return size == 1; }
+ /// Get as a single index (must be at least one index)
+ int getSingleIndex() const { return (size == 1) ? index : -1; }
+ /// Return the first index
+ int getFirstIndex() const { return (size > 0) ? index : -1; }
+ /// True if contains register index
+ bool hasRegister(int registerIndex) const { return registerIndex >= index && registerIndex < index + size; }
+
+ static RegisterRange makeInvalid() { return RegisterRange{ -1, 0 }; }
+ static RegisterRange makeSingle(int index) { return RegisterRange{ int16_t(index), 1 }; }
+ static RegisterRange makeRange(int index, int size) { return RegisterRange{ int16_t(index), uint16_t(size) }; }
+
+ int16_t index; ///< The base index
+ uint16_t size; ///< The amount of register indices
+ };
+
+ void apply(Renderer* renderer, PipelineType pipelineType);
+
+ struct OutputBinding
+ {
+ RefPtr<Resource> resource;
+ Slang::UInt entryIndex;
+ };
+ List<OutputBinding> outputBindings;
+
+ RefPtr<PipelineLayout> pipelineLayout;
+ RefPtr<DescriptorSet> descriptorSet;
+ int m_numRenderTargets = 1;
+};
+
+/// Utility class containing functions that construct items on the renderer using the ShaderInputLayout representation
+struct ShaderRendererUtil
{
/// Generate a texture using the InputTextureDesc and construct a TextureResource using the Renderer with the contents
static Slang::Result generateTextureResource(const InputTextureDesc& inputDesc, int bindFlags, Renderer* renderer, Slang::RefPtr<TextureResource>& textureOut);
/// Create texture resource using inputDesc, and texData to describe format, and contents
static Slang::Result createTextureResource(const InputTextureDesc& inputDesc, const TextureData& texData, int bindFlags, Renderer* renderer, Slang::RefPtr<TextureResource>& textureOut);
-
+
/// Create the BufferResource using the renderer from the contents of inputDesc
static Slang::Result createBufferResource(const InputBufferDesc& inputDesc, bool isOutput, size_t bufferSize, const void* initData, Renderer* renderer, Slang::RefPtr<BufferResource>& bufferOut);
/// Create BindingState::Desc from the contents of layout
- static Slang::Result createBindingStateDesc(const ShaderInputLayout& layout, Renderer* renderer, BindingState::Desc& descOut);
- /// Create BindingState::Desc from a list of ShaderInputLayout entries
- static Slang::Result createBindingStateDesc(ShaderInputLayoutEntry* srcEntries, int numEntries, Renderer* renderer, BindingState::Desc& descOut);
+ static Slang::Result createBindingState(const ShaderInputLayout& layout, Renderer* renderer, BufferResource* addedConstantBuffer, BindingStateImpl** outBindingState);
/// Get the binding register associated with this binding (or -1 if none defined)
- static BindingState::RegisterRange calcRegisterRange(Renderer* renderer, const ShaderInputLayoutEntry& entry);
+ static BindingStateImpl::RegisterRange calcRegisterRange(Renderer* renderer, const ShaderInputLayoutEntry& entry);
+private:
+ /// Create BindingState::Desc from a list of ShaderInputLayout entries
+ static Slang::Result _createBindingState(ShaderInputLayoutEntry* srcEntries, int numEntries, Renderer* renderer, BufferResource* addedConstantBuffer, BindingStateImpl** outBindingState);
};
} // renderer_test
diff --git a/tools/render-test/slang-support.cpp b/tools/render-test/slang-support.cpp
index a6c252843..26e856295 100644
--- a/tools/render-test/slang-support.cpp
+++ b/tools/render-test/slang-support.cpp
@@ -11,7 +11,7 @@
namespace renderer_test {
-ShaderProgram* ShaderCompiler::compileProgram(
+RefPtr<ShaderProgram> ShaderCompiler::compileProgram(
ShaderCompileRequest const& request)
{
SlangSession* slangSession = spCreateSession(NULL);
@@ -92,7 +92,7 @@ ShaderProgram* ShaderCompiler::compileProgram(
}
- ShaderProgram * shaderProgram = nullptr;
+ RefPtr<ShaderProgram> shaderProgram;
Slang::List<const char*> rawTypeNames;
for (auto typeName : request.entryPointTypeArguments)
rawTypeNames.Add(typeName.Buffer());
diff --git a/tools/render-test/slang-support.h b/tools/render-test/slang-support.h
index 8697abcb8..03de062d1 100644
--- a/tools/render-test/slang-support.h
+++ b/tools/render-test/slang-support.h
@@ -11,13 +11,13 @@ namespace renderer_test {
struct ShaderCompiler
{
- Renderer* renderer;
+ RefPtr<Renderer> renderer;
SlangCompileTarget target;
SlangSourceLanguage sourceLanguage;
SlangPassThrough passThrough;
char const* profile;
- ShaderProgram* compileProgram(
+ RefPtr<ShaderProgram> compileProgram(
ShaderCompileRequest const& request);
};
diff --git a/tools/slang-graphics/render-d3d11.cpp b/tools/slang-graphics/render-d3d11.cpp
deleted file mode 100644
index 4f9749e39..000000000
--- a/tools/slang-graphics/render-d3d11.cpp
+++ /dev/null
@@ -1,1101 +0,0 @@
-// render-d3d11.cpp
-
-#define _CRT_SECURE_NO_WARNINGS
-
-#include "render-d3d11.h"
-
-//WORKING: #include "options.h"
-#include "render.h"
-#include "d3d-util.h"
-
-#include "surface.h"
-
-// In order to use the Slang API, we need to include its header
-
-//#include <slang.h>
-
-#include "../../slang-com-ptr.h"
-
-// We will be rendering with Direct3D 11, so we need to include
-// the Windows and D3D11 headers
-
-#define WIN32_LEAN_AND_MEAN
-#define NOMINMAX
-#include <Windows.h>
-#undef WIN32_LEAN_AND_MEAN
-#undef NOMINMAX
-
-#include <d3d11_2.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;
-
-namespace slang_graphics {
-
-class D3D11Renderer : public Renderer
-{
-public:
- // Renderer implementation
- virtual SlangResult initialize(const Desc& desc, void* inWindowHandle) override;
- virtual void setClearColor(const float color[4]) override;
- virtual void clearFrame() override;
- virtual void presentFrame() override;
- virtual TextureResource* createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData) override;
- virtual BufferResource* createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& bufferDesc, const void* initData) override;
- virtual SlangResult captureScreenSurface(Surface& surfaceOut) override;
- virtual InputLayout* createInputLayout( const InputElementDesc* inputElements, UInt inputElementCount) override;
- virtual BindingState* createBindingState(const BindingState::Desc& desc) override;
- virtual ShaderProgram* createProgram(const ShaderProgram::Desc& desc) override;
- virtual void* map(BufferResource* buffer, MapFlavor flavor) override;
- virtual void unmap(BufferResource* buffer) override;
- virtual void setInputLayout(InputLayout* inputLayout) override;
- virtual void setPrimitiveTopology(PrimitiveTopology topology) override;
- virtual void setBindingState(BindingState * state);
- virtual void setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffers, const UInt* strides, const UInt* offsets) override;
- virtual void setShaderProgram(ShaderProgram* inProgram) override;
- virtual void draw(UInt vertexCount, UInt startVertex) override;
- virtual void dispatchCompute(int x, int y, int z) override;
- virtual void submitGpuWork() override {}
- virtual void waitForGpu() override {}
- virtual RendererType getRendererType() const override { return RendererType::DirectX11; }
-
- protected:
-
- struct BindingDetail
- {
- ComPtr<ID3D11ShaderResourceView> m_srv;
- ComPtr<ID3D11UnorderedAccessView> m_uav;
- ComPtr<ID3D11SamplerState> m_samplerState;
- };
-
- class BindingStateImpl: public BindingState
- {
- public:
- typedef BindingState Parent;
-
- /// Ctor
- BindingStateImpl(const Desc& desc):
- Parent(desc)
- {}
-
- List<BindingDetail> m_bindingDetails;
- };
-
- class ShaderProgramImpl: public ShaderProgram
- {
- public:
- ComPtr<ID3D11VertexShader> m_vertexShader;
- ComPtr<ID3D11PixelShader> m_pixelShader;
- ComPtr<ID3D11ComputeShader> m_computeShader;
- };
-
- class BufferResourceImpl: public BufferResource
- {
- public:
- typedef BufferResource Parent;
-
- BufferResourceImpl(const Desc& desc, Usage initialUsage):
- Parent(desc),
- m_initialUsage(initialUsage)
- {
- }
-
- MapFlavor m_mapFlavor;
- Usage m_initialUsage;
- ComPtr<ID3D11Buffer> m_buffer;
- ComPtr<ID3D11Buffer> m_staging;
- };
- class TextureResourceImpl : public TextureResource
- {
- public:
- typedef TextureResource Parent;
-
- TextureResourceImpl(const Desc& desc, Usage initialUsage) :
- Parent(desc),
- m_initialUsage(initialUsage)
- {
- }
- Usage m_initialUsage;
- ComPtr<ID3D11Resource> m_resource;
- };
-
- class InputLayoutImpl: public InputLayout
- {
- public:
- ComPtr<ID3D11InputLayout> m_layout;
- };
-
- /// Capture a texture to a file
- static HRESULT captureTextureToSurface(ID3D11Device* device, ID3D11DeviceContext* context, ID3D11Texture2D* texture, Surface& surfaceOut);
-
- void _applyBindingState(bool isCompute);
-
- ComPtr<IDXGISwapChain> m_swapChain;
- ComPtr<ID3D11Device> m_device;
- ComPtr<ID3D11DeviceContext> m_immediateContext;
- ComPtr<ID3D11Texture2D> m_backBufferTexture;
-
- List<ComPtr<ID3D11RenderTargetView> > m_renderTargetViews;
- List<ComPtr<ID3D11Texture2D> > m_renderTargetTextures;
-
- RefPtr<BindingStateImpl> m_currentBindings;
-
- Desc m_desc;
-
- float m_clearColor[4] = { 0, 0, 0, 0 };
-};
-
-Renderer* createD3D11Renderer()
-{
- return new D3D11Renderer();
-}
-
-/* static */HRESULT D3D11Renderer::captureTextureToSurface(ID3D11Device* device, ID3D11DeviceContext* context, ID3D11Texture2D* texture, Surface& surfaceOut)
-{
- if (!context) return E_INVALIDARG;
- if (!texture) return E_INVALIDARG;
-
- D3D11_TEXTURE2D_DESC textureDesc;
- texture->GetDesc(&textureDesc);
-
- // Don't bother supporting MSAA for right now
- if (textureDesc.SampleDesc.Count > 1)
- {
- fprintf(stderr, "ERROR: cannot capture multi-sample texture\n");
- return E_INVALIDARG;
- }
-
- HRESULT hr = S_OK;
- ComPtr<ID3D11Texture2D> stagingTexture;
-
- if (textureDesc.Usage == D3D11_USAGE_STAGING && (textureDesc.CPUAccessFlags & D3D11_CPU_ACCESS_READ))
- {
- stagingTexture = texture;
- }
- else
- {
- // Modify the descriptor to give us a staging texture
- textureDesc.BindFlags = 0;
- textureDesc.MiscFlags &= ~D3D11_RESOURCE_MISC_TEXTURECUBE;
- textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
- textureDesc.Usage = D3D11_USAGE_STAGING;
-
- hr = device->CreateTexture2D(&textureDesc, 0, stagingTexture.writeRef());
- if (FAILED(hr))
- {
- fprintf(stderr, "ERROR: failed to create staging texture\n");
- return hr;
- }
-
- context->CopyResource(stagingTexture, texture);
- }
-
- // Now just read back texels from the staging textures
- {
- D3D11_MAPPED_SUBRESOURCE mappedResource;
- SLANG_RETURN_ON_FAIL(context->Map(stagingTexture, 0, D3D11_MAP_READ, 0, &mappedResource));
-
- Result res = surfaceOut.set(textureDesc.Width, textureDesc.Height, Format::RGBA_Unorm_UInt8, mappedResource.RowPitch, mappedResource.pData, SurfaceAllocator::getMallocAllocator());
-
- // Make sure to unmap
- context->Unmap(stagingTexture, 0);
- return res;
- }
-}
-
-// !!!!!!!!!!!!!!!!!!!!!!!!!!!! Renderer interface !!!!!!!!!!!!!!!!!!!!!!!!!!
-
-SlangResult D3D11Renderer::initialize(const Desc& desc, void* inWindowHandle)
-{
- auto windowHandle = (HWND)inWindowHandle;
- m_desc = desc;
-
- // Rather than statically link against D3D, we load it dynamically.
- HMODULE d3dModule = LoadLibraryA("d3d11.dll");
- if (!d3dModule)
- {
- fprintf(stderr, "error: failed load 'd3d11.dll'\n");
- return SLANG_FAIL;
- }
-
- PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN D3D11CreateDeviceAndSwapChain_ =
- (PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN)GetProcAddress(d3dModule, "D3D11CreateDeviceAndSwapChain");
- if (!D3D11CreateDeviceAndSwapChain_)
- {
- fprintf(stderr,
- "error: failed load symbol 'D3D11CreateDeviceAndSwapChain'\n");
- return SLANG_FAIL;
- }
-
- // We create our device in debug mode, just so that we can check that the
- // example doesn't trigger warnings.
- UINT deviceFlags = 0;
- deviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
-
- // Our swap chain uses RGBA8 with sRGB, with double buffering.
- DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 };
- swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
-
- // Note(tfoley): Disabling sRGB for DX back buffer for now, so that we
- // can get consistent output with OpenGL, where setting up sRGB will
- // probably be more involved.
- // swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
- swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
-
- swapChainDesc.SampleDesc.Count = 1;
- swapChainDesc.SampleDesc.Quality = 0;
- swapChainDesc.BufferCount = 2;
- swapChainDesc.OutputWindow = windowHandle;
- swapChainDesc.Windowed = TRUE;
- swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
- swapChainDesc.Flags = 0;
-
- // We will ask for the highest feature level that can be supported.
- const D3D_FEATURE_LEVEL featureLevels[] = {
- D3D_FEATURE_LEVEL_11_1,
- D3D_FEATURE_LEVEL_11_0,
- D3D_FEATURE_LEVEL_10_1,
- D3D_FEATURE_LEVEL_10_0,
- D3D_FEATURE_LEVEL_9_3,
- D3D_FEATURE_LEVEL_9_2,
- D3D_FEATURE_LEVEL_9_1,
- };
- D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_9_1;
- const int totalNumFeatureLevels = SLANG_COUNT_OF(featureLevels);
-
- // On a machine that does not have an up-to-date version of D3D installed,
- // the `D3D11CreateDeviceAndSwapChain` call will fail with `E_INVALIDARG`
- // if you ask for featuer level 11_1. The workaround is to call
- // `D3D11CreateDeviceAndSwapChain` up to twice: the first time with 11_1
- // at the start of the list of requested feature levels, and the second
- // time without it.
-
- for (int ii = 0; ii < 2; ++ii)
- {
- const HRESULT hr = D3D11CreateDeviceAndSwapChain_(
- nullptr, // adapter (use default)
- D3D_DRIVER_TYPE_REFERENCE,
- //D3D_DRIVER_TYPE_HARDWARE,
- nullptr, // software
- deviceFlags,
- &featureLevels[ii],
- totalNumFeatureLevels - ii,
- D3D11_SDK_VERSION,
- &swapChainDesc,
- m_swapChain.writeRef(),
- m_device.writeRef(),
- &featureLevel,
- m_immediateContext.writeRef());
-
- // Failures with `E_INVALIDARG` might be due to feature level 11_1
- // not being supported.
- if (hr == E_INVALIDARG)
- {
- continue;
- }
-
- // Other failures are real, though.
- SLANG_RETURN_ON_FAIL(hr);
- // We must have a swap chain
- break;
- }
-
- // After we've created the swap chain, we can request a pointer to the
- // back buffer as a D3D11 texture, and create a render-target view from it.
-
- static const IID kIID_ID3D11Texture2D = {
- 0x6f15aaf2, 0xd208, 0x4e89, 0x9a, 0xb4, 0x48,
- 0x95, 0x35, 0xd3, 0x4f, 0x9c };
-
- SLANG_RETURN_ON_FAIL(m_swapChain->GetBuffer(0, kIID_ID3D11Texture2D, (void**)m_backBufferTexture.writeRef()));
-
- for (int i = 0; i < 8; i++)
- {
- ComPtr<ID3D11Texture2D> texture;
- D3D11_TEXTURE2D_DESC textureDesc;
- m_backBufferTexture->GetDesc(&textureDesc);
- SLANG_RETURN_ON_FAIL(m_device->CreateTexture2D(&textureDesc, nullptr, texture.writeRef()));
-
- ComPtr<ID3D11RenderTargetView> rtv;
- D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
- rtvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
- rtvDesc.Texture2D.MipSlice = 0;
- rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
- SLANG_RETURN_ON_FAIL(m_device->CreateRenderTargetView(texture, &rtvDesc, rtv.writeRef()));
-
- m_renderTargetViews.Add(rtv);
- m_renderTargetTextures.Add(texture);
- }
-
- m_immediateContext->OMSetRenderTargets((UINT)m_renderTargetViews.Count(), m_renderTargetViews.Buffer()->readRef(), nullptr);
-
- // Similarly, we are going to set up a viewport once, and then never
- // switch, since this is a simple test app.
- D3D11_VIEWPORT viewport;
- viewport.TopLeftX = 0;
- viewport.TopLeftY = 0;
- viewport.Width = (float)desc.width;
- viewport.Height = (float)desc.height;
- viewport.MaxDepth = 1; // TODO(tfoley): use reversed depth
- viewport.MinDepth = 0;
- m_immediateContext->RSSetViewports(1, &viewport);
-
- return SLANG_OK;
-}
-
-void D3D11Renderer::setClearColor(const float color[4])
-{
- memcpy(m_clearColor, color, sizeof(m_clearColor));
-}
-
-void D3D11Renderer::clearFrame()
-{
- for (auto i = 0u; i < m_renderTargetViews.Count(); i++)
- {
- m_immediateContext->ClearRenderTargetView(m_renderTargetViews[i], m_clearColor);
- }
-}
-
-void D3D11Renderer::presentFrame()
-{
- m_immediateContext->CopyResource(m_backBufferTexture, m_renderTargetTextures[0]);
- m_swapChain->Present(0, 0);
-}
-
-SlangResult D3D11Renderer::captureScreenSurface(Surface& surfaceOut)
-{
- return captureTextureToSurface(m_device, m_immediateContext, m_renderTargetTextures[0], surfaceOut);
-}
-
-static D3D11_BIND_FLAG _calcResourceFlag(Resource::BindFlag::Enum bindFlag)
-{
- typedef Resource::BindFlag BindFlag;
- switch (bindFlag)
- {
- case BindFlag::VertexBuffer: return D3D11_BIND_VERTEX_BUFFER;
- case BindFlag::IndexBuffer: return D3D11_BIND_INDEX_BUFFER;
- case BindFlag::ConstantBuffer: return D3D11_BIND_CONSTANT_BUFFER;
- case BindFlag::StreamOutput: return D3D11_BIND_STREAM_OUTPUT;
- case BindFlag::RenderTarget: return D3D11_BIND_RENDER_TARGET;
- case BindFlag::DepthStencil: return D3D11_BIND_DEPTH_STENCIL;
- case BindFlag::UnorderedAccess: return D3D11_BIND_UNORDERED_ACCESS;
- case BindFlag::PixelShaderResource: return D3D11_BIND_SHADER_RESOURCE;
- case BindFlag::NonPixelShaderResource: return D3D11_BIND_SHADER_RESOURCE;
- default: return D3D11_BIND_FLAG(0);
- }
-}
-
-static int _calcResourceBindFlags(int bindFlags)
-{
- int dstFlags = 0;
- while (bindFlags)
- {
- int lsb = bindFlags & -bindFlags;
-
- dstFlags |= _calcResourceFlag(Resource::BindFlag::Enum(lsb));
- bindFlags &= ~lsb;
- }
- return dstFlags;
-}
-
-static int _calcResourceAccessFlags(int accessFlags)
-{
- switch (accessFlags)
- {
- case 0: return 0;
- case Resource::AccessFlag::Read: return D3D11_CPU_ACCESS_READ;
- case Resource::AccessFlag::Write: return D3D11_CPU_ACCESS_WRITE;
- case Resource::AccessFlag::Read |
- Resource::AccessFlag::Write: return D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
- default: assert(!"Invalid flags"); return 0;
- }
-}
-
-TextureResource* D3D11Renderer::createTextureResource(Resource::Usage initialUsage, const TextureResource::Desc& descIn, const TextureResource::Data* initData)
-{
- TextureResource::Desc srcDesc(descIn);
- srcDesc.setDefaults(initialUsage);
-
- const int effectiveArraySize = srcDesc.calcEffectiveArraySize();
-
- assert(initData);
- assert(initData->numSubResources == srcDesc.numMipLevels * effectiveArraySize * srcDesc.size.depth);
-
- const DXGI_FORMAT format = D3DUtil::getMapFormat(srcDesc.format);
- if (format == DXGI_FORMAT_UNKNOWN)
- {
- return nullptr;
- }
-
- const int bindFlags = _calcResourceBindFlags(srcDesc.bindFlags);
-
- // Set up the initialize data
- List<D3D11_SUBRESOURCE_DATA> subRes;
- subRes.SetSize(srcDesc.numMipLevels * effectiveArraySize);
- {
- int subResourceIndex = 0;
- for (int i = 0; i < effectiveArraySize; i++)
- {
- for (int j = 0; j < srcDesc.numMipLevels; j++)
- {
- const int mipHeight = TextureResource::calcMipSize(srcDesc.size.height, j);
-
- D3D11_SUBRESOURCE_DATA& data = subRes[subResourceIndex];
-
- data.pSysMem = initData->subResources[subResourceIndex];
-
- data.SysMemPitch = UINT(initData->mipRowStrides[j]);
- data.SysMemSlicePitch = UINT(initData->mipRowStrides[j] * mipHeight);
-
- subResourceIndex++;
- }
- }
- }
-
- const int accessFlags = _calcResourceAccessFlags(srcDesc.cpuAccessFlags);
-
- RefPtr<TextureResourceImpl> texture(new TextureResourceImpl(srcDesc, initialUsage));
-
- switch (srcDesc.type)
- {
- case Resource::Type::Texture1D:
- {
- D3D11_TEXTURE1D_DESC desc = { 0 };
- desc.BindFlags = bindFlags;
- desc.CPUAccessFlags = accessFlags;
- desc.Format = format;
- desc.MiscFlags = 0;
- desc.MipLevels = srcDesc.numMipLevels;
- desc.ArraySize = effectiveArraySize;
- desc.Width = srcDesc.size.width;
- desc.Usage = D3D11_USAGE_DEFAULT;
-
- ComPtr<ID3D11Texture1D> texture1D;
- SLANG_RETURN_NULL_ON_FAIL(m_device->CreateTexture1D(&desc, subRes.Buffer(), texture1D.writeRef()));
-
- texture->m_resource = texture1D;
- break;
- }
- case Resource::Type::TextureCube:
- case Resource::Type::Texture2D:
- {
- D3D11_TEXTURE2D_DESC desc = { 0 };
- desc.BindFlags = bindFlags;
- desc.CPUAccessFlags = accessFlags;
- desc.Format = format;
- desc.MiscFlags = 0;
- desc.MipLevels = srcDesc.numMipLevels;
- desc.ArraySize = effectiveArraySize;
-
- desc.Width = srcDesc.size.width;
- desc.Height = srcDesc.size.height;
- desc.Usage = D3D11_USAGE_DEFAULT;
- desc.SampleDesc.Count = srcDesc.sampleDesc.numSamples;
- desc.SampleDesc.Quality = srcDesc.sampleDesc.quality;
-
- if (srcDesc.type == Resource::Type::TextureCube)
- {
- desc.MiscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE;
- }
-
- ComPtr<ID3D11Texture2D> texture2D;
- SLANG_RETURN_NULL_ON_FAIL(m_device->CreateTexture2D(&desc, subRes.Buffer(), texture2D.writeRef()));
-
- texture->m_resource = texture2D;
- break;
- }
- case Resource::Type::Texture3D:
- {
- D3D11_TEXTURE3D_DESC desc = { 0 };
- desc.BindFlags = bindFlags;
- desc.CPUAccessFlags = accessFlags;
- desc.Format = format;
- desc.MiscFlags = 0;
- desc.MipLevels = srcDesc.numMipLevels;
- desc.Width = srcDesc.size.width;
- desc.Height = srcDesc.size.height;
- desc.Depth = srcDesc.size.depth;
- desc.Usage = D3D11_USAGE_DEFAULT;
-
- ComPtr<ID3D11Texture3D> texture3D;
- SLANG_RETURN_NULL_ON_FAIL(m_device->CreateTexture3D(&desc, subRes.Buffer(), texture3D.writeRef()));
-
- texture->m_resource = texture3D;
- break;
- }
- default: return nullptr;
- }
-
- return texture.detach();
-}
-
-BufferResource* D3D11Renderer::createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& descIn, const void* initData)
-{
- BufferResource::Desc srcDesc(descIn);
- srcDesc.setDefaults(initialUsage);
-
- // Make aligned to 256 bytes... not sure why, but if you remove this the tests do fail.
- const size_t alignedSizeInBytes = D3DUtil::calcAligned(srcDesc.sizeInBytes, 256);
-
- // Hack to make the initialization never read from out of bounds memory, by copying into a buffer
- List<uint8_t> initDataBuffer;
- if (initData && alignedSizeInBytes > srcDesc.sizeInBytes)
- {
- initDataBuffer.SetSize(alignedSizeInBytes);
- ::memcpy(initDataBuffer.Buffer(), initData, srcDesc.sizeInBytes);
- initData = initDataBuffer.Buffer();
- }
-
- D3D11_BUFFER_DESC bufferDesc = { 0 };
- bufferDesc.ByteWidth = UINT(alignedSizeInBytes);
- bufferDesc.BindFlags = _calcResourceBindFlags(srcDesc.bindFlags);
- // For read we'll need to do some staging
- bufferDesc.CPUAccessFlags = _calcResourceAccessFlags(descIn.cpuAccessFlags & Resource::AccessFlag::Write);
- bufferDesc.Usage = D3D11_USAGE_DEFAULT;
-
- // If written by CPU, make it dynamic
- if (descIn.cpuAccessFlags & Resource::AccessFlag::Write)
- {
- bufferDesc.Usage = D3D11_USAGE_DYNAMIC;
- }
-
- switch (initialUsage)
- {
- case Resource::Usage::ConstantBuffer:
- {
- // We'll just assume ConstantBuffers are dynamic for now
- bufferDesc.Usage = D3D11_USAGE_DYNAMIC;
- break;
- }
- default: break;
- }
-
- if (bufferDesc.BindFlags & (D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE))
- {
- //desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;
- if (srcDesc.elementSize != 0)
- {
- bufferDesc.StructureByteStride = srcDesc.elementSize;
- bufferDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
- }
- else
- {
- bufferDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
- }
- }
-
- D3D11_SUBRESOURCE_DATA subResourceData = { 0 };
- subResourceData.pSysMem = initData;
-
- RefPtr<BufferResourceImpl> buffer(new BufferResourceImpl(srcDesc, initialUsage));
-
- SLANG_RETURN_NULL_ON_FAIL(m_device->CreateBuffer(&bufferDesc, initData ? &subResourceData : nullptr, buffer->m_buffer.writeRef()));
-
- if (srcDesc.cpuAccessFlags & Resource::AccessFlag::Read)
- {
- D3D11_BUFFER_DESC bufDesc = {};
- bufDesc.BindFlags = 0;
- bufDesc.ByteWidth = (UINT)alignedSizeInBytes;
- bufDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
- bufDesc.Usage = D3D11_USAGE_STAGING;
-
- SLANG_RETURN_NULL_ON_FAIL(m_device->CreateBuffer(&bufDesc, nullptr, buffer->m_staging.writeRef()));
- }
-
- return buffer.detach();
-}
-
-InputLayout* D3D11Renderer::createInputLayout(const InputElementDesc* inputElementsIn, UInt inputElementCount)
-{
- D3D11_INPUT_ELEMENT_DESC inputElements[16] = {};
-
- char hlslBuffer[1024];
- char* hlslCursor = &hlslBuffer[0];
-
- hlslCursor += sprintf(hlslCursor, "float4 main(\n");
-
- for (UInt ii = 0; ii < inputElementCount; ++ii)
- {
- inputElements[ii].SemanticName = inputElementsIn[ii].semanticName;
- inputElements[ii].SemanticIndex = (UINT)inputElementsIn[ii].semanticIndex;
- inputElements[ii].Format = D3DUtil::getMapFormat(inputElementsIn[ii].format);
- inputElements[ii].InputSlot = 0;
- inputElements[ii].AlignedByteOffset = (UINT)inputElementsIn[ii].offset;
- inputElements[ii].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
- inputElements[ii].InstanceDataStepRate = 0;
-
- if (ii != 0)
- {
- hlslCursor += sprintf(hlslCursor, ",\n");
- }
-
- char const* typeName = "Unknown";
- switch (inputElementsIn[ii].format)
- {
- case Format::RGBA_Float32:
- typeName = "float4";
- break;
- case Format::RGB_Float32:
- typeName = "float3";
- break;
- case Format::RG_Float32:
- typeName = "float2";
- break;
- case Format::R_Float32:
- typeName = "float";
- break;
- default:
- return nullptr;
- }
-
- hlslCursor += sprintf(hlslCursor, "%s a%d : %s%d",
- typeName,
- (int)ii,
- inputElementsIn[ii].semanticName,
- (int)inputElementsIn[ii].semanticIndex);
- }
-
- hlslCursor += sprintf(hlslCursor, "\n) : SV_Position { return 0; }");
-
- ComPtr<ID3DBlob> vertexShaderBlob;
- SLANG_RETURN_NULL_ON_FAIL(D3DUtil::compileHLSLShader("inputLayout", hlslBuffer, "main", "vs_5_0", vertexShaderBlob));
-
- ComPtr<ID3D11InputLayout> inputLayout;
- SLANG_RETURN_NULL_ON_FAIL(m_device->CreateInputLayout(&inputElements[0], (UINT)inputElementCount, vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(),
- inputLayout.writeRef()));
-
- InputLayoutImpl* impl = new InputLayoutImpl;
- impl->m_layout.swap(inputLayout);
-
- return impl;
-}
-
-void* D3D11Renderer::map(BufferResource* bufferIn, MapFlavor flavor)
-{
- BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(bufferIn);
-
- D3D11_MAP mapType;
- ID3D11Buffer* buffer = bufferResource->m_buffer;
-
- switch (flavor)
- {
- case MapFlavor::WriteDiscard:
- mapType = D3D11_MAP_WRITE_DISCARD;
- break;
- case MapFlavor::HostWrite:
- mapType = D3D11_MAP_WRITE;
- break;
- case MapFlavor::HostRead:
- mapType = D3D11_MAP_READ;
-
- buffer = bufferResource->m_staging;
- if (!buffer)
- {
- return nullptr;
- }
-
- // Okay copy the data over
- m_immediateContext->CopyResource(buffer, bufferResource->m_buffer);
-
- break;
- default:
- return nullptr;
- }
-
- // We update our constant buffer per-frame, just for the purposes
- // of the example, but we don't actually load different data
- // per-frame (we always use an identity projection).
- D3D11_MAPPED_SUBRESOURCE mappedSub;
- SLANG_RETURN_NULL_ON_FAIL(m_immediateContext->Map(buffer, 0, mapType, 0, &mappedSub));
-
- bufferResource->m_mapFlavor = flavor;
-
- return mappedSub.pData;
-}
-
-void D3D11Renderer::unmap(BufferResource* bufferIn)
-{
- BufferResourceImpl* bufferResource = static_cast<BufferResourceImpl*>(bufferIn);
- ID3D11Buffer* buffer = (bufferResource->m_mapFlavor == MapFlavor::HostRead) ? bufferResource->m_staging : bufferResource->m_buffer;
- m_immediateContext->Unmap(buffer, 0);
-}
-
-void D3D11Renderer::setInputLayout(InputLayout* inputLayoutIn)
-{
- auto inputLayout = static_cast<InputLayoutImpl*>(inputLayoutIn);
- m_immediateContext->IASetInputLayout(inputLayout->m_layout);
-}
-
-void D3D11Renderer::setPrimitiveTopology(PrimitiveTopology topology)
-{
- m_immediateContext->IASetPrimitiveTopology(D3DUtil::getPrimitiveTopology(topology));
-}
-
-void D3D11Renderer::setVertexBuffers(UInt startSlot, UInt slotCount, BufferResource*const* buffersIn, const UInt* stridesIn, const UInt* offsetsIn)
-{
- static const int kMaxVertexBuffers = 16;
- assert(slotCount <= kMaxVertexBuffers);
-
- UINT vertexStrides[kMaxVertexBuffers];
- UINT vertexOffsets[kMaxVertexBuffers];
- ID3D11Buffer* dxBuffers[kMaxVertexBuffers];
-
- auto buffers = (BufferResourceImpl*const*)buffersIn;
-
- for (UInt ii = 0; ii < slotCount; ++ii)
- {
- vertexStrides[ii] = (UINT)stridesIn[ii];
- vertexOffsets[ii] = (UINT)offsetsIn[ii];
- dxBuffers[ii] = buffers[ii]->m_buffer;
- }
-
- m_immediateContext->IASetVertexBuffers((UINT)startSlot, (UINT)slotCount, dxBuffers, &vertexStrides[0], &vertexOffsets[0]);
-}
-
-void D3D11Renderer::setShaderProgram(ShaderProgram* programIn)
-{
- auto program = (ShaderProgramImpl*)programIn;
- m_immediateContext->CSSetShader(program->m_computeShader, nullptr, 0);
- m_immediateContext->VSSetShader(program->m_vertexShader, nullptr, 0);
- m_immediateContext->PSSetShader(program->m_pixelShader, nullptr, 0);
-}
-
-void D3D11Renderer::draw(UInt vertexCount, UInt startVertex)
-{
- _applyBindingState(false);
- m_immediateContext->Draw((UINT)vertexCount, (UINT)startVertex);
-}
-
-ShaderProgram* D3D11Renderer::createProgram(const ShaderProgram::Desc& desc)
-{
- if (desc.pipelineType == PipelineType::Compute)
- {
- auto computeKernel = desc.findKernel(StageType::Compute);
-
- ComPtr<ID3D11ComputeShader> computeShader;
- SLANG_RETURN_NULL_ON_FAIL(m_device->CreateComputeShader(computeKernel->codeBegin, computeKernel->getCodeSize(), nullptr, computeShader.writeRef()));
-
- ShaderProgramImpl* shaderProgram = new ShaderProgramImpl();
- shaderProgram->m_computeShader.swap(computeShader);
- return shaderProgram;
- }
- else
- {
- auto vertexKernel = desc.findKernel(StageType::Vertex);
- auto fragmentKernel = desc.findKernel(StageType::Fragment);
-
- ComPtr<ID3D11VertexShader> vertexShader;
- ComPtr<ID3D11PixelShader> pixelShader;
-
- SLANG_RETURN_NULL_ON_FAIL(m_device->CreateVertexShader(vertexKernel->codeBegin, vertexKernel->getCodeSize(), nullptr, vertexShader.writeRef()));
- SLANG_RETURN_NULL_ON_FAIL(m_device->CreatePixelShader(fragmentKernel->codeBegin, fragmentKernel->getCodeSize(), nullptr, pixelShader.writeRef()));
-
- ShaderProgramImpl* shaderProgram = new ShaderProgramImpl();
- shaderProgram->m_vertexShader.swap(vertexShader);
- shaderProgram->m_pixelShader.swap(pixelShader);
- return shaderProgram;
- }
-}
-
-void D3D11Renderer::dispatchCompute(int x, int y, int z)
-{
- _applyBindingState(true);
- m_immediateContext->Dispatch(x, y, z);
-}
-
-BindingState* D3D11Renderer::createBindingState(const BindingState::Desc& bindingStateDesc)
-{
- RefPtr<BindingStateImpl> bindingState(new BindingStateImpl(bindingStateDesc));
-
- const auto& srcBindings = bindingStateDesc.m_bindings;
- const int numBindings = int(srcBindings.Count());
-
- auto& dstDetails = bindingState->m_bindingDetails;
- dstDetails.SetSize(numBindings);
-
- for (int i = 0; i < numBindings; ++i)
- {
- auto& dstDetail = dstDetails[i];
- const auto& srcBinding = srcBindings[i];
-
- assert(srcBinding.registerRange.isSingle());
-
- switch (srcBinding.bindingType)
- {
- case BindingType::Buffer:
- {
- assert(srcBinding.resource && srcBinding.resource->isBuffer());
-
- BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(srcBinding.resource.Ptr());
- const BufferResource::Desc& bufferDesc = buffer->getDesc();
-
- const int elemSize = bufferDesc.elementSize <= 0 ? 1 : bufferDesc.elementSize;
-
- if (bufferDesc.bindFlags & Resource::BindFlag::UnorderedAccess)
- {
- D3D11_UNORDERED_ACCESS_VIEW_DESC viewDesc;
- memset(&viewDesc, 0, sizeof(viewDesc));
- viewDesc.Buffer.FirstElement = 0;
- viewDesc.Buffer.NumElements = (UINT)(bufferDesc.sizeInBytes / elemSize);
- viewDesc.Buffer.Flags = 0;
- viewDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
- viewDesc.Format = D3DUtil::getMapFormat(bufferDesc.format);
-
- if (bufferDesc.elementSize == 0 && bufferDesc.format == Format::Unknown)
- {
- viewDesc.Buffer.Flags |= D3D11_BUFFER_UAV_FLAG_RAW;
- viewDesc.Format = DXGI_FORMAT_R32_TYPELESS;
- }
-
- SLANG_RETURN_NULL_ON_FAIL(m_device->CreateUnorderedAccessView(buffer->m_buffer, &viewDesc, dstDetail.m_uav.writeRef()));
- }
- if (bufferDesc.bindFlags & (Resource::BindFlag::NonPixelShaderResource | Resource::BindFlag::PixelShaderResource))
- {
- D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc;
- memset(&viewDesc, 0, sizeof(viewDesc));
- viewDesc.Buffer.FirstElement = 0;
- viewDesc.Buffer.ElementWidth = elemSize;
- viewDesc.Buffer.NumElements = (UINT)(bufferDesc.sizeInBytes / elemSize);
- viewDesc.Buffer.ElementOffset = 0;
- viewDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
- viewDesc.Format = DXGI_FORMAT_UNKNOWN;
-
- if (bufferDesc.elementSize == 0)
- {
- viewDesc.Format = DXGI_FORMAT_R32_FLOAT;
- }
-
- SLANG_RETURN_NULL_ON_FAIL(m_device->CreateShaderResourceView(buffer->m_buffer, &viewDesc, dstDetail.m_srv.writeRef()));
- }
- break;
- }
- case BindingType::Texture:
- case BindingType::CombinedTextureSampler:
- {
- assert(srcBinding.resource && srcBinding.resource->isTexture());
-
- TextureResourceImpl* texture = static_cast<TextureResourceImpl*>(srcBinding.resource.Ptr());
-
- const TextureResource::Desc& textureDesc = texture->getDesc();
-
- D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc;
- viewDesc.Format = D3DUtil::getMapFormat(textureDesc.format);
-
- switch (texture->getType())
- {
- case Resource::Type::Texture1D:
- {
- if (textureDesc.arraySize <= 0)
- {
- viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D;
- viewDesc.Texture1D.MipLevels = textureDesc.numMipLevels;
- viewDesc.Texture1D.MostDetailedMip = 0;
- }
- else
- {
- viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1DARRAY;
- viewDesc.Texture1DArray.ArraySize = textureDesc.arraySize;
- viewDesc.Texture1DArray.FirstArraySlice = 0;
- viewDesc.Texture1DArray.MipLevels = textureDesc.numMipLevels;
- viewDesc.Texture1DArray.MostDetailedMip = 0;
- }
- break;
- }
- case Resource::Type::Texture2D:
- {
- if (textureDesc.arraySize <= 0)
- {
- viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
- viewDesc.Texture2D.MipLevels = textureDesc.numMipLevels;
- viewDesc.Texture2D.MostDetailedMip = 0;
- }
- else
- {
- viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
- viewDesc.Texture2DArray.ArraySize = textureDesc.arraySize;
- viewDesc.Texture2DArray.FirstArraySlice = 0;
- viewDesc.Texture2DArray.MipLevels = textureDesc.numMipLevels;
- viewDesc.Texture2DArray.MostDetailedMip = 0;
- }
- break;
- }
- case Resource::Type::TextureCube:
- {
- if (textureDesc.arraySize <= 0)
- {
- viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
- viewDesc.TextureCube.MipLevels = textureDesc.numMipLevels;
- viewDesc.TextureCube.MostDetailedMip = 0;
- }
- else
- {
- viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBEARRAY;
- viewDesc.TextureCubeArray.MipLevels = textureDesc.numMipLevels;
- viewDesc.TextureCubeArray.MostDetailedMip = 0;
- viewDesc.TextureCubeArray.First2DArrayFace = 0;
- viewDesc.TextureCubeArray.NumCubes = textureDesc.arraySize;
- }
- break;
- }
- case Resource::Type::Texture3D:
- {
- viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
- viewDesc.Texture3D.MipLevels = textureDesc.numMipLevels; // Old code fixed as one
- viewDesc.Texture3D.MostDetailedMip = 0;
- break;
- }
- default:
- {
- assert(!"Unhandled type");
- return nullptr;
- }
- }
-
- SLANG_RETURN_NULL_ON_FAIL(m_device->CreateShaderResourceView(texture->m_resource, &viewDesc, dstDetail.m_srv.writeRef()));
- break;
- }
- case BindingType::Sampler:
- {
- const BindingState::SamplerDesc& samplerDesc = bindingStateDesc.m_samplerDescs[srcBinding.descIndex];
-
- D3D11_SAMPLER_DESC desc = {};
- desc.AddressU = desc.AddressV = desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
-
- if (samplerDesc.isCompareSampler)
- {
- desc.ComparisonFunc = D3D11_COMPARISON_LESS_EQUAL;
- desc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT;
- desc.MinLOD = desc.MaxLOD = 0.0f;
- }
- else
- {
- desc.Filter = D3D11_FILTER_ANISOTROPIC;
- desc.MaxAnisotropy = 8;
- desc.MinLOD = 0.0f;
- desc.MaxLOD = 100.0f;
- }
- SLANG_RETURN_NULL_ON_FAIL(m_device->CreateSamplerState(&desc, dstDetail.m_samplerState.writeRef()));
- break;
- }
- default:
- {
- assert(!"Unhandled type");
- return nullptr;
- }
- }
- }
-
- // Done
- return bindingState.detach();
-}
-
-void D3D11Renderer::_applyBindingState(bool isCompute)
-{
- auto context = m_immediateContext.get();
-
- const auto& details = m_currentBindings->m_bindingDetails;
- const auto& bindings = m_currentBindings->getDesc().m_bindings;
-
- const int numBindings = int(bindings.Count());
-
- for (int i = 0; i < numBindings; ++i)
- {
- const auto& binding = bindings[i];
- const auto& detail = details[i];
-
- const int bindingIndex = binding.registerRange.getSingleIndex();
-
- switch (binding.bindingType)
- {
- case BindingType::Buffer:
- {
- assert(binding.resource && binding.resource->isBuffer());
- if (binding.resource->canBind(Resource::BindFlag::ConstantBuffer))
- {
- ID3D11Buffer* buffer = static_cast<BufferResourceImpl*>(binding.resource.Ptr())->m_buffer;
- if (isCompute)
- context->CSSetConstantBuffers(bindingIndex, 1, &buffer);
- else
- {
- context->VSSetConstantBuffers(bindingIndex, 1, &buffer);
- context->PSSetConstantBuffers(bindingIndex, 1, &buffer);
- }
- }
- else if (detail.m_uav)
- {
- if (isCompute)
- context->CSSetUnorderedAccessViews(bindingIndex, 1, detail.m_uav.readRef(), nullptr);
- else
- context->OMSetRenderTargetsAndUnorderedAccessViews(m_currentBindings->getDesc().m_numRenderTargets,
- m_renderTargetViews.Buffer()->readRef(), nullptr, bindingIndex, 1, detail.m_uav.readRef(), nullptr);
- }
- else
- {
- if (isCompute)
- context->CSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef());
- else
- {
- context->PSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef());
- context->VSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef());
- }
- }
- break;
- }
- case BindingType::Texture:
- {
- if (detail.m_uav)
- {
- if (isCompute)
- context->CSSetUnorderedAccessViews(bindingIndex, 1, detail.m_uav.readRef(), nullptr);
- else
- context->OMSetRenderTargetsAndUnorderedAccessViews(D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL,
- nullptr, nullptr, bindingIndex, 1, detail.m_uav.readRef(), nullptr);
- }
- else
- {
- if (isCompute)
- context->CSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef());
- else
- {
- context->PSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef());
- context->VSSetShaderResources(bindingIndex, 1, detail.m_srv.readRef());
- }
- }
- break;
- }
- case BindingType::Sampler:
- {
- if (isCompute)
- context->CSSetSamplers(bindingIndex, 1, detail.m_samplerState.readRef());
- else
- {
- context->PSSetSamplers(bindingIndex, 1, detail.m_samplerState.readRef());
- context->VSSetSamplers(bindingIndex, 1, detail.m_samplerState.readRef());
- }
- break;
- }
- default:
- {
- assert(!"Not implemented");
- return;
- }
- }
- }
-}
-
-void D3D11Renderer::setBindingState(BindingState* state)
-{
- m_currentBindings = static_cast<BindingStateImpl*>(state);
-}
-
-} // renderer_test