diff --git a/Bin/PAKBuilder.exe b/Bin/PAKBuilder.exe
index f8819ab..42353fe 100644
Binary files a/Bin/PAKBuilder.exe and b/Bin/PAKBuilder.exe differ
diff --git a/Bin/TextureTool.exe b/Bin/TextureTool.exe
index 04ea193..09ded03 100644
Binary files a/Bin/TextureTool.exe and b/Bin/TextureTool.exe differ
diff --git a/HelloTexturedCube/HelloTexturedCube.vcxproj b/HelloTexturedCube/HelloTexturedCube.vcxproj
index f363c2a..e0896e5 100644
--- a/HelloTexturedCube/HelloTexturedCube.vcxproj
+++ b/HelloTexturedCube/HelloTexturedCube.vcxproj
@@ -28,6 +28,9 @@
+
+ {8269dcce-e226-46e4-b9f6-290ab5df2678}
+
{53923514-84b2-4b78-889a-8709c6bfa3a5}
diff --git a/HelloTexturedCube/src/HelloTexturedCubeGame.cpp b/HelloTexturedCube/src/HelloTexturedCubeGame.cpp
index 8f5c0c0..62bf501 100644
--- a/HelloTexturedCube/src/HelloTexturedCubeGame.cpp
+++ b/HelloTexturedCube/src/HelloTexturedCubeGame.cpp
@@ -126,6 +126,9 @@ void HelloTexturedCubeGame::BaseGame_Draw()
VERUS_QREF_RENDERER;
VERUS_QREF_TIMER;
+ // If swap chain is used, then at some point an image must be acquired from this swap chain:
+ renderer.AcquireSwapChainImage();
+
if (!_csh.IsSet() && _tex->IsLoaded())
_csh = _shader->BindDescriptorSetTextures(1, { _tex });
diff --git a/HelloTexturedCube/src/HelloTexturedCubeShader.hlsl b/HelloTexturedCube/src/HelloTexturedCubeShader.hlsl
index 883fa68..e4f0d37 100644
--- a/HelloTexturedCube/src/HelloTexturedCubeShader.hlsl
+++ b/HelloTexturedCube/src/HelloTexturedCubeShader.hlsl
@@ -11,6 +11,14 @@
# define VK_LOCATION_COLOR0
#endif
+#ifdef _DIRECT3D11
+# define CBUFFER(set, type, name) cbuffer type : register(b##set) { type name; }
+# define REG(slot, space, sm50slot) register(sm50slot)
+#else
+# define CBUFFER(set, type, name) ConstantBuffer name : register(b0, space##set);
+# define REG(slot, space, sm50slot) register(slot, space)
+#endif
+
VERUS_UBUFFER UB_ShaderVS
{
mataff _matW;
@@ -22,11 +30,11 @@ VERUS_UBUFFER UB_ShaderFS
float _phase;
};
-ConstantBuffer g_ubShaderVS : register(b0, space0);
-ConstantBuffer g_ubShaderFS : register(b0, space1);
+CBUFFER(0, UB_ShaderVS, g_ubShaderVS)
+CBUFFER(1, UB_ShaderFS, g_ubShaderFS)
-Texture2D g_tex : register(t1, space1);
-SamplerState g_sam : register(s1, space1);
+Texture2D g_tex : REG(t1, space1, t0);
+SamplerState g_sam : REG(s1, space1, s0);
struct VSI
{
diff --git a/HelloTriangle/HelloTriangle.vcxproj b/HelloTriangle/HelloTriangle.vcxproj
index 74f530d..38b5e84 100644
--- a/HelloTriangle/HelloTriangle.vcxproj
+++ b/HelloTriangle/HelloTriangle.vcxproj
@@ -23,6 +23,9 @@
+
+ {8269dcce-e226-46e4-b9f6-290ab5df2678}
+
{53923514-84b2-4b78-889a-8709c6bfa3a5}
diff --git a/HelloTriangle/src/HelloTriangleGame.cpp b/HelloTriangle/src/HelloTriangleGame.cpp
index 1ef0420..40285cf 100644
--- a/HelloTriangle/src/HelloTriangleGame.cpp
+++ b/HelloTriangle/src/HelloTriangleGame.cpp
@@ -95,6 +95,9 @@ void HelloTriangleGame::BaseGame_Draw()
VERUS_QREF_RENDERER;
VERUS_QREF_TIMER;
+ // If swap chain is used, then at some point an image must be acquired from this swap chain:
+ renderer.AcquireSwapChainImage();
+
//ImGui::Text("HelloTriangle");
auto cb = renderer.GetCommandBuffer(); // Default command buffer for this frame.
diff --git a/HelloTriangle/src/HelloTriangleShader.hlsl b/HelloTriangle/src/HelloTriangleShader.hlsl
index feb60e0..f263f66 100644
--- a/HelloTriangle/src/HelloTriangleShader.hlsl
+++ b/HelloTriangle/src/HelloTriangleShader.hlsl
@@ -12,6 +12,14 @@ R"(
# define VK_LOCATION_COLOR0
#endif
+#ifdef _DIRECT3D11
+# define CBUFFER(set, type, name) cbuffer type : register(b##set) { type name; }
+# define REG(slot, space, sm50slot) register(sm50slot)
+#else
+# define CBUFFER(set, type, name) ConstantBuffer name : register(b0, space##set);
+# define REG(slot, space, sm50slot) register(slot, space)
+#endif
+
VERUS_UBUFFER UB_ShaderVS
{
matrix _matWVP;
@@ -22,8 +30,8 @@ VERUS_UBUFFER UB_ShaderFS
float _phase;
};
-ConstantBuffer g_ubShaderVS : register(b0, space0);
-ConstantBuffer g_ubShaderFS : register(b0, space1);
+CBUFFER(0, UB_ShaderVS, g_ubShaderVS)
+CBUFFER(1, UB_ShaderFS, g_ubShaderFS)
struct VSI
{
diff --git a/README.md b/README.md
index db3b57a..af88ba3 100644
--- a/README.md
+++ b/README.md
@@ -3,15 +3,16 @@
# Verus Engine
## What is Verus Engine?
-Verus Engine is a modern, platform-agnostic 3D game engine. It is developed using **C++** and **HLSL**. It is based on **Direct3D 12** and **Vulkan** graphics APIs. The code is user friendly and well optimized. The engine is intended to be a full-featured solution for making games. It includes modules to handle input, audio, networking and other things. Hence there is no need to search for third-party libraries or write custom code.
+Verus Engine is a modern, platform-agnostic 3D game engine. It is developed using **C++** and **HLSL**. It is based on **Vulkan** and **Direct3D 12** graphics APIs. The code is user friendly and well optimized. The engine is intended to be a full-featured solution for making games. It includes modules to handle input, audio, networking and other things. Hence there is no need to search for third-party libraries or write custom code.
## Supported systems
-* **Windows 10**, 8, 8.1 *(via Vulkan renderer)*
+* **Windows 10**, 8.1, 8, 7 *(via Vulkan and Direct3D 11 renderers)*
* **64-bit only**, 32-bit is not supported
## Supported graphics libraries
-* Vulkan
-* Direct3D 12
+* Vulkan 1.1
+* Direct3D 11 *(Shader Model 5.0)*
+* Direct3D 12 *(Shader Model 5.1)*
## Features
* Native cross-platform code
@@ -41,6 +42,7 @@ These features should be implemented in version **1.x**:
- [x] glTF file format support
- [x] Materials v2.0: PBR/GGX with Metallic-Roughness workflow
+- [x] Direct3D 11
- [ ] Shadow maps for all lights
- [ ] Triggers
- [ ] Quest system, dialogue system
diff --git a/RendererDirect3D11/RendererDirect3D11.vcxproj b/RendererDirect3D11/RendererDirect3D11.vcxproj
new file mode 100644
index 0000000..b8756d0
--- /dev/null
+++ b/RendererDirect3D11/RendererDirect3D11.vcxproj
@@ -0,0 +1,132 @@
+
+
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {8269dcce-e226-46e4-b9f6-290ab5df2678}
+ RendererDirect3D11
+ 10.0.20348.0
+
+
+
+ DynamicLibrary
+ true
+ v142
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ false
+
+
+
+ Level3
+ true
+ _DEBUG;RENDERERDIRECT3D11_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+ Fast
+ $(ProjectDir)src;%(AdditionalIncludeDirectories)
+
+
+ Windows
+ true
+ false
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;RENDERERDIRECT3D11_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+ Fast
+ $(ProjectDir)src;%(AdditionalIncludeDirectories)
+
+
+ Windows
+ true
+ true
+ true
+ false
+
+
+
+
+ {b154d670-e4b1-4d8a-885c-69546a5bd833}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Create
+ Create
+
+
+ NotUsing
+ NotUsing
+
+
+
+
+
+
\ No newline at end of file
diff --git a/RendererDirect3D11/RendererDirect3D11.vcxproj.filters b/RendererDirect3D11/RendererDirect3D11.vcxproj.filters
new file mode 100644
index 0000000..59ae10d
--- /dev/null
+++ b/RendererDirect3D11/RendererDirect3D11.vcxproj.filters
@@ -0,0 +1,99 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {dbb9012f-6f9f-4ce5-b70c-1f656c01194c}
+
+
+ {4383f8f9-69c0-46d9-8fa3-36fb4a0f14a6}
+
+
+ {4bc40ebd-8358-46b3-a398-ad110d56b0d5}
+
+
+ {76aa8120-363f-4e19-88f7-f297c5101755}
+
+
+
+
+ src
+
+
+ src\CGI
+
+
+ src\CGI
+
+
+ src\CGI
+
+
+ src\CGI
+
+
+ src\CGI
+
+
+ src\CGI
+
+
+ src\CGI
+
+
+ src\CGI
+
+
+ src\ThirdParty\imgui
+
+
+ src\CGI
+
+
+
+
+ src
+
+
+ src
+
+
+ src\CGI
+
+
+ src\CGI
+
+
+ src\CGI
+
+
+ src\CGI
+
+
+ src\CGI
+
+
+ src\CGI
+
+
+ src\CGI
+
+
+ src\ThirdParty\imgui
+
+
+ src\CGI
+
+
+
\ No newline at end of file
diff --git a/RendererDirect3D11/src/CGI/CGI.h b/RendererDirect3D11/src/CGI/CGI.h
new file mode 100644
index 0000000..d6f4025
--- /dev/null
+++ b/RendererDirect3D11/src/CGI/CGI.h
@@ -0,0 +1,27 @@
+// Copyright (C) 2021-2022, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
+#pragma once
+
+#define VERUS_ENABLE_COM_RELEASE_CHECK
+#ifdef VERUS_ENABLE_COM_RELEASE_CHECK
+# define VERUS_COM_RELEASE_CHECK(p) {if(p) {const ULONG count = p->AddRef(); p->Release(); VERUS_RT_ASSERT(2 == count);}}
+#else
+# define VERUS_COM_RELEASE_CHECK(p) {}
+#endif
+
+namespace verus
+{
+ inline void SetDebugObjectName(ID3D11DeviceChild* p, CSZ name)
+ {
+ if (p)
+ p->SetPrivateData(WKPDID_D3DDebugObjectName, static_cast(strlen(name)), name);
+ }
+}
+
+#include "Native.h"
+#include "RenderPass.h"
+#include "GeometryD3D11.h"
+#include "TextureD3D11.h"
+#include "ShaderD3D11.h"
+#include "PipelineD3D11.h"
+#include "CommandBufferD3D11.h"
+#include "RendererD3D11.h"
diff --git a/RendererDirect3D11/src/CGI/CommandBufferD3D11.cpp b/RendererDirect3D11/src/CGI/CommandBufferD3D11.cpp
new file mode 100644
index 0000000..21391ba
--- /dev/null
+++ b/RendererDirect3D11/src/CGI/CommandBufferD3D11.cpp
@@ -0,0 +1,339 @@
+// Copyright (C) 2021-2022, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
+#include "pch.h"
+
+using namespace verus;
+using namespace verus::CGI;
+
+CommandBufferD3D11::CommandBufferD3D11()
+{
+ VERUS_ZERO_MEM(_blendFactor);
+}
+
+CommandBufferD3D11::~CommandBufferD3D11()
+{
+ Done();
+}
+
+void CommandBufferD3D11::Init()
+{
+ VERUS_INIT();
+ VERUS_QREF_RENDERER_D3D11;
+
+ _vClearValues.reserve(16);
+ _pDeviceContext = pRendererD3D11->GetD3DDeviceContext();
+}
+
+void CommandBufferD3D11::Done()
+{
+ _pDeviceContext.Reset();
+
+ VERUS_DONE(CommandBufferD3D11);
+}
+
+void CommandBufferD3D11::InitOneTimeSubmit()
+{
+ Init();
+}
+
+void CommandBufferD3D11::DoneOneTimeSubmit()
+{
+ Done();
+}
+
+void CommandBufferD3D11::Begin()
+{
+}
+
+void CommandBufferD3D11::End()
+{
+}
+
+void CommandBufferD3D11::PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout oldLayout, ImageLayout newLayout, Range mipLevels, Range arrayLayers)
+{
+}
+
+void CommandBufferD3D11::BeginRenderPass(RPHandle renderPassHandle, FBHandle framebufferHandle, std::initializer_list ilClearValues, bool setViewportAndScissor)
+{
+ VERUS_QREF_RENDERER_D3D11;
+
+ _pRenderPass = &pRendererD3D11->GetRenderPass(renderPassHandle);
+ _pFramebuffer = &pRendererD3D11->GetFramebuffer(framebufferHandle);
+
+ VERUS_RT_ASSERT(_pRenderPass->_vAttachments.size() == ilClearValues.size());
+
+ _vClearValues.clear();
+ for (const auto& x : ilClearValues)
+ {
+ auto pColor = x.ToPointer();
+ _vClearValues.push_back(pColor[0]);
+ _vClearValues.push_back(pColor[1]);
+ _vClearValues.push_back(pColor[2]);
+ _vClearValues.push_back(pColor[3]);
+ }
+
+ _subpassIndex = 0;
+ PrepareSubpass();
+
+ if (setViewportAndScissor)
+ {
+ const Vector4 rc(0, 0, static_cast(_pFramebuffer->_width), static_cast(_pFramebuffer->_height));
+ SetViewport({ rc }, 0, 1);
+ SetScissor({ rc });
+ }
+}
+
+void CommandBufferD3D11::NextSubpass()
+{
+ _subpassIndex++;
+ PrepareSubpass();
+}
+
+void CommandBufferD3D11::EndRenderPass()
+{
+ // Unbind everything:
+ _pDeviceContext->OMSetRenderTargets(0, nullptr, nullptr);
+
+ _pRenderPass = nullptr;
+ _pFramebuffer = nullptr;
+ _subpassIndex = 0;
+}
+
+void CommandBufferD3D11::BindPipeline(PipelinePtr pipe)
+{
+ auto& pipeD3D11 = static_cast(*pipe);
+ if (pipeD3D11.IsCompute())
+ {
+ _pDeviceContext->CSSetShader(pipeD3D11.GetD3DCS(), nullptr, 0);
+ }
+ else
+ {
+ _pDeviceContext->VSSetShader(pipeD3D11.GetD3DVS(), nullptr, 0);
+ _pDeviceContext->HSSetShader(pipeD3D11.GetD3DHS(), nullptr, 0);
+ _pDeviceContext->DSSetShader(pipeD3D11.GetD3DDS(), nullptr, 0);
+ _pDeviceContext->GSSetShader(pipeD3D11.GetD3DGS(), nullptr, 0);
+ _pDeviceContext->PSSetShader(pipeD3D11.GetD3DPS(), nullptr, 0);
+ _pDeviceContext->OMSetBlendState(pipeD3D11.GetD3DBlendState(), _blendFactor, pipeD3D11.GetSampleMask());
+ _pDeviceContext->RSSetState(pipeD3D11.GetD3DRasterizerState());
+ _pDeviceContext->OMSetDepthStencilState(pipeD3D11.GetD3DDepthStencilState(), pipeD3D11.GetStencilRef());
+ _pDeviceContext->IASetInputLayout(pipeD3D11.GetD3DInputLayout());
+ _pDeviceContext->IASetPrimitiveTopology(pipeD3D11.GetD3DPrimitiveTopology());
+ }
+}
+
+void CommandBufferD3D11::SetViewport(std::initializer_list il, float minDepth, float maxDepth)
+{
+ if (il.size() > 0)
+ {
+ const float w = il.begin()->Width();
+ const float h = il.begin()->Height();
+ _viewportSize = Vector4(w, h, 1 / w, 1 / h);
+ }
+
+ VERUS_RT_ASSERT(il.size() <= VERUS_MAX_CA);
+ D3D11_VIEWPORT vpD3D11[VERUS_MAX_CA];
+ UINT count = 0;
+ for (const auto& rc : il)
+ {
+ vpD3D11[count].TopLeftX = rc.getX();
+ vpD3D11[count].TopLeftY = rc.getY();
+ vpD3D11[count].Width = rc.Width();
+ vpD3D11[count].Height = rc.Height();
+ vpD3D11[count].MinDepth = minDepth;
+ vpD3D11[count].MaxDepth = maxDepth;
+ count++;
+ }
+ _pDeviceContext->RSSetViewports(count, vpD3D11);
+}
+
+void CommandBufferD3D11::SetScissor(std::initializer_list il)
+{
+ VERUS_RT_ASSERT(il.size() <= VERUS_MAX_CA);
+ D3D11_RECT rcD3D11[VERUS_MAX_CA];
+ UINT count = 0;
+ for (const auto& rc : il)
+ rcD3D11[count++] = CD3D11_RECT(
+ static_cast(rc.getX()),
+ static_cast(rc.getY()),
+ static_cast(rc.getZ()),
+ static_cast(rc.getW()));
+ _pDeviceContext->RSSetScissorRects(count, rcD3D11);
+}
+
+void CommandBufferD3D11::SetBlendConstants(const float* p)
+{
+ memcpy(_blendFactor, p, 4 * sizeof(float));
+}
+
+void CommandBufferD3D11::BindVertexBuffers(GeometryPtr geo, UINT32 bindingsFilter)
+{
+ auto& geoD3D11 = static_cast(*geo);
+ ID3D11Buffer* buffers[VERUS_MAX_VB];
+ UINT strides[VERUS_MAX_VB];
+ UINT offsets[VERUS_MAX_VB];
+ const int count = geoD3D11.GetVertexBufferCount();
+ int filteredCount = 0;
+ VERUS_FOR(i, count)
+ {
+ if ((bindingsFilter >> i) & 0x1)
+ {
+ VERUS_RT_ASSERT(filteredCount < VERUS_MAX_VB);
+ buffers[filteredCount] = geoD3D11.GetD3DVertexBuffer(i);
+ strides[filteredCount] = geoD3D11.GetStride(i);
+ offsets[filteredCount] = 0;
+ filteredCount++;
+ }
+ }
+ _pDeviceContext->IASetVertexBuffers(0, filteredCount, buffers, strides, offsets);
+}
+
+void CommandBufferD3D11::BindIndexBuffer(GeometryPtr geo)
+{
+ auto& geoD3D11 = static_cast(*geo);
+ _pDeviceContext->IASetIndexBuffer(geoD3D11.GetD3DIndexBuffer(), geoD3D11.Has32BitIndices() ? DXGI_FORMAT_R32_UINT : DXGI_FORMAT_R16_UINT, 0);
+}
+
+bool CommandBufferD3D11::BindDescriptors(ShaderPtr shader, int setNumber, CSHandle complexSetHandle)
+{
+ auto& shaderD3D11 = static_cast(*shader);
+
+ ShaderStageFlags stageFlags;
+ ShaderResources shaderResources;
+ ID3D11Buffer* pBuffer = shaderD3D11.UpdateUniformBuffer(setNumber, stageFlags);
+ if (complexSetHandle.IsSet())
+ {
+ shaderD3D11.GetShaderResources(setNumber, complexSetHandle.Get(), shaderResources);
+ shaderD3D11.GetSamplers(setNumber, complexSetHandle.Get(), shaderResources);
+ }
+
+ if (stageFlags & ShaderStageFlags::vs)
+ {
+ _pDeviceContext->VSSetConstantBuffers(setNumber, 1, &pBuffer);
+ if (shaderResources._srvCount)
+ {
+ _pDeviceContext->VSSetShaderResources(shaderResources._srvStartSlot, shaderResources._srvCount, shaderResources._srvs);
+ _pDeviceContext->VSSetSamplers(shaderResources._srvStartSlot, shaderResources._srvCount, shaderResources._samplers);
+ }
+ }
+ if (stageFlags & ShaderStageFlags::hs)
+ {
+ _pDeviceContext->HSSetConstantBuffers(setNumber, 1, &pBuffer);
+ if (shaderResources._srvCount)
+ {
+ _pDeviceContext->HSSetShaderResources(shaderResources._srvStartSlot, shaderResources._srvCount, shaderResources._srvs);
+ _pDeviceContext->HSSetSamplers(shaderResources._srvStartSlot, shaderResources._srvCount, shaderResources._samplers);
+ }
+ }
+ if (stageFlags & ShaderStageFlags::ds)
+ {
+ _pDeviceContext->DSSetConstantBuffers(setNumber, 1, &pBuffer);
+ if (shaderResources._srvCount)
+ {
+ _pDeviceContext->DSSetShaderResources(shaderResources._srvStartSlot, shaderResources._srvCount, shaderResources._srvs);
+ _pDeviceContext->DSSetSamplers(shaderResources._srvStartSlot, shaderResources._srvCount, shaderResources._samplers);
+ }
+ }
+ if (stageFlags & ShaderStageFlags::gs)
+ {
+ _pDeviceContext->GSSetConstantBuffers(setNumber, 1, &pBuffer);
+ if (shaderResources._srvCount)
+ {
+ _pDeviceContext->GSSetShaderResources(shaderResources._srvStartSlot, shaderResources._srvCount, shaderResources._srvs);
+ _pDeviceContext->GSSetSamplers(shaderResources._srvStartSlot, shaderResources._srvCount, shaderResources._samplers);
+ }
+ }
+ if (stageFlags & ShaderStageFlags::fs)
+ {
+ _pDeviceContext->PSSetConstantBuffers(setNumber, 1, &pBuffer);
+ if (shaderResources._srvCount)
+ {
+ _pDeviceContext->PSSetShaderResources(shaderResources._srvStartSlot, shaderResources._srvCount, shaderResources._srvs);
+ _pDeviceContext->PSSetSamplers(shaderResources._srvStartSlot, shaderResources._srvCount, shaderResources._samplers);
+ }
+ }
+ if (stageFlags & ShaderStageFlags::cs)
+ {
+ _pDeviceContext->CSSetConstantBuffers(setNumber, 1, &pBuffer);
+ if (shaderResources._srvCount)
+ {
+ _pDeviceContext->CSSetShaderResources(shaderResources._srvStartSlot, shaderResources._srvCount, shaderResources._srvs);
+ _pDeviceContext->CSSetSamplers(shaderResources._srvStartSlot, shaderResources._srvCount, shaderResources._samplers);
+ }
+ if (shaderResources._uavCount)
+ _pDeviceContext->CSSetUnorderedAccessViews(shaderResources._uavStartSlot, shaderResources._uavCount, shaderResources._uavs, nullptr);
+ }
+
+ return true;
+}
+
+void CommandBufferD3D11::PushConstants(ShaderPtr shader, int offset, int size, const void* p, ShaderStageFlags stageFlags)
+{
+}
+
+void CommandBufferD3D11::Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance)
+{
+ _pDeviceContext->DrawInstanced(vertexCount, instanceCount, firstVertex, firstInstance);
+}
+
+void CommandBufferD3D11::DrawIndexed(int indexCount, int instanceCount, int firstIndex, int vertexOffset, int firstInstance)
+{
+ _pDeviceContext->DrawIndexedInstanced(indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
+}
+
+void CommandBufferD3D11::Dispatch(int groupCountX, int groupCountY, int groupCountZ)
+{
+ _pDeviceContext->Dispatch(groupCountX, groupCountY, groupCountZ);
+}
+
+void CommandBufferD3D11::DispatchMesh(int groupCountX, int groupCountY, int groupCountZ)
+{
+}
+
+void CommandBufferD3D11::TraceRays(int width, int height, int depth)
+{
+}
+
+ID3D11DeviceContext* CommandBufferD3D11::GetD3DDeviceContext() const
+{
+ return _pDeviceContext.Get();
+}
+
+void CommandBufferD3D11::PrepareSubpass()
+{
+ RP::RcD3DSubpass subpass = _pRenderPass->_vSubpasses[_subpassIndex];
+ RP::RcD3DFramebufferSubpass fs = _pFramebuffer->_vSubpasses[_subpassIndex];
+
+ // Clear attachments for this subpass:
+ int index = 0;
+ for (const auto& ref : subpass._vColor)
+ {
+ const auto& attachment = _pRenderPass->_vAttachments[ref._index];
+ if (RP::Attachment::LoadOp::clear == attachment._loadOp && attachment._clearSubpassIndex == _subpassIndex)
+ _pDeviceContext->ClearRenderTargetView(fs._vRTVs[index], &_vClearValues[ref._index << 2]);
+ index++;
+ }
+ if (subpass._depthStencil._index >= 0)
+ {
+ const auto& attachment = _pRenderPass->_vAttachments[subpass._depthStencil._index];
+ if (RP::Attachment::LoadOp::clear == attachment._loadOp && attachment._clearSubpassIndex == _subpassIndex)
+ {
+ UINT clearFlags = D3D11_CLEAR_DEPTH;
+ UINT8 stencil = 0;
+ if (RP::Attachment::LoadOp::clear == attachment._stencilLoadOp)
+ {
+ clearFlags |= D3D11_CLEAR_STENCIL;
+ stencil = static_cast(_vClearValues[(subpass._depthStencil._index << 2) + 1]);
+ }
+ _pDeviceContext->ClearDepthStencilView(fs._pDSV, clearFlags, _vClearValues[subpass._depthStencil._index << 2], stencil);
+ }
+ }
+
+ ID3D11RenderTargetView* rtvs[VERUS_MAX_CA] = {};
+ const int count = Math::Min(static_cast(fs._vRTVs.size()), VERUS_MAX_CA);
+ if (!fs._vRTVs.empty())
+ memcpy(rtvs, fs._vRTVs.data(), count * sizeof(ID3D11RenderTargetView*));
+ ID3D11DepthStencilView* pDSV = fs._pDSV ? fs._pDSV : nullptr;
+ _pDeviceContext->OMSetRenderTargets(
+ Utils::Cast32(subpass._vColor.size()),
+ !fs._vRTVs.empty() ? rtvs : nullptr,
+ fs._pDSV ? pDSV : nullptr);
+}
diff --git a/RendererDirect3D11/src/CGI/CommandBufferD3D11.h b/RendererDirect3D11/src/CGI/CommandBufferD3D11.h
new file mode 100644
index 0000000..d775595
--- /dev/null
+++ b/RendererDirect3D11/src/CGI/CommandBufferD3D11.h
@@ -0,0 +1,64 @@
+// Copyright (C) 2021-2022, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
+#pragma once
+
+namespace verus
+{
+ namespace CGI
+ {
+ class CommandBufferD3D11 : public BaseCommandBuffer
+ {
+ ComPtr _pDeviceContext;
+ RP::PcD3DRenderPass _pRenderPass = nullptr;
+ RP::PcD3DFramebuffer _pFramebuffer = nullptr;
+ Vector _vClearValues;
+ int _subpassIndex = 0;
+ float _blendFactor[4];
+
+ public:
+ CommandBufferD3D11();
+ virtual ~CommandBufferD3D11() override;
+
+ virtual void Init() override;
+ virtual void Done() override;
+
+ virtual void InitOneTimeSubmit() override;
+ virtual void DoneOneTimeSubmit() override;
+
+ virtual void Begin() override;
+ virtual void End() override;
+
+ virtual void PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout oldLayout, ImageLayout newLayout, Range mipLevels, Range arrayLayers) override;
+
+ virtual void BeginRenderPass(RPHandle renderPassHandle, FBHandle framebufferHandle,
+ std::initializer_list ilClearValues, bool setViewportAndScissor) override;
+ virtual void NextSubpass() override;
+ virtual void EndRenderPass() override;
+
+ virtual void BindPipeline(PipelinePtr pipe) override;
+ virtual void SetViewport(std::initializer_list il, float minDepth, float maxDepth) override;
+ virtual void SetScissor(std::initializer_list il) override;
+ virtual void SetBlendConstants(const float* p) override;
+
+ virtual void BindVertexBuffers(GeometryPtr geo, UINT32 bindingsFilter) override;
+ virtual void BindIndexBuffer(GeometryPtr geo) override;
+
+ virtual bool BindDescriptors(ShaderPtr shader, int setNumber, CSHandle complexSetHandle) override;
+ virtual void PushConstants(ShaderPtr shader, int offset, int size, const void* p, ShaderStageFlags stageFlags) override;
+
+ virtual void Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance) override;
+ virtual void DrawIndexed(int indexCount, int instanceCount, int firstIndex, int vertexOffset, int firstInstance) override;
+ virtual void Dispatch(int groupCountX, int groupCountY, int groupCountZ) override;
+ virtual void DispatchMesh(int groupCountX, int groupCountY, int groupCountZ) override;
+ virtual void TraceRays(int width, int height, int depth) override;
+
+ //
+ // D3D11
+ //
+
+ ID3D11DeviceContext* GetD3DDeviceContext() const;
+
+ void PrepareSubpass();
+ };
+ VERUS_TYPEDEFS(CommandBufferD3D11);
+ }
+}
diff --git a/RendererDirect3D11/src/CGI/GeometryD3D11.cpp b/RendererDirect3D11/src/CGI/GeometryD3D11.cpp
new file mode 100644
index 0000000..3dc5c3e
--- /dev/null
+++ b/RendererDirect3D11/src/CGI/GeometryD3D11.cpp
@@ -0,0 +1,230 @@
+// Copyright (C) 2021-2022, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
+#include "pch.h"
+
+using namespace verus;
+using namespace verus::CGI;
+
+GeometryD3D11::GeometryD3D11()
+{
+}
+
+GeometryD3D11::~GeometryD3D11()
+{
+ Done();
+}
+
+void GeometryD3D11::Init(RcGeometryDesc desc)
+{
+ VERUS_INIT();
+
+ _name = desc._name;
+ _dynBindingsMask = desc._dynBindingsMask;
+ _32BitIndices = desc._32BitIndices;
+
+ _vInputElementDescs.reserve(GetVertexInputAttrDescCount(desc._pVertexInputAttrDesc));
+ int i = 0;
+ while (desc._pVertexInputAttrDesc[i]._offset >= 0)
+ {
+ int binding = desc._pVertexInputAttrDesc[i]._binding;
+ D3D11_INPUT_CLASSIFICATION inputClassification = D3D11_INPUT_PER_VERTEX_DATA;
+ UINT instanceDataStepRate = 0;
+ if (binding < 0)
+ {
+ binding = -binding;
+ _instBindingsMask |= (1 << binding);
+ inputClassification = D3D11_INPUT_PER_INSTANCE_DATA;
+ instanceDataStepRate = 1;
+ }
+ D3D11_INPUT_ELEMENT_DESC ieDesc =
+ {
+ ToNativeSemanticName(desc._pVertexInputAttrDesc[i]._usage),
+ static_cast(desc._pVertexInputAttrDesc[i]._usageIndex),
+ ToNativeFormat(desc._pVertexInputAttrDesc[i]._usage, desc._pVertexInputAttrDesc[i]._type, desc._pVertexInputAttrDesc[i]._components),
+ static_cast(binding),
+ static_cast(desc._pVertexInputAttrDesc[i]._offset),
+ inputClassification,
+ instanceDataStepRate
+ };
+ _vInputElementDescs.push_back(ieDesc);
+ i++;
+ }
+
+ _vStrides.reserve(GetBindingCount(desc._pVertexInputAttrDesc));
+ i = 0;
+ while (desc._pStrides[i] > 0)
+ {
+ _vStrides.push_back(desc._pStrides[i]);
+ i++;
+ }
+
+ _vVertexBuffers.reserve(4);
+}
+
+void GeometryD3D11::Done()
+{
+ ForceScheduled();
+
+ _indexBuffer._pBuffer.Reset();
+ for (auto& x : _vVertexBuffers)
+ x._pBuffer.Reset();
+ _vVertexBuffers.clear();
+
+ VERUS_DONE(GeometryD3D11);
+}
+
+void GeometryD3D11::CreateVertexBuffer(int count, int binding)
+{
+ VERUS_QREF_RENDERER_D3D11;
+ HRESULT hr = 0;
+
+ if (_vVertexBuffers.size() <= binding)
+ _vVertexBuffers.resize(binding + 1);
+
+ auto& vb = _vVertexBuffers[binding];
+ const int elementSize = _vStrides[binding];
+ vb._bufferSize = count * elementSize;
+
+ D3D11_BUFFER_DESC vbDesc = {};
+ vbDesc.ByteWidth = Utils::Cast32(vb._bufferSize);
+ vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+ if (((_instBindingsMask | _dynBindingsMask) >> binding) & 0x1)
+ {
+ vbDesc.Usage = D3D11_USAGE_DYNAMIC;
+ vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ if (FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateBuffer(&vbDesc, nullptr, &vb._pBuffer)))
+ throw VERUS_RUNTIME_ERROR << "CreateBuffer(D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_DYNAMIC), " << VERUS_HR(hr);
+ SetDebugObjectName(vb._pBuffer.Get(), _C(_name + " (Dynamic VB, " + std::to_string(binding) + ")"));
+ }
+ else
+ {
+ if (FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateBuffer(&vbDesc, nullptr, &vb._pBuffer)))
+ throw VERUS_RUNTIME_ERROR << "CreateBuffer(D3D11_BIND_VERTEX_BUFFER), " << VERUS_HR(hr);
+ SetDebugObjectName(vb._pBuffer.Get(), _C(_name + " (VB, " + std::to_string(binding) + ")"));
+ }
+}
+
+void GeometryD3D11::UpdateVertexBuffer(const void* p, int binding, PBaseCommandBuffer pCB, INT64 size, INT64 offset)
+{
+ VERUS_QREF_RENDERER;
+ HRESULT hr = 0;
+
+ if (!pCB)
+ pCB = renderer.GetCommandBuffer().Get();
+ auto pDeviceContext = static_cast(pCB)->GetD3DDeviceContext();
+
+ if (((_instBindingsMask | _dynBindingsMask) >> binding) & 0x1)
+ {
+ auto& vb = _vVertexBuffers[binding];
+ const int elementSize = _vStrides[binding];
+ size = size ? size * elementSize : vb._bufferSize;
+
+ const D3D11_MAP mapType = (size == vb._bufferSize) ? D3D11_MAP_WRITE_DISCARD : D3D11_MAP_WRITE_NO_OVERWRITE;
+ D3D11_MAPPED_SUBRESOURCE ms = {};
+ if (FAILED(hr = pDeviceContext->Map(vb._pBuffer.Get(), 0, mapType, 0, &ms)))
+ throw VERUS_RUNTIME_ERROR << "Map(); hr=" << VERUS_HR(hr);
+ BYTE* pMappedData = static_cast(ms.pData);
+ memcpy(pMappedData + offset * elementSize, p, size);
+ pDeviceContext->Unmap(vb._pBuffer.Get(), 0);
+ }
+ else
+ {
+ auto& vb = _vVertexBuffers[binding];
+ pDeviceContext->UpdateSubresource(
+ vb._pBuffer.Get(), 0, nullptr,
+ p, 0, 0);
+ }
+}
+
+void GeometryD3D11::CreateIndexBuffer(int count)
+{
+ VERUS_QREF_RENDERER_D3D11;
+ HRESULT hr = 0;
+
+ const int elementSize = _32BitIndices ? sizeof(UINT32) : sizeof(UINT16);
+ _indexBuffer._bufferSize = count * elementSize;
+
+ D3D11_BUFFER_DESC ibDesc = {};
+ ibDesc.ByteWidth = Utils::Cast32(_indexBuffer._bufferSize);
+ ibDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
+ if ((_dynBindingsMask >> 31) & 0x1)
+ {
+ ibDesc.Usage = D3D11_USAGE_DYNAMIC;
+ ibDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ if (FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateBuffer(&ibDesc, nullptr, &_indexBuffer._pBuffer)))
+ throw VERUS_RUNTIME_ERROR << "CreateBuffer(D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_DYNAMIC), " << VERUS_HR(hr);
+ SetDebugObjectName(_indexBuffer._pBuffer.Get(), _C(_name + " (Dynamic IB)"));
+ }
+ else
+ {
+ if (FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateBuffer(&ibDesc, nullptr, &_indexBuffer._pBuffer)))
+ throw VERUS_RUNTIME_ERROR << "CreateBuffer(D3D11_BIND_VERTEX_BUFFER), " << VERUS_HR(hr);
+ SetDebugObjectName(_indexBuffer._pBuffer.Get(), _C(_name + " (IB)"));
+ }
+}
+
+void GeometryD3D11::UpdateIndexBuffer(const void* p, PBaseCommandBuffer pCB, INT64 size, INT64 offset)
+{
+ VERUS_QREF_RENDERER;
+ HRESULT hr = 0;
+
+ if (!pCB)
+ pCB = renderer.GetCommandBuffer().Get();
+ auto pDeviceContext = static_cast(pCB)->GetD3DDeviceContext();
+
+ if ((_dynBindingsMask >> 31) & 0x1)
+ {
+ const int elementSize = _32BitIndices ? sizeof(UINT32) : sizeof(UINT16);
+ size = size ? size * elementSize : _indexBuffer._bufferSize;
+
+ const D3D11_MAP mapType = (size == _indexBuffer._bufferSize) ? D3D11_MAP_WRITE_DISCARD : D3D11_MAP_WRITE_NO_OVERWRITE;
+ D3D11_MAPPED_SUBRESOURCE ms = {};
+ if (FAILED(hr = pDeviceContext->Map(_indexBuffer._pBuffer.Get(), 0, mapType, 0, &ms)))
+ throw VERUS_RUNTIME_ERROR << "Map(); hr=" << VERUS_HR(hr);
+ BYTE* pMappedData = static_cast(ms.pData);
+ memcpy(pMappedData + offset * elementSize, p, size);
+ pDeviceContext->Unmap(_indexBuffer._pBuffer.Get(), 0);
+ }
+ else
+ {
+ pDeviceContext->UpdateSubresource(
+ _indexBuffer._pBuffer.Get(), 0, nullptr,
+ p, 0, 0);
+ }
+}
+
+Continue GeometryD3D11::Scheduled_Update()
+{
+ return Continue::yes;
+}
+
+void GeometryD3D11::GetD3DInputElementDescs(UINT32 bindingsFilter, Vector& vInputElementDescs) const
+{
+ UINT replaceBinding[VERUS_MAX_VB] = {}; // For bindings compaction.
+ UINT binding = 0;
+ VERUS_FOR(i, VERUS_MAX_VB)
+ {
+ replaceBinding[i] = binding;
+ if ((bindingsFilter >> i) & 0x1)
+ binding++;
+ }
+
+ vInputElementDescs.reserve(_vInputElementDescs.size());
+ for (const auto& x : _vInputElementDescs)
+ {
+ if ((bindingsFilter >> x.InputSlot) & 0x1)
+ {
+ vInputElementDescs.push_back(x);
+ vInputElementDescs.back().InputSlot = replaceBinding[x.InputSlot];
+ }
+ }
+}
+
+ID3D11Buffer* GeometryD3D11::GetD3DVertexBuffer(int binding) const
+{
+ return _vVertexBuffers[binding]._pBuffer.Get();
+}
+
+ID3D11Buffer* GeometryD3D11::GetD3DIndexBuffer() const
+{
+ return _indexBuffer._pBuffer.Get();
+}
diff --git a/RendererDirect3D11/src/CGI/GeometryD3D11.h b/RendererDirect3D11/src/CGI/GeometryD3D11.h
new file mode 100644
index 0000000..7b04917
--- /dev/null
+++ b/RendererDirect3D11/src/CGI/GeometryD3D11.h
@@ -0,0 +1,49 @@
+// Copyright (C) 2021-2022, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
+#pragma once
+
+namespace verus
+{
+ namespace CGI
+ {
+ class GeometryD3D11 : public BaseGeometry
+ {
+ struct BufferEx
+ {
+ ComPtr _pBuffer;
+ UINT64 _bufferSize = 0;
+ };
+
+ Vector _vVertexBuffers;
+ BufferEx _indexBuffer;
+ Vector _vInputElementDescs;
+ Vector _vStrides;
+
+ public:
+ GeometryD3D11();
+ virtual ~GeometryD3D11() override;
+
+ virtual void Init(RcGeometryDesc desc) override;
+ virtual void Done() override;
+
+ virtual void CreateVertexBuffer(int count, int binding) override;
+ virtual void UpdateVertexBuffer(const void* p, int binding, PBaseCommandBuffer pCB, INT64 size, INT64 offset) override;
+
+ virtual void CreateIndexBuffer(int count) override;
+ virtual void UpdateIndexBuffer(const void* p, PBaseCommandBuffer pCB, INT64 size, INT64 offset) override;
+
+ virtual Continue Scheduled_Update() override;
+
+ //
+ // D3D11
+ //
+
+ void GetD3DInputElementDescs(UINT32 bindingsFilter, Vector& vInputElementDescs) const;
+ int GetStride(int binding) const { return _vStrides[binding]; }
+
+ int GetVertexBufferCount() const { return Utils::Cast32(_vVertexBuffers.size()); }
+ ID3D11Buffer* GetD3DVertexBuffer(int binding) const;
+ ID3D11Buffer* GetD3DIndexBuffer() const;
+ };
+ VERUS_TYPEDEFS(GeometryD3D11);
+ }
+}
diff --git a/RendererDirect3D11/src/CGI/Native.cpp b/RendererDirect3D11/src/CGI/Native.cpp
new file mode 100644
index 0000000..4ae9d40
--- /dev/null
+++ b/RendererDirect3D11/src/CGI/Native.cpp
@@ -0,0 +1,236 @@
+// Copyright (C) 2021-2022, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
+#include "pch.h"
+
+using namespace verus;
+
+D3D11_COMPARISON_FUNC CGI::ToNativeCompareOp(CompareOp compareOp)
+{
+ switch (compareOp)
+ {
+ case CompareOp::never: return D3D11_COMPARISON_NEVER;
+ case CompareOp::less: return D3D11_COMPARISON_LESS;
+ case CompareOp::equal: return D3D11_COMPARISON_EQUAL;
+ case CompareOp::lessOrEqual: return D3D11_COMPARISON_LESS_EQUAL;
+ case CompareOp::greater: return D3D11_COMPARISON_GREATER;
+ case CompareOp::notEqual: return D3D11_COMPARISON_NOT_EQUAL;
+ case CompareOp::greaterOrEqual: return D3D11_COMPARISON_GREATER_EQUAL;
+ case CompareOp::always: return D3D11_COMPARISON_ALWAYS;
+ default: throw VERUS_RECOVERABLE << "ToNativeCompareOp()";
+ }
+}
+
+UINT CGI::ToNativeCubeMapFace(CubeMapFace face)
+{
+ switch (face)
+ {
+ case CubeMapFace::posX: return 0;
+ case CubeMapFace::negX: return 1;
+ case CubeMapFace::posY: return 2;
+ case CubeMapFace::negY: return 3;
+ case CubeMapFace::posZ: return 4;
+ case CubeMapFace::negZ: return 5;
+ default: throw VERUS_RECOVERABLE << "ToNativeCubeMapFace()";
+ }
+}
+
+D3D11_FILL_MODE CGI::ToNativePolygonMode(PolygonMode polygonMode)
+{
+ switch (polygonMode)
+ {
+ case PolygonMode::fill: return D3D11_FILL_SOLID;
+ case PolygonMode::line: return D3D11_FILL_WIREFRAME;
+ default: throw VERUS_RECOVERABLE << "ToNativePolygonMode()";
+ }
+}
+
+D3D11_CULL_MODE CGI::ToNativeCullMode(CullMode cullMode)
+{
+ switch (cullMode)
+ {
+ case CullMode::none: return D3D11_CULL_NONE;
+ case CullMode::front: return D3D11_CULL_FRONT;
+ case CullMode::back: return D3D11_CULL_BACK;
+ default: throw VERUS_RECOVERABLE << "ToNativeCullMode()";
+ }
+}
+
+D3D_PRIMITIVE_TOPOLOGY CGI::ToNativePrimitiveTopology(PrimitiveTopology primitiveTopology)
+{
+ switch (primitiveTopology)
+ {
+ case PrimitiveTopology::pointList: return D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
+ case PrimitiveTopology::lineList: return D3D_PRIMITIVE_TOPOLOGY_LINELIST;
+ case PrimitiveTopology::lineStrip: return D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
+ case PrimitiveTopology::triangleList: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
+ case PrimitiveTopology::triangleStrip: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
+ case PrimitiveTopology::patchList3: return D3D_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST;
+ case PrimitiveTopology::patchList4: return D3D_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST;
+ default: throw VERUS_RECOVERABLE << "ToNativePrimitiveTopology()";
+ }
+}
+
+DXGI_FORMAT CGI::ToNativeFormat(Format format, bool typeless)
+{
+ switch (format)
+ {
+ case Format::unormR10G10B10A2: return DXGI_FORMAT_R10G10B10A2_UNORM;
+ case Format::sintR16: return DXGI_FORMAT_R16_SINT;
+ case Format::floatR11G11B10: return DXGI_FORMAT_R11G11B10_FLOAT;
+
+ case Format::unormR8: return DXGI_FORMAT_R8_UNORM;
+ case Format::unormR8G8: return DXGI_FORMAT_R8G8_UNORM;
+ case Format::unormR8G8B8A8: return DXGI_FORMAT_R8G8B8A8_UNORM;
+ case Format::unormB8G8R8A8: return DXGI_FORMAT_B8G8R8A8_UNORM;
+ case Format::srgbR8G8B8A8: return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
+ case Format::srgbB8G8R8A8: return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
+
+ case Format::floatR16: return DXGI_FORMAT_R16_FLOAT;
+ case Format::floatR16G16: return DXGI_FORMAT_R16G16_FLOAT;
+ case Format::floatR16G16B16A16: return DXGI_FORMAT_R16G16B16A16_FLOAT;
+
+ case Format::floatR32: return DXGI_FORMAT_R32_FLOAT;
+ case Format::floatR32G32: return DXGI_FORMAT_R32G32_FLOAT;
+ case Format::floatR32G32B32A32: return DXGI_FORMAT_R32G32B32A32_FLOAT;
+
+ case Format::unormD16: return typeless ? DXGI_FORMAT_R16_TYPELESS : DXGI_FORMAT_D16_UNORM;
+ case Format::unormD24uintS8: return typeless ? DXGI_FORMAT_R24G8_TYPELESS : DXGI_FORMAT_D24_UNORM_S8_UINT;
+ case Format::floatD32: return typeless ? DXGI_FORMAT_R32_TYPELESS : DXGI_FORMAT_D32_FLOAT;
+
+ case Format::unormBC1: return DXGI_FORMAT_BC1_UNORM;
+ case Format::unormBC2: return DXGI_FORMAT_BC2_UNORM;
+ case Format::unormBC3: return DXGI_FORMAT_BC3_UNORM;
+ case Format::unormBC4: return DXGI_FORMAT_BC4_UNORM;
+ case Format::unormBC5: return DXGI_FORMAT_BC5_UNORM;
+ case Format::unormBC7: return DXGI_FORMAT_BC7_UNORM;
+ case Format::snormBC4: return DXGI_FORMAT_BC4_SNORM;
+ case Format::snormBC5: return DXGI_FORMAT_BC5_SNORM;
+ case Format::srgbBC1: return DXGI_FORMAT_BC1_UNORM_SRGB;
+ case Format::srgbBC2: return DXGI_FORMAT_BC2_UNORM_SRGB;
+ case Format::srgbBC3: return DXGI_FORMAT_BC3_UNORM_SRGB;
+ case Format::srgbBC7: return DXGI_FORMAT_BC7_UNORM_SRGB;
+
+ default: throw VERUS_RECOVERABLE << "ToNativeFormat()";
+ }
+}
+
+DXGI_FORMAT CGI::ToNativeSampledDepthFormat(Format format)
+{
+ switch (format)
+ {
+ case Format::unormD16: return DXGI_FORMAT_R16_UNORM;
+ case Format::unormD24uintS8: return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
+ case Format::floatD32: return DXGI_FORMAT_R32_FLOAT;
+
+ default: throw VERUS_RECOVERABLE << "ToNativeSampledDepthFormat()";
+ }
+}
+
+CSZ CGI::ToNativeSemanticName(ViaUsage usage)
+{
+ static const CSZ names[] =
+ {
+ "POSITION", // ViaUsage::position
+ "BLENDWEIGHTS", // ViaUsage::blendWeights
+ "BLENDINDICES", // ViaUsage::blendIndices
+ "NORMAL", // ViaUsage::normal
+ "TANGENT", // ViaUsage::tangent
+ "BINORMAL", // ViaUsage::binormal
+ "COLOR", // ViaUsage::color
+ "PSIZE", // ViaUsage::psize
+ "TEXCOORD", // ViaUsage::texCoord
+ "INSTDATA", // ViaUsage::instData
+ "ATTR" // ViaUsage::attr
+ };
+ return names[+usage];
+}
+
+DXGI_FORMAT CGI::ToNativeFormat(ViaUsage usage, ViaType type, int components)
+{
+ VERUS_RT_ASSERT(components >= 1 && components <= 4);
+ int index = components - 1;
+
+ static const DXGI_FORMAT floats[] =
+ {
+ DXGI_FORMAT_R32_FLOAT,
+ DXGI_FORMAT_R32G32_FLOAT,
+ DXGI_FORMAT_R32G32B32_FLOAT,
+ DXGI_FORMAT_R32G32B32A32_FLOAT
+ };
+ static const DXGI_FORMAT halfs[] =
+ {
+ DXGI_FORMAT_R16_FLOAT,
+ DXGI_FORMAT_R16G16_FLOAT,
+ DXGI_FORMAT_R16G16_FLOAT,
+ DXGI_FORMAT_R16G16B16A16_FLOAT
+ };
+ static const DXGI_FORMAT shorts[] =
+ {
+ DXGI_FORMAT_R16G16_SINT,
+ DXGI_FORMAT_R16G16_SINT,
+ DXGI_FORMAT_R16G16B16A16_SINT,
+ DXGI_FORMAT_R16G16B16A16_SINT,
+ DXGI_FORMAT_R16G16_SNORM,
+ DXGI_FORMAT_R16G16_SNORM,
+ DXGI_FORMAT_R16G16B16A16_SNORM,
+ DXGI_FORMAT_R16G16B16A16_SNORM
+ };
+ static const DXGI_FORMAT bytes[] =
+ {
+ DXGI_FORMAT_R8G8B8A8_UINT,
+ DXGI_FORMAT_R8G8B8A8_UINT,
+ DXGI_FORMAT_R8G8B8A8_UINT,
+ DXGI_FORMAT_R8G8B8A8_UINT,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_SNORM,
+ DXGI_FORMAT_R8G8B8A8_SNORM,
+ DXGI_FORMAT_R8G8B8A8_SNORM,
+ DXGI_FORMAT_R8G8B8A8_SNORM
+ };
+
+ switch (type)
+ {
+ case ViaType::floats:
+ {
+ return floats[index];
+ }
+ break;
+ case ViaType::halfs:
+ {
+ VERUS_RT_ASSERT(3 != components);
+ return halfs[index];
+ }
+ break;
+ case ViaType::shorts:
+ {
+ VERUS_RT_ASSERT(2 == components || 4 == components);
+ switch (usage)
+ {
+ case ViaUsage::normal:
+ case ViaUsage::tangent:
+ case ViaUsage::binormal:
+ index += 4; break; // SNORM.
+ }
+ return shorts[index];
+ }
+ break;
+ case ViaType::ubytes:
+ {
+ VERUS_RT_ASSERT(4 == components);
+ switch (usage)
+ {
+ case ViaUsage::normal:
+ case ViaUsage::tangent:
+ case ViaUsage::binormal:
+ index += 8; break; // SNORM.
+ case ViaUsage::color:
+ index += 4; break; // UNORM.
+ }
+ return bytes[index];
+ }
+ break;
+ default: throw VERUS_RECOVERABLE << "ToNativeFormat(); ViaType=?";
+ }
+}
diff --git a/RendererDirect3D11/src/CGI/Native.h b/RendererDirect3D11/src/CGI/Native.h
new file mode 100644
index 0000000..eb30bc8
--- /dev/null
+++ b/RendererDirect3D11/src/CGI/Native.h
@@ -0,0 +1,24 @@
+// Copyright (C) 2021-2022, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
+#pragma once
+
+namespace verus
+{
+ namespace CGI
+ {
+ D3D11_COMPARISON_FUNC ToNativeCompareOp(CompareOp compareOp);
+
+ UINT ToNativeCubeMapFace(CubeMapFace face);
+
+ D3D11_FILL_MODE ToNativePolygonMode(PolygonMode polygonMode);
+
+ D3D11_CULL_MODE ToNativeCullMode(CullMode cullMode);
+
+ D3D_PRIMITIVE_TOPOLOGY ToNativePrimitiveTopology(PrimitiveTopology primitiveTopology);
+
+ DXGI_FORMAT ToNativeFormat(Format format, bool typeless);
+ DXGI_FORMAT ToNativeSampledDepthFormat(Format format);
+
+ CSZ ToNativeSemanticName(ViaUsage usage);
+ DXGI_FORMAT ToNativeFormat(ViaUsage usage, ViaType type, int components);
+ }
+}
diff --git a/RendererDirect3D11/src/CGI/PipelineD3D11.cpp b/RendererDirect3D11/src/CGI/PipelineD3D11.cpp
new file mode 100644
index 0000000..1c35d5f
--- /dev/null
+++ b/RendererDirect3D11/src/CGI/PipelineD3D11.cpp
@@ -0,0 +1,223 @@
+// Copyright (C) 2021-2022, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
+#include "pch.h"
+
+using namespace verus;
+using namespace verus::CGI;
+
+PipelineD3D11::PipelineD3D11()
+{
+}
+
+PipelineD3D11::~PipelineD3D11()
+{
+ Done();
+}
+
+void PipelineD3D11::Init(RcPipelineDesc desc)
+{
+ VERUS_INIT();
+ VERUS_QREF_RENDERER_D3D11;
+ HRESULT hr = 0;
+
+ if (desc._compute)
+ {
+ _compute = true;
+ InitCompute(desc);
+ return;
+ }
+
+ // Attachment count according to blend equations:
+ int attachmentCount = 0;
+ for (const auto& x : desc._colorAttachBlendEqs)
+ {
+ if (x.empty())
+ break;
+ attachmentCount++;
+ }
+
+ RcGeometryD3D11 geo = static_cast(*desc._geometry);
+ RcShaderD3D11 shader = static_cast(*desc._shader);
+
+ _topology = ToNativePrimitiveTopology(desc._topology);
+ _vertexInputBindingsFilter = desc._vertexInputBindingsFilter;
+
+ RP::RcD3DRenderPass renderPass = pRendererD3D11->GetRenderPass(desc._renderPassHandle);
+ RP::RcD3DSubpass subpass = renderPass._vSubpasses[desc._subpass];
+
+ const String name = String(" (") + _C(shader.GetSourceName()) + ", " + desc._shaderBranch + ")";
+
+ ComPtr pBlob;
+ ShaderD3D11::RcCompiled compiled = shader.GetCompiled(desc._shaderBranch);
+ pBlob = compiled._pBlobs[+BaseShader::Stage::vs];
+ if (pBlob && FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateVertexShader(pBlob->GetBufferPointer(), pBlob->GetBufferSize(), nullptr, &_pVS)))
+ throw VERUS_RUNTIME_ERROR << "CreateVertexShader(); hr=" << VERUS_HR(hr);
+ SetDebugObjectName(_pVS.Get(), _C(String("Pipeline.VS") + name));
+ pBlob = compiled._pBlobs[+BaseShader::Stage::hs];
+ if (pBlob && FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateHullShader(pBlob->GetBufferPointer(), pBlob->GetBufferSize(), nullptr, &_pHS)))
+ throw VERUS_RUNTIME_ERROR << "CreateHullShader(); hr=" << VERUS_HR(hr);
+ SetDebugObjectName(_pHS.Get(), _C(String("Pipeline.HS") + name));
+ pBlob = compiled._pBlobs[+BaseShader::Stage::ds];
+ if (pBlob && FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateDomainShader(pBlob->GetBufferPointer(), pBlob->GetBufferSize(), nullptr, &_pDS)))
+ throw VERUS_RUNTIME_ERROR << "CreateDomainShader(); hr=" << VERUS_HR(hr);
+ SetDebugObjectName(_pDS.Get(), _C(String("Pipeline.DS") + name));
+ pBlob = compiled._pBlobs[+BaseShader::Stage::gs];
+ if (pBlob && FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateGeometryShader(pBlob->GetBufferPointer(), pBlob->GetBufferSize(), nullptr, &_pGS)))
+ throw VERUS_RUNTIME_ERROR << "CreateGeometryShader(); hr=" << VERUS_HR(hr);
+ SetDebugObjectName(_pGS.Get(), _C(String("Pipeline.GS") + name));
+ pBlob = compiled._pBlobs[+BaseShader::Stage::fs];
+ if (pBlob && FAILED(hr = pRendererD3D11->GetD3DDevice()->CreatePixelShader(pBlob->GetBufferPointer(), pBlob->GetBufferSize(), nullptr, &_pPS)))
+ throw VERUS_RUNTIME_ERROR << "CreatePixelShader(); hr=" << VERUS_HR(hr);
+ SetDebugObjectName(_pPS.Get(), _C(String("Pipeline.PS") + name));
+ pBlob = compiled._pBlobs[+BaseShader::Stage::vs];
+
+ D3D11_BLEND_DESC bDesc = {};
+ bDesc.AlphaToCoverageEnable = FALSE;
+ bDesc.IndependentBlendEnable = TRUE;
+ FillBlendStateRenderTargets(desc, attachmentCount, bDesc);
+ if (FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateBlendState(&bDesc, &_pBlendState)))
+ throw VERUS_RUNTIME_ERROR << "CreateBlendState(); hr=" << VERUS_HR(hr);
+ SetDebugObjectName(_pBlendState.Get(), _C(String("Pipeline.BlendState") + name));
+
+ D3D11_RASTERIZER_DESC rDesc = {};
+ rDesc.FillMode = ToNativePolygonMode(desc._rasterizationState._polygonMode);
+ rDesc.CullMode = ToNativeCullMode(desc._rasterizationState._cullMode);
+ rDesc.FrontCounterClockwise = TRUE;
+ rDesc.DepthBias = static_cast(desc._rasterizationState._depthBiasConstantFactor);
+ rDesc.DepthBiasClamp = desc._rasterizationState._depthBiasClamp;
+ rDesc.SlopeScaledDepthBias = desc._rasterizationState._depthBiasSlopeFactor;
+ rDesc.DepthClipEnable = TRUE;
+ rDesc.ScissorEnable = TRUE;
+ rDesc.MultisampleEnable = FALSE;
+ rDesc.AntialiasedLineEnable = (desc._colorAttachBlendEqs[0] == VERUS_COLOR_BLEND_ALPHA) ? TRUE : FALSE;
+ if (FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateRasterizerState(&rDesc, &_pRasterizerState)))
+ throw VERUS_RUNTIME_ERROR << "CreateRasterizerState(); hr=" << VERUS_HR(hr);
+ SetDebugObjectName(_pRasterizerState.Get(), _C(String("Pipeline.RasterizerState") + name));
+
+ D3D11_DEPTH_STENCIL_DESC dsDesc = {};
+ if (subpass._depthStencil._index >= 0)
+ {
+ dsDesc.DepthEnable = desc._depthTestEnable;
+ dsDesc.DepthWriteMask = desc._depthWriteEnable ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
+ dsDesc.DepthFunc = ToNativeCompareOp(desc._depthCompareOp);
+ dsDesc.StencilEnable = desc._stencilTestEnable;
+ }
+ if (FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateDepthStencilState(&dsDesc, &_pDepthStencilState)))
+ throw VERUS_RUNTIME_ERROR << "CreateDepthStencilState(); hr=" << VERUS_HR(hr);
+ SetDebugObjectName(_pDepthStencilState.Get(), _C(String("Pipeline.DepthStencilState") + name));
+
+ Vector vInputElementDescs;
+ geo.GetD3DInputElementDescs(_vertexInputBindingsFilter, vInputElementDescs);
+ if (FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateInputLayout(
+ vInputElementDescs.data(),
+ Utils::Cast32(vInputElementDescs.size()),
+ pBlob->GetBufferPointer(),
+ pBlob->GetBufferSize(),
+ &_pInputLayout)))
+ throw VERUS_RUNTIME_ERROR << "CreateInputLayout(); hr=" << VERUS_HR(hr);
+ SetDebugObjectName(_pInputLayout.Get(), _C(String("Pipeline.InputLayout") + name));
+}
+
+void PipelineD3D11::Done()
+{
+ _pInputLayout.Reset();
+ _pDepthStencilState.Reset();
+ _pRasterizerState.Reset();
+ _pBlendState.Reset();
+ _pCS.Reset();
+ _pPS.Reset();
+ _pGS.Reset();
+ _pDS.Reset();
+ _pHS.Reset();
+ _pVS.Reset();
+
+ VERUS_DONE(PipelineD3D11);
+}
+
+void PipelineD3D11::InitCompute(RcPipelineDesc desc)
+{
+ VERUS_QREF_RENDERER_D3D11;
+ HRESULT hr = 0;
+
+ RcShaderD3D11 shader = static_cast(*desc._shader);
+
+ const String name = String(" (") + _C(shader.GetSourceName()) + ", " + desc._shaderBranch + ")";
+
+ ComPtr pBlob;
+ ShaderD3D11::RcCompiled compiled = shader.GetCompiled(desc._shaderBranch);
+ pBlob = compiled._pBlobs[+BaseShader::Stage::cs];
+ if (pBlob && FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateComputeShader(pBlob->GetBufferPointer(), pBlob->GetBufferSize(), nullptr, &_pCS)))
+ throw VERUS_RUNTIME_ERROR << "CreateComputeShader(); hr=" << VERUS_HR(hr);
+ SetDebugObjectName(_pCS.Get(), _C(String("Pipeline.CS") + name));
+}
+
+void PipelineD3D11::FillBlendStateRenderTargets(RcPipelineDesc desc, int attachmentCount, D3D11_BLEND_DESC& blendDesc)
+{
+ VERUS_FOR(i, attachmentCount)
+ {
+ CSZ p = _C(desc._colorAttachWriteMasks[i]);
+ while (*p)
+ {
+ switch (*p)
+ {
+ case 'r': blendDesc.RenderTarget[i].RenderTargetWriteMask |= D3D11_COLOR_WRITE_ENABLE_RED; break;
+ case 'g': blendDesc.RenderTarget[i].RenderTargetWriteMask |= D3D11_COLOR_WRITE_ENABLE_GREEN; break;
+ case 'b': blendDesc.RenderTarget[i].RenderTargetWriteMask |= D3D11_COLOR_WRITE_ENABLE_BLUE; break;
+ case 'a': blendDesc.RenderTarget[i].RenderTargetWriteMask |= D3D11_COLOR_WRITE_ENABLE_ALPHA; break;
+ }
+ p++;
+ }
+
+ if (desc._colorAttachBlendEqs[i] != "off")
+ {
+ blendDesc.RenderTarget[i].BlendEnable = TRUE;
+
+ static const D3D11_BLEND bfs[] =
+ {
+ D3D11_BLEND_ZERO,
+ D3D11_BLEND_ONE,
+ D3D11_BLEND_INV_DEST_ALPHA,
+ D3D11_BLEND_INV_DEST_COLOR,
+ D3D11_BLEND_INV_BLEND_FACTOR,
+ D3D11_BLEND_INV_SRC_ALPHA,
+ D3D11_BLEND_INV_SRC_COLOR,
+ D3D11_BLEND_DEST_ALPHA,
+ D3D11_BLEND_DEST_COLOR,
+ D3D11_BLEND_BLEND_FACTOR,
+ D3D11_BLEND_SRC_ALPHA,
+ D3D11_BLEND_SRC_ALPHA_SAT,
+ D3D11_BLEND_SRC_COLOR
+ };
+ static const D3D11_BLEND_OP ops[] =
+ {
+ D3D11_BLEND_OP_ADD,
+ D3D11_BLEND_OP_SUBTRACT,
+ D3D11_BLEND_OP_REV_SUBTRACT,
+ D3D11_BLEND_OP_MIN,
+ D3D11_BLEND_OP_MAX
+ };
+
+ int colorBlendOp = -1;
+ int alphaBlendOp = -1;
+ int srcColorBlendFactor = -1;
+ int dstColorBlendFactor = -1;
+ int srcAlphaBlendFactor = -1;
+ int dstAlphaBlendFactor = -1;
+
+ BaseRenderer::SetAlphaBlendHelper(
+ _C(desc._colorAttachBlendEqs[i]),
+ colorBlendOp,
+ alphaBlendOp,
+ srcColorBlendFactor,
+ dstColorBlendFactor,
+ srcAlphaBlendFactor,
+ dstAlphaBlendFactor);
+
+ blendDesc.RenderTarget[i].SrcBlend = bfs[srcColorBlendFactor];
+ blendDesc.RenderTarget[i].DestBlend = bfs[dstColorBlendFactor];
+ blendDesc.RenderTarget[i].BlendOp = ops[colorBlendOp];
+ blendDesc.RenderTarget[i].SrcBlendAlpha = bfs[srcAlphaBlendFactor];
+ blendDesc.RenderTarget[i].DestBlendAlpha = bfs[dstAlphaBlendFactor];
+ blendDesc.RenderTarget[i].BlendOpAlpha = ops[alphaBlendOp];
+ }
+ }
+}
diff --git a/RendererDirect3D11/src/CGI/PipelineD3D11.h b/RendererDirect3D11/src/CGI/PipelineD3D11.h
new file mode 100644
index 0000000..f14ccb5
--- /dev/null
+++ b/RendererDirect3D11/src/CGI/PipelineD3D11.h
@@ -0,0 +1,55 @@
+// Copyright (C) 2021-2022, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
+#pragma once
+
+namespace verus
+{
+ namespace CGI
+ {
+ class PipelineD3D11 : public BasePipeline
+ {
+ ComPtr _pVS;
+ ComPtr _pHS;
+ ComPtr _pDS;
+ ComPtr _pGS;
+ ComPtr _pPS;
+ ComPtr _pCS;
+ ComPtr _pBlendState;
+ ComPtr _pRasterizerState;
+ ComPtr _pDepthStencilState;
+ ComPtr _pInputLayout;
+ UINT _sampleMask = UINT_MAX;
+ UINT _stencilRef = 0;
+ D3D_PRIMITIVE_TOPOLOGY _topology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
+ bool _compute = false;
+
+ public:
+ PipelineD3D11();
+ virtual ~PipelineD3D11() override;
+
+ virtual void Init(RcPipelineDesc desc) override;
+ virtual void Done() override;
+
+ //
+ // D3D11
+ //
+
+ VERUS_P(void InitCompute(RcPipelineDesc desc));
+ bool IsCompute() const { return _compute; }
+ ID3D11VertexShader* GetD3DVS() const { return _pVS.Get(); }
+ ID3D11HullShader* GetD3DHS() const { return _pHS.Get(); }
+ ID3D11DomainShader* GetD3DDS() const { return _pDS.Get(); }
+ ID3D11GeometryShader* GetD3DGS() const { return _pGS.Get(); }
+ ID3D11PixelShader* GetD3DPS() const { return _pPS.Get(); }
+ ID3D11ComputeShader* GetD3DCS() const { return _pCS.Get(); }
+ ID3D11BlendState* GetD3DBlendState() const { return _pBlendState.Get(); }
+ ID3D11RasterizerState* GetD3DRasterizerState() const { return _pRasterizerState.Get(); }
+ ID3D11DepthStencilState* GetD3DDepthStencilState() const { return _pDepthStencilState.Get(); }
+ ID3D11InputLayout* GetD3DInputLayout() const { return _pInputLayout.Get(); }
+ UINT GetSampleMask() const { return _sampleMask; }
+ UINT GetStencilRef() const { return _stencilRef; }
+ D3D_PRIMITIVE_TOPOLOGY GetD3DPrimitiveTopology() const { return _topology; }
+ void FillBlendStateRenderTargets(RcPipelineDesc desc, int attachmentCount, D3D11_BLEND_DESC& blendDesc);
+ };
+ VERUS_TYPEDEFS(PipelineD3D11);
+ }
+}
diff --git a/RendererDirect3D11/src/CGI/RenderPass.cpp b/RendererDirect3D11/src/CGI/RenderPass.cpp
new file mode 100644
index 0000000..f74772e
--- /dev/null
+++ b/RendererDirect3D11/src/CGI/RenderPass.cpp
@@ -0,0 +1,5 @@
+// Copyright (C) 2021-2022, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
+#include "pch.h"
+
+using namespace verus;
+using namespace verus::CGI;
diff --git a/RendererDirect3D11/src/CGI/RenderPass.h b/RendererDirect3D11/src/CGI/RenderPass.h
new file mode 100644
index 0000000..27b3391
--- /dev/null
+++ b/RendererDirect3D11/src/CGI/RenderPass.h
@@ -0,0 +1,76 @@
+// Copyright (C) 2021-2022, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
+#pragma once
+
+namespace verus
+{
+ namespace CGI
+ {
+ namespace RP
+ {
+ class D3DAttachment
+ {
+ public:
+ Format _format = Format::unormR8G8B8A8;
+ int _sampleCount = 1;
+ Attachment::LoadOp _loadOp = Attachment::LoadOp::load;
+ Attachment::StoreOp _storeOp = Attachment::StoreOp::store;
+ Attachment::LoadOp _stencilLoadOp = Attachment::LoadOp::dontCare;
+ Attachment::StoreOp _stencilStoreOp = Attachment::StoreOp::dontCare;
+ int _clearSubpassIndex = -1;
+ };
+ VERUS_TYPEDEFS(D3DAttachment);
+
+ class D3DRef
+ {
+ public:
+ int _index = -1;
+ };
+ VERUS_TYPEDEFS(D3DRef);
+
+ class D3DSubpass
+ {
+ public:
+ Vector _vInput;
+ Vector _vColor;
+ Vector _vResolve;
+ Vector _vPreserve;
+ D3DRef _depthStencil;
+ bool _depthStencilReadOnly = false;
+ };
+ VERUS_TYPEDEFS(D3DSubpass);
+
+ class D3DDependency
+ {
+ public:
+ };
+ VERUS_TYPEDEFS(D3DDependency);
+
+ class D3DRenderPass
+ {
+ public:
+ Vector _vAttachments;
+ Vector _vSubpasses;
+ };
+ VERUS_TYPEDEFS(D3DRenderPass);
+
+ class D3DFramebufferSubpass
+ {
+ public:
+ Vector _vRTVs;
+ ID3D11DepthStencilView* _pDSV = nullptr;
+ };
+ VERUS_TYPEDEFS(D3DFramebufferSubpass);
+
+ class D3DFramebuffer
+ {
+ public:
+ Vector _vSubpasses;
+ int _width = 0;
+ int _height = 0;
+ int _mipLevels = 1;
+ CubeMapFace _cubeMapFace = CubeMapFace::none;
+ };
+ VERUS_TYPEDEFS(D3DFramebuffer);
+ }
+ }
+}
diff --git a/RendererDirect3D11/src/CGI/RendererD3D11.cpp b/RendererDirect3D11/src/CGI/RendererD3D11.cpp
new file mode 100644
index 0000000..439e76a
--- /dev/null
+++ b/RendererDirect3D11/src/CGI/RendererD3D11.cpp
@@ -0,0 +1,675 @@
+// Copyright (C) 2021-2022, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
+#include "pch.h"
+
+using namespace verus;
+using namespace verus::CGI;
+
+RendererD3D11::RendererD3D11()
+{
+}
+
+RendererD3D11::~RendererD3D11()
+{
+ Done();
+}
+
+void RendererD3D11::ReleaseMe()
+{
+ Free();
+ TestAllocCount();
+}
+
+void RendererD3D11::Init()
+{
+ VERUS_INIT();
+
+ _vRenderPasses.reserve(20);
+ _vFramebuffers.reserve(40);
+
+ InitD3D();
+}
+
+void RendererD3D11::Done()
+{
+ WaitIdle();
+
+ if (ImGui::GetCurrentContext())
+ {
+ ImGui_ImplDX11_Shutdown();
+ ImGui_ImplSDL2_Shutdown();
+ ImGui::DestroyContext();
+ Renderer::I().ImGuiSetCurrentContext(nullptr);
+ }
+
+ DeleteFramebuffer(FBHandle::Make(-2));
+ DeleteRenderPass(RPHandle::Make(-2));
+
+ _vSamplers.clear();
+
+ _pSwapChainBufferRTV.Reset();
+ _pSwapChainBuffer.Reset();
+ VERUS_COM_RELEASE_CHECK(_pSwapChain.Get());
+ _pSwapChain.Reset();
+ VERUS_COM_RELEASE_CHECK(_pDeviceContext.Get());
+ _pDeviceContext.Reset();
+ VERUS_COM_RELEASE_CHECK(_pDevice.Get());
+ _pDevice.Reset();
+
+ VERUS_DONE(RendererD3D11);
+}
+
+ComPtr RendererD3D11::CreateFactory()
+{
+ HRESULT hr = 0;
+ ComPtr pFactory;
+ if (FAILED(hr = CreateDXGIFactory1(IID_PPV_ARGS(&pFactory)))) // DXGI 1.1, Windows 7.
+ throw VERUS_RUNTIME_ERROR << "CreateDXGIFactory1(); hr=" << VERUS_HR(hr);
+ return pFactory;
+}
+
+ComPtr RendererD3D11::GetAdapter(ComPtr pFactory)
+{
+ ComPtr pAdapter;
+ for (UINT index = 0; SUCCEEDED(pFactory->EnumAdapters1(index, &pAdapter)); ++index)
+ {
+ DXGI_ADAPTER_DESC1 adapterDesc = {};
+ if (SUCCEEDED(pAdapter->GetDesc1(&adapterDesc)))
+ break;
+ pAdapter.Reset();
+ }
+
+ if (!pAdapter)
+ throw VERUS_RUNTIME_ERROR << "GetAdapter(); Adapter not found";
+
+ DXGI_ADAPTER_DESC1 adapterDesc = {};
+ pAdapter->GetDesc1(&adapterDesc);
+ const String description = Str::WideToUtf8(adapterDesc.Description);
+ VERUS_LOG_INFO("Adapter desc: " << description);
+ return pAdapter;
+}
+
+void RendererD3D11::CreateSwapChainBufferRTV()
+{
+ HRESULT hr = 0;
+ if (FAILED(hr = _pSwapChain->GetBuffer(0, IID_PPV_ARGS(&_pSwapChainBuffer))))
+ throw VERUS_RUNTIME_ERROR << "GetBuffer(); hr=" << VERUS_HR(hr);
+ D3D11_RENDER_TARGET_VIEW_DESC rtvDesc = {};
+ rtvDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
+ rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
+ if (FAILED(hr = _pDevice->CreateRenderTargetView(_pSwapChainBuffer.Get(), &rtvDesc, &_pSwapChainBufferRTV)))
+ throw VERUS_RUNTIME_ERROR << "CreateRenderTargetView(); hr=" << VERUS_HR(hr);
+}
+
+void RendererD3D11::InitD3D()
+{
+ VERUS_QREF_RENDERER;
+ VERUS_QREF_CONST_SETTINGS;
+ HRESULT hr = 0;
+
+ //
+ SDL_Window* pWnd = renderer.GetMainWindow()->GetSDL();
+ VERUS_RT_ASSERT(pWnd);
+ SDL_SysWMinfo wmInfo = {};
+ SDL_VERSION(&wmInfo.version);
+ if (!SDL_GetWindowWMInfo(pWnd, &wmInfo))
+ throw VERUS_RUNTIME_ERROR << "SDL_GetWindowWMInfo()";
+ //
+
+ _featureLevel = D3D_FEATURE_LEVEL_11_0;
+
+ ComPtr pFactory = CreateFactory();
+ ComPtr pAdapter = GetAdapter(pFactory);
+
+ VERUS_LOG_INFO("Using feature level: 11_0");
+
+ _swapChainBufferCount = settings._displayVSync ? 3 : 2;
+
+ _swapChainDesc.BufferDesc.Width = renderer.GetSwapChainWidth();
+ _swapChainDesc.BufferDesc.Height = renderer.GetSwapChainHeight();
+ _swapChainDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
+ _swapChainDesc.SampleDesc.Count = 1;
+ _swapChainDesc.SampleDesc.Quality = 0;
+ _swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+ _swapChainDesc.BufferCount = _swapChainBufferCount;
+ _swapChainDesc.OutputWindow = wmInfo.info.win.window;
+ _swapChainDesc.Windowed = (App::DisplayMode::windowed == settings._displayMode);
+ _swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
+
+ UINT flags = 0;
+#ifdef _DEBUG
+ flags = D3D11_CREATE_DEVICE_DEBUG;
+#endif
+
+ if (FAILED(hr = D3D11CreateDeviceAndSwapChain(
+ pAdapter.Get(),
+ D3D_DRIVER_TYPE_UNKNOWN,
+ NULL,
+ flags,
+ nullptr,
+ 0,
+ D3D11_SDK_VERSION,
+ &_swapChainDesc,
+ &_pSwapChain,
+ &_pDevice,
+ &_featureLevel,
+ &_pDeviceContext)))
+ throw VERUS_RUNTIME_ERROR << "D3D11CreateDeviceAndSwapChain(); hr=" << VERUS_HR(hr);
+
+#if defined(_DEBUG) || defined(VERUS_RELEASE_DEBUG)
+ ComPtr pInfoQueue;
+ if (SUCCEEDED(_pDevice.As(&pInfoQueue)))
+ {
+ D3D11_MESSAGE_ID denyList[] =
+ {
+ D3D11_MESSAGE_ID_DEVICE_VSSETSHADERRESOURCES_HAZARD,
+ D3D11_MESSAGE_ID_DEVICE_HSSETSHADERRESOURCES_HAZARD,
+ D3D11_MESSAGE_ID_DEVICE_DSSETSHADERRESOURCES_HAZARD,
+ D3D11_MESSAGE_ID_DEVICE_GSSETSHADERRESOURCES_HAZARD,
+ D3D11_MESSAGE_ID_DEVICE_PSSETSHADERRESOURCES_HAZARD,
+ D3D11_MESSAGE_ID_DEVICE_CSSETSHADERRESOURCES_HAZARD,
+ D3D11_MESSAGE_ID_DEVICE_OMSETRENDERTARGETS_HAZARD,
+ D3D11_MESSAGE_ID_SETPRIVATEDATA_CHANGINGPARAMS
+ };
+ D3D11_INFO_QUEUE_FILTER filter = {};
+ filter.DenyList.NumIDs = VERUS_COUNT_OF(denyList);
+ filter.DenyList.pIDList = denyList;
+ pInfoQueue->AddStorageFilterEntries(&filter);
+ pInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, TRUE);
+ pInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, TRUE);
+ pInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, TRUE);
+ }
+#endif
+
+ CreateSwapChainBufferRTV();
+
+ CreateSamplers();
+}
+
+void RendererD3D11::CreateSamplers()
+{
+ VERUS_QREF_CONST_SETTINGS;
+ HRESULT hr = 0;
+
+ const bool tf = settings._gpuTrilinearFilter;
+ auto ApplyTrilinearFilter = [tf](const D3D11_FILTER filter)
+ {
+ return tf ? static_cast(filter + 1) : filter;
+ };
+
+ _vSamplers.resize(+Sampler::count);
+
+ D3D11_SAMPLER_DESC desc = {};
+ D3D11_SAMPLER_DESC init = {};
+ init.Filter = ApplyTrilinearFilter(D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT);
+ init.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
+ init.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
+ init.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
+ init.MipLODBias = 0;
+ init.MaxAnisotropy = 0;
+ init.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
+ init.MinLOD = 0;
+ init.MaxLOD = D3D11_FLOAT32_MAX;
+
+ desc = init;
+ desc.Filter = D3D11_FILTER_ANISOTROPIC;
+ desc.MipLODBias = -2;
+ desc.MaxAnisotropy = settings._gpuAnisotropyLevel;
+ if (FAILED(hr = _pDevice->CreateSamplerState(&desc, &_vSamplers[+Sampler::lodBias])))
+ throw VERUS_RUNTIME_ERROR << "CreateSamplerState(); hr=" << VERUS_HR(hr);
+
+ desc = init;
+ desc.Filter = (settings._sceneShadowQuality <= App::Settings::Quality::low) ?
+ D3D11_FILTER_COMPARISON_MIN_MAG_MIP_POINT : D3D11_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT;
+ desc.AddressU = desc.AddressV = desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
+ desc.ComparisonFunc = D3D11_COMPARISON_LESS_EQUAL;
+ if (FAILED(hr = _pDevice->CreateSamplerState(&desc, &_vSamplers[+Sampler::shadow])))
+ throw VERUS_RUNTIME_ERROR << "CreateSamplerState(); hr=" << VERUS_HR(hr);
+
+ desc = init;
+ desc.Filter = D3D11_FILTER_ANISOTROPIC;
+ desc.MaxAnisotropy = settings._gpuAnisotropyLevel;
+ if (FAILED(hr = _pDevice->CreateSamplerState(&desc, &_vSamplers[+Sampler::aniso])))
+ throw VERUS_RUNTIME_ERROR << "CreateSamplerState(); hr=" << VERUS_HR(hr);
+
+ desc = init;
+ desc.Filter = D3D11_FILTER_ANISOTROPIC;
+ desc.AddressU = desc.AddressV = desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
+ desc.MaxAnisotropy = settings._gpuAnisotropyLevel;
+ if (FAILED(hr = _pDevice->CreateSamplerState(&desc, &_vSamplers[+Sampler::anisoClamp])))
+ throw VERUS_RUNTIME_ERROR << "CreateSamplerState(); hr=" << VERUS_HR(hr);
+
+ desc = init;
+ desc.Filter = D3D11_FILTER_ANISOTROPIC;
+ desc.MipLODBias = -0.5f;
+ desc.MaxAnisotropy = settings._gpuAnisotropyLevel;
+ if (FAILED(hr = _pDevice->CreateSamplerState(&desc, &_vSamplers[+Sampler::anisoSharp])))
+ throw VERUS_RUNTIME_ERROR << "CreateSamplerState(); hr=" << VERUS_HR(hr);
+
+ //
+ desc = init;
+ if (FAILED(hr = _pDevice->CreateSamplerState(&desc, &_vSamplers[+Sampler::linearMipL])))
+ throw VERUS_RUNTIME_ERROR << "CreateSamplerState(); hr=" << VERUS_HR(hr);
+
+ desc = init;
+ desc.Filter = ApplyTrilinearFilter(D3D11_FILTER_MIN_MAG_MIP_POINT);
+ if (FAILED(hr = _pDevice->CreateSamplerState(&desc, &_vSamplers[+Sampler::nearestMipL])))
+ throw VERUS_RUNTIME_ERROR << "CreateSamplerState(); hr=" << VERUS_HR(hr);
+
+ desc = init;
+ desc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
+ if (FAILED(hr = _pDevice->CreateSamplerState(&desc, &_vSamplers[+Sampler::linearMipN])))
+ throw VERUS_RUNTIME_ERROR << "CreateSamplerState(); hr=" << VERUS_HR(hr);
+
+ desc = init;
+ desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
+ if (FAILED(hr = _pDevice->CreateSamplerState(&desc, &_vSamplers[+Sampler::nearestMipN])))
+ throw VERUS_RUNTIME_ERROR << "CreateSamplerState(); hr=" << VERUS_HR(hr);
+ //
+
+ //
+ desc = init;
+ desc.AddressU = desc.AddressV = desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
+ if (FAILED(hr = _pDevice->CreateSamplerState(&desc, &_vSamplers[+Sampler::linearClampMipL])))
+ throw VERUS_RUNTIME_ERROR << "CreateSamplerState(); hr=" << VERUS_HR(hr);
+
+ desc = init;
+ desc.Filter = ApplyTrilinearFilter(D3D11_FILTER_MIN_MAG_MIP_POINT);
+ desc.AddressU = desc.AddressV = desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
+ if (FAILED(hr = _pDevice->CreateSamplerState(&desc, &_vSamplers[+Sampler::nearestClampMipL])))
+ throw VERUS_RUNTIME_ERROR << "CreateSamplerState(); hr=" << VERUS_HR(hr);
+
+ desc = init;
+ desc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
+ desc.AddressU = desc.AddressV = desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
+ if (FAILED(hr = _pDevice->CreateSamplerState(&desc, &_vSamplers[+Sampler::linearClampMipN])))
+ throw VERUS_RUNTIME_ERROR << "CreateSamplerState(); hr=" << VERUS_HR(hr);
+
+ desc = init;
+ desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
+ desc.AddressU = desc.AddressV = desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
+ if (FAILED(hr = _pDevice->CreateSamplerState(&desc, &_vSamplers[+Sampler::nearestClampMipN])))
+ throw VERUS_RUNTIME_ERROR << "CreateSamplerState(); hr=" << VERUS_HR(hr);
+ //
+}
+
+ID3D11SamplerState* RendererD3D11::GetD3DSamplerState(Sampler s) const
+{
+ return _vSamplers[+s].Get();
+}
+
+void RendererD3D11::ImGuiInit(RPHandle renderPassHandle)
+{
+ VERUS_QREF_RENDERER;
+ VERUS_QREF_CONST_SETTINGS;
+
+ IMGUI_CHECKVERSION();
+ ImGuiContext* pContext = ImGui::CreateContext();
+ renderer.ImGuiSetCurrentContext(pContext);
+ auto& io = ImGui::GetIO();
+ io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
+ io.ConfigWindowsMoveFromTitleBarOnly = true;
+ io.IniFilename = nullptr;
+ if (!settings._imguiFont.empty())
+ {
+ Vector vData;
+ IO::FileSystem::LoadResource(_C(settings._imguiFont), vData);
+ void* pFontData = IM_ALLOC(vData.size());
+ memcpy(pFontData, vData.data(), vData.size());
+ io.Fonts->AddFontFromMemoryTTF(pFontData, Utils::Cast32(vData.size()), static_cast(settings.GetFontSize()), nullptr, io.Fonts->GetGlyphRangesCyrillic());
+ }
+
+ ImGui::StyleColorsDark();
+
+ ImGui_ImplSDL2_InitForD3D(renderer.GetMainWindow()->GetSDL());
+ ImGui_ImplDX11_Init(_pDevice.Get(), _pDeviceContext.Get());
+}
+
+void RendererD3D11::ImGuiRenderDrawData()
+{
+ VERUS_QREF_RENDERER;
+ renderer.UpdateUtilization();
+ ImGui::Render();
+ if (ImGui::GetDrawData())
+ ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
+}
+
+void RendererD3D11::ResizeSwapChain()
+{
+ VERUS_QREF_RENDERER;
+ HRESULT hr = 0;
+
+ _pSwapChainBufferRTV.Reset();
+ _pSwapChainBuffer.Reset();
+
+ if (FAILED(hr = _pSwapChain->ResizeBuffers(
+ _swapChainDesc.BufferCount,
+ renderer.GetSwapChainWidth(),
+ renderer.GetSwapChainHeight(),
+ _swapChainDesc.BufferDesc.Format,
+ _swapChainDesc.Flags)))
+ throw VERUS_RUNTIME_ERROR << "ResizeBuffers(); hr=" << VERUS_HR(hr);
+
+ CreateSwapChainBufferRTV();
+}
+
+void RendererD3D11::BeginFrame()
+{
+ _swapChainBufferIndex = -1;
+
+ ImGui_ImplDX11_NewFrame();
+ ImGui_ImplSDL2_NewFrame();
+ ImGui::NewFrame();
+}
+
+void RendererD3D11::AcquireSwapChainImage()
+{
+ _swapChainBufferIndex = 0;
+}
+
+void RendererD3D11::EndFrame()
+{
+ VERUS_QREF_CONST_SETTINGS;
+ HRESULT hr = 0;
+
+ UpdateScheduled();
+
+ ImGui::EndFrame();
+
+ _ringBufferIndex = (_ringBufferIndex + 1) % s_ringBufferSize;
+
+ //
+ if (_swapChainBufferIndex >= 0)
+ {
+ UINT syncInterval = settings._displayVSync ? 1 : 0;
+ UINT flags = 0;
+ if (FAILED(hr = _pSwapChain->Present(syncInterval, flags)))
+ throw VERUS_RUNTIME_ERROR << "Present(); hr=" << VERUS_HR(hr);
+ }
+ //
+}
+
+void RendererD3D11::WaitIdle()
+{
+ if (_pDeviceContext)
+ _pDeviceContext->Flush();
+}
+
+void RendererD3D11::OnMinimized()
+{
+ WaitIdle();
+ _pSwapChain->Present(0, 0);
+}
+
+// Resources:
+
+PBaseCommandBuffer RendererD3D11::InsertCommandBuffer()
+{
+ return TStoreCommandBuffers::Insert();
+}
+
+PBaseGeometry RendererD3D11::InsertGeometry()
+{
+ return TStoreGeometry::Insert();
+}
+
+PBasePipeline RendererD3D11::InsertPipeline()
+{
+ return TStorePipelines::Insert();
+}
+
+PBaseShader RendererD3D11::InsertShader()
+{
+ return TStoreShaders::Insert();
+}
+
+PBaseTexture RendererD3D11::InsertTexture()
+{
+ return TStoreTextures::Insert();
+}
+
+void RendererD3D11::DeleteCommandBuffer(PBaseCommandBuffer p)
+{
+ TStoreCommandBuffers::Delete(static_cast(p));
+}
+
+void RendererD3D11::DeleteGeometry(PBaseGeometry p)
+{
+ TStoreGeometry::Delete(static_cast(p));
+}
+
+void RendererD3D11::DeletePipeline(PBasePipeline p)
+{
+ TStorePipelines::Delete(static_cast(p));
+}
+
+void RendererD3D11::DeleteShader(PBaseShader p)
+{
+ TStoreShaders::Delete(static_cast(p));
+}
+
+void RendererD3D11::DeleteTexture(PBaseTexture p)
+{
+ TStoreTextures::Delete(static_cast(p));
+}
+
+RPHandle RendererD3D11::CreateRenderPass(std::initializer_list ilA, std::initializer_list ilS, std::initializer_list ilD)
+{
+ RP::D3DRenderPass renderPass;
+
+ renderPass._vAttachments.reserve(ilA.size());
+ for (const auto& attachment : ilA)
+ {
+ RP::D3DAttachment d3dAttach;
+ d3dAttach._format = attachment._format;
+ d3dAttach._sampleCount = attachment._sampleCount;
+ d3dAttach._loadOp = attachment._loadOp;
+ d3dAttach._storeOp = attachment._storeOp;
+ d3dAttach._stencilLoadOp = attachment._stencilLoadOp;
+ d3dAttach._stencilStoreOp = attachment._stencilStoreOp;
+ renderPass._vAttachments.push_back(std::move(d3dAttach));
+ }
+
+ auto GetAttachmentIndexByName = [&ilA](CSZ name) -> int
+ {
+ if (!name)
+ return -1;
+ int index = 0;
+ for (const auto& attachment : ilA)
+ {
+ if (!strcmp(attachment._name, name))
+ return index;
+ index++;
+ }
+ throw VERUS_RECOVERABLE << "CreateRenderPass(); Attachment not found";
+ };
+
+ renderPass._vSubpasses.reserve(ilS.size());
+ for (const auto& subpass : ilS)
+ {
+ RP::D3DSubpass d3dSubpass;
+
+ d3dSubpass._vInput.reserve(subpass._ilInput.size());
+ for (const auto& input : subpass._ilInput)
+ {
+ RP::D3DRef ref;
+ ref._index = GetAttachmentIndexByName(input._name);
+ d3dSubpass._vInput.push_back(ref);
+ }
+
+ d3dSubpass._vColor.reserve(subpass._ilColor.size());
+ for (const auto& color : subpass._ilColor)
+ {
+ RP::D3DRef ref;
+ ref._index = GetAttachmentIndexByName(color._name);
+ d3dSubpass._vColor.push_back(ref);
+
+ if (-1 == renderPass._vAttachments[ref._index]._clearSubpassIndex)
+ renderPass._vAttachments[ref._index]._clearSubpassIndex = Utils::Cast32(renderPass._vSubpasses.size());
+ }
+
+ if (subpass._depthStencil._name)
+ {
+ d3dSubpass._depthStencil._index = GetAttachmentIndexByName(subpass._depthStencil._name);
+ d3dSubpass._depthStencilReadOnly = (ImageLayout::depthStencilReadOnly == subpass._depthStencil._layout);
+
+ if (-1 == renderPass._vAttachments[d3dSubpass._depthStencil._index]._clearSubpassIndex)
+ renderPass._vAttachments[d3dSubpass._depthStencil._index]._clearSubpassIndex = Utils::Cast32(renderPass._vSubpasses.size());
+ }
+
+ d3dSubpass._vPreserve.reserve(subpass._ilPreserve.size());
+ for (const auto& preserve : subpass._ilPreserve)
+ d3dSubpass._vPreserve.push_back(GetAttachmentIndexByName(preserve._name));
+
+ renderPass._vSubpasses.push_back(std::move(d3dSubpass));
+ }
+
+ const int nextIndex = GetNextRenderPassIndex();
+ if (nextIndex >= _vRenderPasses.size())
+ _vRenderPasses.push_back(std::move(renderPass));
+ else
+ _vRenderPasses[nextIndex] = renderPass;
+
+ return RPHandle::Make(nextIndex);
+}
+
+FBHandle RendererD3D11::CreateFramebuffer(RPHandle renderPassHandle, std::initializer_list il, int w, int h, int swapChainBufferIndex, CubeMapFace cubeMapFace)
+{
+ RP::RcD3DRenderPass renderPass = GetRenderPass(renderPassHandle);
+ RP::D3DFramebuffer framebuffer;
+ framebuffer._width = w;
+ framebuffer._height = h;
+ framebuffer._cubeMapFace = cubeMapFace;
+
+ const Vector vTex(il);
+ auto GetRTV = [this, &vTex, swapChainBufferIndex, cubeMapFace](int index) -> ID3D11RenderTargetView*
+ {
+ if (swapChainBufferIndex >= 0)
+ {
+ if (index)
+ {
+ auto& texD3D11 = static_cast(*vTex[index - 1]);
+ return texD3D11.GetRTV();
+ }
+ else
+ {
+ return _pSwapChainBufferRTV.Get();
+ }
+ }
+ else
+ {
+ auto& texD3D11 = static_cast(*vTex[index]);
+ switch (cubeMapFace)
+ {
+ case CubeMapFace::all: return texD3D11.GetRTV(index); break;
+ case CubeMapFace::none: return texD3D11.GetRTV(); break;
+ default: return texD3D11.GetRTV(!index ? +cubeMapFace : 0);
+ }
+ }
+ };
+ auto GetDSV = [this, &vTex, swapChainBufferIndex](int index, bool depthStencilReadOnly) -> ID3D11DepthStencilView*
+ {
+ if (swapChainBufferIndex >= 0)
+ {
+ if (index)
+ {
+ auto& texD3D11 = static_cast(*vTex[index - 1]);
+ return texD3D11.GetDSV(depthStencilReadOnly);
+ }
+ else
+ {
+ VERUS_RT_ASSERT("Using swapChainBufferIndex for DSV");
+ return nullptr;
+ }
+ }
+ else
+ {
+ auto& texD3D11 = static_cast(*vTex[index]);
+ return texD3D11.GetDSV(depthStencilReadOnly);
+ }
+ };
+
+ VERUS_FOR(i, renderPass._vAttachments.size())
+ {
+ if (!i && -1 == swapChainBufferIndex)
+ framebuffer._mipLevels = vTex.front()->GetMipLevelCount();
+ }
+
+ framebuffer._vSubpasses.reserve(renderPass._vSubpasses.size());
+ for (const auto& subpass : renderPass._vSubpasses)
+ {
+ RP::D3DFramebufferSubpass fs;
+
+ if (!subpass._vColor.empty())
+ {
+ fs._vRTVs.resize(subpass._vColor.size());
+ int index = 0;
+ for (const auto& ref : subpass._vColor)
+ {
+ fs._vRTVs[index] = GetRTV(ref._index);
+ index++;
+ }
+ }
+ if (subpass._depthStencil._index >= 0)
+ {
+ fs._pDSV = GetDSV(subpass._depthStencil._index, subpass._depthStencilReadOnly);
+ }
+
+ framebuffer._vSubpasses.push_back(std::move(fs));
+ }
+
+ const int nextIndex = GetNextFramebufferIndex();
+ if (nextIndex >= _vFramebuffers.size())
+ _vFramebuffers.push_back(std::move(framebuffer));
+ else
+ _vFramebuffers[nextIndex] = framebuffer;
+
+ return FBHandle::Make(nextIndex);
+}
+
+void RendererD3D11::DeleteRenderPass(RPHandle handle)
+{
+ if (handle.IsSet())
+ _vRenderPasses[handle.Get()] = RP::D3DRenderPass();
+ else if (-2 == handle.Get())
+ _vRenderPasses.clear();
+}
+
+void RendererD3D11::DeleteFramebuffer(FBHandle handle)
+{
+ if (handle.IsSet())
+ _vFramebuffers[handle.Get()] = RP::D3DFramebuffer();
+ else if (-2 == handle.Get())
+ _vFramebuffers.clear();
+}
+
+int RendererD3D11::GetNextRenderPassIndex() const
+{
+ const int count = Utils::Cast32(_vRenderPasses.size());
+ VERUS_FOR(i, count)
+ {
+ if (_vRenderPasses[i]._vSubpasses.empty())
+ return i;
+ }
+ return count;
+}
+
+int RendererD3D11::GetNextFramebufferIndex() const
+{
+ const int count = Utils::Cast32(_vFramebuffers.size());
+ VERUS_FOR(i, count)
+ {
+ if (_vFramebuffers[i]._vSubpasses.empty())
+ return i;
+ }
+ return count;
+}
+
+RP::RcD3DRenderPass RendererD3D11::GetRenderPass(RPHandle handle) const
+{
+ return _vRenderPasses[handle.Get()];
+}
+
+RP::RcD3DFramebuffer RendererD3D11::GetFramebuffer(FBHandle handle) const
+{
+ return _vFramebuffers[handle.Get()];
+}
diff --git a/RendererDirect3D11/src/CGI/RendererD3D11.h b/RendererDirect3D11/src/CGI/RendererD3D11.h
new file mode 100644
index 0000000..4feeb58
--- /dev/null
+++ b/RendererDirect3D11/src/CGI/RendererD3D11.h
@@ -0,0 +1,96 @@
+// Copyright (C) 2021-2022, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
+#pragma once
+
+namespace verus
+{
+ namespace CGI
+ {
+ typedef Store TStoreCommandBuffers;
+ typedef Store TStoreGeometry;
+ typedef Store TStorePipelines;
+ typedef Store TStoreShaders;
+ typedef Store TStoreTextures;
+ class RendererD3D11 : public Singleton, public BaseRenderer,
+ private TStoreCommandBuffers, private TStoreGeometry, private TStorePipelines, private TStoreShaders, private TStoreTextures
+ {
+ ComPtr _pDevice;
+ ComPtr _pDeviceContext;
+ ComPtr _pSwapChain;
+ ComPtr _pSwapChainBuffer;
+ ComPtr _pSwapChainBufferRTV;
+
+ Vector> _vSamplers;
+ Vector _vRenderPasses;
+ Vector _vFramebuffers;
+ D3D_FEATURE_LEVEL _featureLevel = D3D_FEATURE_LEVEL_11_0;
+ DXGI_SWAP_CHAIN_DESC _swapChainDesc = {};
+
+ public:
+ RendererD3D11();
+ ~RendererD3D11();
+
+ virtual void ReleaseMe() override;
+
+ void Init();
+ void Done();
+
+ private:
+ static ComPtr CreateFactory();
+ static ComPtr GetAdapter(ComPtr pFactory);
+ void CreateSwapChainBufferRTV();
+ void InitD3D();
+
+ public:
+ //
+ void CreateSamplers();
+
+ ID3D11Device* GetD3DDevice() const { return _pDevice.Get(); }
+ ID3D11DeviceContext* GetD3DDeviceContext() const { return _pDeviceContext.Get(); }
+ ID3D11SamplerState* GetD3DSamplerState(Sampler s) const;
+ //
+
+ virtual void ImGuiInit(RPHandle renderPassHandle) override;
+ virtual void ImGuiRenderDrawData() override;
+
+ virtual void ResizeSwapChain() override;
+
+ // Which graphics API?
+ virtual Gapi GetGapi() override { return Gapi::direct3D11; }
+
+ //
+ virtual void BeginFrame() override;
+ virtual void AcquireSwapChainImage() override;
+ virtual void EndFrame() override;
+ virtual void WaitIdle() override;
+ virtual void OnMinimized() override;
+ //
+
+ //
+ virtual PBaseCommandBuffer InsertCommandBuffer() override;
+ virtual PBaseGeometry InsertGeometry() override;
+ virtual PBasePipeline InsertPipeline() override;
+ virtual PBaseShader InsertShader() override;
+ virtual PBaseTexture InsertTexture() override;
+
+ virtual void DeleteCommandBuffer(PBaseCommandBuffer p) override;
+ virtual void DeleteGeometry(PBaseGeometry p) override;
+ virtual void DeletePipeline(PBasePipeline p) override;
+ virtual void DeleteShader(PBaseShader p) override;
+ virtual void DeleteTexture(PBaseTexture p) override;
+
+ virtual RPHandle CreateRenderPass(std::initializer_list ilA, std::initializer_list ilS, std::initializer_list ilD) override;
+ virtual FBHandle CreateFramebuffer(RPHandle renderPassHandle, std::initializer_list il, int w, int h,
+ int swapChainBufferIndex = -1, CubeMapFace cubeMapFace = CubeMapFace::none) override;
+ virtual void DeleteRenderPass(RPHandle handle) override;
+ virtual void DeleteFramebuffer(FBHandle handle) override;
+ int GetNextRenderPassIndex() const;
+ int GetNextFramebufferIndex() const;
+ RP::RcD3DRenderPass GetRenderPass(RPHandle handle) const;
+ RP::RcD3DFramebuffer GetFramebuffer(FBHandle handle) const;
+ //
+ };
+ VERUS_TYPEDEFS(RendererD3D11);
+ }
+}
+
+#define VERUS_QREF_RENDERER_D3D11 CGI::PRendererD3D11 pRendererD3D11 = CGI::RendererD3D11::P()
diff --git a/RendererDirect3D11/src/CGI/ShaderD3D11.cpp b/RendererDirect3D11/src/CGI/ShaderD3D11.cpp
new file mode 100644
index 0000000..be100b2
--- /dev/null
+++ b/RendererDirect3D11/src/CGI/ShaderD3D11.cpp
@@ -0,0 +1,394 @@
+// Copyright (C) 2021-2022, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
+#include "pch.h"
+
+using namespace verus;
+using namespace verus::CGI;
+
+// ShaderInclude:
+
+HRESULT STDMETHODCALLTYPE ShaderInclude::Open(
+ D3D_INCLUDE_TYPE IncludeType,
+ LPCSTR pFileName,
+ LPCVOID pParentData,
+ LPCVOID* ppData,
+ UINT* pBytes)
+{
+ const String url = String("[Shaders]:") + pFileName;
+ Vector vData;
+ IO::FileSystem::LoadResource(_C(url), vData);
+ char* p = new char[vData.size()];
+ memcpy(p, vData.data(), vData.size());
+ *pBytes = Utils::Cast32(vData.size());
+ *ppData = p;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE ShaderInclude::Close(LPCVOID pData)
+{
+ delete[] pData;
+ return S_OK;
+}
+
+// ShaderD3D11:
+
+ShaderD3D11::ShaderD3D11()
+{
+}
+
+ShaderD3D11::~ShaderD3D11()
+{
+ Done();
+}
+
+void ShaderD3D11::Init(CSZ source, CSZ sourceName, CSZ* branches)
+{
+ VERUS_INIT();
+ VERUS_QREF_CONST_SETTINGS;
+ HRESULT hr = 0;
+
+ _sourceName = sourceName;
+ const size_t len = strlen(source);
+ ShaderInclude inc;
+ const String version = "5_0";
+#ifdef _DEBUG
+ const UINT flags = D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_WARNINGS_ARE_ERRORS | D3DCOMPILE_ALL_RESOURCES_BOUND | D3DCOMPILE_OPTIMIZATION_LEVEL1 | D3DCOMPILE_DEBUG;
+#else
+ const UINT flags = D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_WARNINGS_ARE_ERRORS | D3DCOMPILE_ALL_RESOURCES_BOUND | D3DCOMPILE_OPTIMIZATION_LEVEL3;
+#endif
+ ComPtr pErrorMsgs;
+ ComPtr pBlob;
+
+ auto CheckErrorMsgs = [this](ComPtr& pErrorMsgs)
+ {
+ if (pErrorMsgs)
+ {
+ OnError(static_cast(pErrorMsgs->GetBufferPointer()));
+ pErrorMsgs.Reset();
+ }
+ };
+
+ while (*branches)
+ {
+ String entry, stageEntries[+Stage::count], stages;
+ Vector vMacroName;
+ Vector vMacroValue;
+ const String branch = Parse(*branches, entry, stageEntries, stages, vMacroName, vMacroValue, "DEF_");
+
+ if (IsInIgnoreList(_C(branch)))
+ {
+ branches++;
+ continue;
+ }
+
+ //
+ Vector vDefines;
+ vDefines.reserve(20);
+ const int count = Utils::Cast32(vMacroName.size());
+ VERUS_FOR(i, count)
+ {
+ D3D_SHADER_MACRO sm;
+ sm.Name = _C(vMacroName[i]);
+ sm.Definition = _C(vMacroValue[i]);
+ vDefines.push_back(sm);
+ }
+ //
+
+ //
+ char defAnisotropyLevel[64] = {};
+ {
+ sprintf_s(defAnisotropyLevel, "%d", settings._gpuAnisotropyLevel);
+ vDefines.push_back({ "_ANISOTROPY_LEVEL", defAnisotropyLevel });
+ }
+ char defShaderQuality[64] = {};
+ {
+ sprintf_s(defShaderQuality, "%d", settings._gpuShaderQuality);
+ vDefines.push_back({ "_SHADER_QUALITY", defShaderQuality });
+ }
+ char defShadowQuality[64] = {};
+ {
+ sprintf_s(defShadowQuality, "%d", settings._sceneShadowQuality);
+ vDefines.push_back({ "_SHADOW_QUALITY", defShadowQuality });
+ }
+ char defWaterQuality[64] = {};
+ {
+ sprintf_s(defWaterQuality, "%d", settings._sceneWaterQuality);
+ vDefines.push_back({ "_WATER_QUALITY", defWaterQuality });
+ }
+ char defMaxNumBones[64] = {};
+ {
+ sprintf_s(defMaxNumBones, "%d", VERUS_MAX_BONES);
+ vDefines.push_back({ "VERUS_MAX_BONES", defMaxNumBones });
+ }
+ vDefines.push_back({ "_DIRECT3D", "1" });
+ vDefines.push_back({ "_DIRECT3D11", "1" });
+ const int typeIndex = Utils::Cast32(vDefines.size());
+ vDefines.push_back({ "_XS", "1" });
+ vDefines.push_back({});
+ //
+
+ Compiled compiled;
+ compiled._entry = entry;
+
+ if (strchr(_C(stages), 'V'))
+ {
+ compiled._stageCount++;
+ vDefines[typeIndex].Name = "_VS";
+ hr = D3DCompile(source, len, sourceName, vDefines.data(), &inc, _C(stageEntries[+Stage::vs]), _C("vs_" + version), flags, 0, &compiled._pBlobs[+Stage::vs], &pErrorMsgs);
+ CheckErrorMsgs(pErrorMsgs);
+ }
+
+ if (strchr(_C(stages), 'H'))
+ {
+ compiled._stageCount++;
+ vDefines[typeIndex].Name = "_HS";
+ hr = D3DCompile(source, len, sourceName, vDefines.data(), &inc, _C(stageEntries[+Stage::hs]), _C("hs_" + version), flags, 0, &compiled._pBlobs[+Stage::hs], &pErrorMsgs);
+ CheckErrorMsgs(pErrorMsgs);
+ }
+
+ if (strchr(_C(stages), 'D'))
+ {
+ compiled._stageCount++;
+ vDefines[typeIndex].Name = "_DS";
+ hr = D3DCompile(source, len, sourceName, vDefines.data(), &inc, _C(stageEntries[+Stage::ds]), _C("ds_" + version), flags, 0, &compiled._pBlobs[+Stage::ds], &pErrorMsgs);
+ CheckErrorMsgs(pErrorMsgs);
+ }
+
+ if (strchr(_C(stages), 'G'))
+ {
+ compiled._stageCount++;
+ vDefines[typeIndex].Name = "_GS";
+ hr = D3DCompile(source, len, sourceName, vDefines.data(), &inc, _C(stageEntries[+Stage::gs]), _C("gs_" + version), flags, 0, &compiled._pBlobs[+Stage::gs], &pErrorMsgs);
+ CheckErrorMsgs(pErrorMsgs);
+ }
+
+ if (strchr(_C(stages), 'F'))
+ {
+ compiled._stageCount++;
+ vDefines[typeIndex].Name = "_FS";
+ hr = D3DCompile(source, len, sourceName, vDefines.data(), &inc, _C(stageEntries[+Stage::fs]), _C("ps_" + version), flags, 0, &compiled._pBlobs[+Stage::fs], &pErrorMsgs);
+ CheckErrorMsgs(pErrorMsgs);
+ }
+
+ if (strchr(_C(stages), 'C'))
+ {
+ compiled._stageCount++;
+ vDefines[typeIndex].Name = "_CS";
+ hr = D3DCompile(source, len, sourceName, vDefines.data(), &inc, _C(stageEntries[+Stage::cs]), _C("cs_" + version), flags, 0, &compiled._pBlobs[+Stage::cs], &pErrorMsgs);
+ CheckErrorMsgs(pErrorMsgs);
+ _compute = true;
+ }
+
+ _mapCompiled[branch] = compiled;
+
+ branches++;
+ }
+
+ _vDescriptorSetDesc.reserve(4);
+}
+
+void ShaderD3D11::Done()
+{
+ for (auto& dsd : _vDescriptorSetDesc)
+ dsd._pConstantBuffer.Reset();
+
+ for (auto& x : _mapCompiled)
+ {
+ VERUS_FOR(i, +Stage::count)
+ x.second._pBlobs[i].Reset();
+ }
+
+ VERUS_DONE(ShaderD3D11);
+}
+
+void ShaderD3D11::CreateDescriptorSet(int setNumber, const void* pSrc, int size, int capacity, std::initializer_list il, ShaderStageFlags stageFlags)
+{
+ VERUS_QREF_RENDERER_D3D11;
+ VERUS_RT_ASSERT(_vDescriptorSetDesc.size() == setNumber);
+ VERUS_RT_ASSERT(!(reinterpret_cast(pSrc) & 0xF));
+ HRESULT hr = 0;
+
+ DescriptorSetDesc dsd;
+ dsd._vSamplers.assign(il);
+ dsd._pSrc = pSrc;
+ dsd._size = size;
+ dsd._alignedSize = size;
+ dsd._capacity = 1;
+ dsd._capacityInBytes = dsd._alignedSize * dsd._capacity;
+ dsd._stageFlags = stageFlags;
+
+ dsd._srvCount = 0;
+ dsd._uavCount = 0;
+ for (const auto& sampler : dsd._vSamplers)
+ {
+ if (Sampler::storage == sampler)
+ dsd._uavCount++;
+ else
+ dsd._srvCount++;
+ }
+ dsd._srvStartSlot = 0;
+ dsd._uavStartSlot = 0;
+ for (const auto& prevDsd : _vDescriptorSetDesc)
+ {
+ dsd._srvStartSlot += prevDsd._srvCount;
+ dsd._uavStartSlot += prevDsd._uavCount;
+ }
+
+ D3D11_BUFFER_DESC bDesc = {};
+ bDesc.ByteWidth = dsd._capacityInBytes;
+ bDesc.Usage = D3D11_USAGE_DYNAMIC;
+ bDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
+ bDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ if (FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateBuffer(&bDesc, 0, &dsd._pConstantBuffer)))
+ throw VERUS_RUNTIME_ERROR << "CreateBuffer(D3D11_BIND_CONSTANT_BUFFER); hr=" << VERUS_HR(hr);
+ SetDebugObjectName(dsd._pConstantBuffer.Get(), _C("Shader.ConstantBuffer (" + _sourceName + ", set=" + std::to_string(setNumber) + ")"));
+
+ _vDescriptorSetDesc.push_back(dsd);
+}
+
+void ShaderD3D11::CreatePipelineLayout()
+{
+ // Everything is awesome, everything is cool...
+}
+
+CSHandle ShaderD3D11::BindDescriptorSetTextures(int setNumber, std::initializer_list il, const int* pMipLevels, const int* pArrayLayers)
+{
+ VERUS_QREF_RENDERER_D3D11;
+
+ //
+ int complexSetHandle = -1;
+ VERUS_FOR(i, _vComplexSets.size())
+ {
+ if (_vComplexSets[i]._vTextures.empty())
+ {
+ complexSetHandle = i;
+ break;
+ }
+ }
+ if (-1 == complexSetHandle)
+ {
+ complexSetHandle = Utils::Cast32(_vComplexSets.size());
+ _vComplexSets.resize(complexSetHandle + 1);
+ }
+ //
+
+ const auto& dsd = _vDescriptorSetDesc[setNumber];
+ VERUS_RT_ASSERT(dsd._vSamplers.size() == il.size());
+
+ RComplexSet complexSet = _vComplexSets[complexSetHandle];
+ complexSet._vTextures.reserve(il.size());
+ complexSet._vSRVs.reserve(dsd._srvCount);
+ complexSet._vUAVs.reserve(dsd._uavCount);
+ int index = 0;
+ for (const auto x : il)
+ {
+ complexSet._vTextures.push_back(x);
+ const int mipLevelCount = x->GetMipLevelCount();
+ const int mipLevel = pMipLevels ? pMipLevels[index] : 0;
+ const int arrayLayer = pArrayLayers ? pArrayLayers[index] : 0;
+ const auto& texD3D11 = static_cast(*x);
+ if (Sampler::storage == dsd._vSamplers[index])
+ complexSet._vUAVs.push_back(mipLevel >= 0 ? texD3D11.GetUAV(mipLevel + arrayLayer * (mipLevelCount - 1)) : nullptr);
+ else
+ complexSet._vSRVs.push_back(texD3D11.GetSRV());
+ index++;
+ }
+
+ return CSHandle::Make(complexSetHandle);
+}
+
+void ShaderD3D11::FreeDescriptorSet(CSHandle& complexSetHandle)
+{
+ if (complexSetHandle.IsSet() && complexSetHandle.Get() < _vComplexSets.size())
+ {
+ auto& complexSet = _vComplexSets[complexSetHandle.Get()];
+ complexSet._vTextures.clear();
+ complexSet._vSRVs.clear();
+ complexSet._vUAVs.clear();
+ }
+ complexSetHandle = CSHandle();
+}
+
+void ShaderD3D11::BeginBindDescriptors()
+{
+ // Map/Unmap is done per each update.
+}
+
+void ShaderD3D11::EndBindDescriptors()
+{
+}
+
+ID3D11Buffer* ShaderD3D11::UpdateUniformBuffer(int setNumber, ShaderStageFlags& stageFlags)
+{
+ VERUS_QREF_RENDERER_D3D11;
+ HRESULT hr = 0;
+
+ const auto& dsd = _vDescriptorSetDesc[setNumber];
+
+ D3D11_MAPPED_SUBRESOURCE ms;
+ if (FAILED(hr = pRendererD3D11->GetD3DDeviceContext()->Map(dsd._pConstantBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &ms)))
+ throw VERUS_RUNTIME_ERROR << "Map(); hr=" << VERUS_HR(hr);
+ memcpy(ms.pData, dsd._pSrc, dsd._size);
+ pRendererD3D11->GetD3DDeviceContext()->Unmap(dsd._pConstantBuffer.Get(), 0);
+
+ stageFlags = dsd._stageFlags;
+
+ return dsd._pConstantBuffer.Get();
+}
+
+void ShaderD3D11::GetShaderResources(int setNumber, int complexSetHandle, RShaderResources shaderResources)
+{
+ if (complexSetHandle >= 0)
+ {
+ const auto& dsd = _vDescriptorSetDesc[setNumber];
+ const auto& complexSet = _vComplexSets[complexSetHandle];
+ shaderResources._srvCount = dsd._srvCount;
+ shaderResources._uavCount = dsd._uavCount;
+ shaderResources._srvStartSlot = dsd._srvStartSlot;
+ shaderResources._uavStartSlot = dsd._uavStartSlot;
+ if (shaderResources._srvCount)
+ memcpy(shaderResources._srvs, complexSet._vSRVs.data(), shaderResources._srvCount * sizeof(ID3D11ShaderResourceView*));
+ if (shaderResources._uavCount)
+ memcpy(shaderResources._uavs, complexSet._vUAVs.data(), shaderResources._uavCount * sizeof(ID3D11UnorderedAccessView*));
+ }
+}
+
+void ShaderD3D11::GetSamplers(int setNumber, int complexSetHandle, RShaderResources shaderResources)
+{
+ VERUS_QREF_RENDERER_D3D11;
+
+ const auto& dsd = _vDescriptorSetDesc[setNumber];
+ VERUS_FOR(i, dsd._vSamplers.size())
+ {
+ if (Sampler::custom == dsd._vSamplers[i])
+ {
+ VERUS_RT_ASSERT(complexSetHandle >= 0);
+ const auto& complexSet = _vComplexSets[complexSetHandle];
+ const auto& texD3D11 = static_cast(*complexSet._vTextures[i]);
+ shaderResources._samplers[i] = texD3D11.GetD3DSamplerState();
+ }
+ else if (Sampler::input == dsd._vSamplers[i])
+ {
+ shaderResources._samplers[i] = pRendererD3D11->GetD3DSamplerState(Sampler::nearestClampMipN);
+ }
+ else
+ {
+ shaderResources._samplers[i] = pRendererD3D11->GetD3DSamplerState(dsd._vSamplers[i]);
+ }
+ }
+}
+
+void ShaderD3D11::OnError(CSZ s)
+{
+ VERUS_QREF_RENDERER;
+
+ if (strstr(s, "HS': entrypoint not found"))
+ return;
+ if (strstr(s, "DS': entrypoint not found"))
+ return;
+ if (strstr(s, "GS': entrypoint not found"))
+ return;
+ if (strstr(s, "error X"))
+ renderer.OnShaderError(s);
+ else
+ renderer.OnShaderWarning(s);
+}
diff --git a/RendererDirect3D11/src/CGI/ShaderD3D11.h b/RendererDirect3D11/src/CGI/ShaderD3D11.h
new file mode 100644
index 0000000..9f72c9e
--- /dev/null
+++ b/RendererDirect3D11/src/CGI/ShaderD3D11.h
@@ -0,0 +1,107 @@
+// Copyright (C) 2021-2022, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
+#pragma once
+
+namespace verus
+{
+ namespace CGI
+ {
+ struct ShaderInclude : public ID3DInclude
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Open(
+ D3D_INCLUDE_TYPE IncludeType,
+ LPCSTR pFileName,
+ LPCVOID pParentData,
+ LPCVOID* ppData,
+ UINT* pBytes) override;
+ virtual HRESULT STDMETHODCALLTYPE Close(LPCVOID pData) override;
+ };
+ VERUS_TYPEDEFS(ShaderInclude);
+
+ struct ShaderResources
+ {
+ UINT _srvCount = 0;
+ UINT _uavCount = 0;
+ UINT _srvStartSlot = 0;
+ UINT _uavStartSlot = 0;
+ ID3D11ShaderResourceView* _srvs[VERUS_MAX_FB_ATTACH];
+ ID3D11UnorderedAccessView* _uavs[VERUS_MAX_FB_ATTACH];
+ ID3D11SamplerState* _samplers[VERUS_MAX_FB_ATTACH];
+ };
+ VERUS_TYPEDEFS(ShaderResources);
+
+ class ShaderD3D11 : public BaseShader
+ {
+ public:
+ struct Compiled
+ {
+ ComPtr _pBlobs[+Stage::count];
+ String _entry;
+ int _stageCount = 0;
+ };
+ VERUS_TYPEDEFS(Compiled);
+
+ private:
+ typedef Map TMapCompiled;
+
+ struct DescriptorSetDesc
+ {
+ Vector _vSamplers;
+ ComPtr _pConstantBuffer;
+ const void* _pSrc = nullptr;
+ int _size = 0;
+ int _alignedSize = 0;
+ int _capacity = 1;
+ int _capacityInBytes = 0;
+ UINT _srvCount = 0;
+ UINT _uavCount = 0;
+ UINT _srvStartSlot = 0;
+ UINT _uavStartSlot = 0;
+ ShaderStageFlags _stageFlags = ShaderStageFlags::vs_fs;
+ };
+
+ struct ComplexSet
+ {
+ Vector _vTextures;
+ Vector _vSRVs;
+ Vector _vUAVs;
+ };
+ VERUS_TYPEDEFS(ComplexSet);
+
+ TMapCompiled _mapCompiled;
+ Vector _vDescriptorSetDesc;
+ Vector _vComplexSets;
+ bool _compute = false;
+
+ public:
+ ShaderD3D11();
+ virtual ~ShaderD3D11() override;
+
+ virtual void Init(CSZ source, CSZ sourceName, CSZ* branches) override;
+ virtual void Done() override;
+
+ virtual void CreateDescriptorSet(int setNumber, const void* pSrc, int size, int capacity, std::initializer_list il, ShaderStageFlags stageFlags) override;
+ virtual void CreatePipelineLayout() override;
+ virtual CSHandle BindDescriptorSetTextures(int setNumber, std::initializer_list il, const int* pMipLevels, const int* pArrayLayers) override;
+ virtual void FreeDescriptorSet(CSHandle& complexSetHandle) override;
+
+ virtual void BeginBindDescriptors() override;
+ virtual void EndBindDescriptors() override;
+
+ //
+ // D3D11
+ //
+
+ RcCompiled GetCompiled(CSZ branch) const { return _mapCompiled.at(branch); }
+
+ ID3D11Buffer* UpdateUniformBuffer(int setNumber, ShaderStageFlags& stageFlags);
+ void GetShaderResources(int setNumber, int complexSetHandle, RShaderResources shaderResources);
+ void GetSamplers(int setNumber, int complexSetHandle, RShaderResources shaderResources);
+ int GetDescriptorSetCount() const { return static_cast(_vDescriptorSetDesc.size()); }
+ bool IsCompute() const { return _compute; }
+
+ void OnError(CSZ s);
+ };
+ VERUS_TYPEDEFS(ShaderD3D11);
+ }
+}
diff --git a/RendererDirect3D11/src/CGI/TextureD3D11.cpp b/RendererDirect3D11/src/CGI/TextureD3D11.cpp
new file mode 100644
index 0000000..15a0d16
--- /dev/null
+++ b/RendererDirect3D11/src/CGI/TextureD3D11.cpp
@@ -0,0 +1,578 @@
+// Copyright (C) 2021-2022, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
+#include "pch.h"
+
+using namespace verus;
+using namespace verus::CGI;
+
+TextureD3D11::TextureD3D11()
+{
+}
+
+TextureD3D11::~TextureD3D11()
+{
+ Done();
+}
+
+void TextureD3D11::Init(RcTextureDesc desc)
+{
+ VERUS_INIT();
+ VERUS_RT_ASSERT(desc._width > 0 && desc._height > 0);
+ VERUS_QREF_RENDERER;
+ VERUS_QREF_RENDERER_D3D11;
+ HRESULT hr = 0;
+
+ // Variables:
+ _size = Vector4(
+ float(desc._width),
+ float(desc._height),
+ 1.f / desc._width,
+ 1.f / desc._height);
+ if (desc._name)
+ _name = desc._name;
+ _desc = desc;
+ _initAtFrame = renderer.GetFrameCount();
+ if (desc._flags & TextureDesc::Flags::anyShaderResource)
+ _mainLayout = ImageLayout::xsReadOnly;
+ _bytesPerPixel = FormatToBytesPerPixel(desc._format);
+
+ _desc._mipLevels = _desc._mipLevels ? _desc._mipLevels : Math::ComputeMipLevels(_desc._width, _desc._height, _desc._depth);
+ const bool renderTarget = (_desc._flags & TextureDesc::Flags::colorAttachment);
+ const bool depthFormat = IsDepthFormat(_desc._format);
+ const bool depthSampled = _desc._flags & (TextureDesc::Flags::depthSampledR | TextureDesc::Flags::depthSampledW);
+ const bool cubeMap = (_desc._flags & TextureDesc::Flags::cubeMap);
+ if (cubeMap)
+ _desc._arrayLayers *= +CubeMapFace::count;
+
+ // Create:
+ D3D11_TEXTURE2D_DESC tex2DDesc = {};
+ tex2DDesc.Width = _desc._width;
+ tex2DDesc.Height = _desc._height;
+ tex2DDesc.MipLevels = _desc._mipLevels;
+ tex2DDesc.ArraySize = _desc._arrayLayers;
+ tex2DDesc.Format = ToNativeFormat(_desc._format, depthSampled);
+ tex2DDesc.SampleDesc.Count = _desc._sampleCount;
+ tex2DDesc.Usage = D3D11_USAGE_DEFAULT;
+ tex2DDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+ tex2DDesc.CPUAccessFlags = 0;
+ tex2DDesc.MiscFlags = 0;
+ if (renderTarget)
+ tex2DDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
+ if (depthFormat)
+ {
+ tex2DDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
+ if (depthSampled)
+ tex2DDesc.BindFlags |= D3D11_BIND_SHADER_RESOURCE;
+ }
+ if (cubeMap)
+ tex2DDesc.MiscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE;
+
+ D3D11_TEXTURE3D_DESC tex3DDesc = {};
+ tex3DDesc.Width = tex2DDesc.Width;
+ tex3DDesc.Height = tex2DDesc.Height;
+ tex3DDesc.Depth = _desc._depth;
+ tex3DDesc.MipLevels = tex2DDesc.MipLevels;
+ tex3DDesc.Format = tex2DDesc.Format;
+ tex3DDesc.Usage = tex2DDesc.Usage;
+ tex3DDesc.BindFlags = tex2DDesc.BindFlags;
+ tex3DDesc.CPUAccessFlags = tex2DDesc.CPUAccessFlags;
+ tex3DDesc.MiscFlags = tex2DDesc.MiscFlags;
+
+ if (_desc._depth > 1)
+ {
+ if (FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateTexture3D(&tex3DDesc, nullptr, &_pTexture3D)))
+ throw VERUS_RUNTIME_ERROR << "CreateTexture3D(); hr=" << VERUS_HR(hr);
+ SetDebugObjectName(_pTexture3D.Get(), _C(_name));
+ }
+ else
+ {
+ if (FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateTexture2D(&tex2DDesc, nullptr, &_pTexture2D)))
+ throw VERUS_RUNTIME_ERROR << "CreateTexture2D(); hr=" << VERUS_HR(hr);
+ SetDebugObjectName(_pTexture2D.Get(), _C(_name));
+ }
+
+ // Optional mipmap:
+ if (_desc._flags & TextureDesc::Flags::generateMips)
+ {
+ VERUS_RT_ASSERT(_desc._mipLevels > 1);
+ // Create storage image for compute shader. First mip level is not required.
+ const int uaMipLevels = Math::Max(1, _desc._mipLevels - 1);
+ D3D11_TEXTURE2D_DESC uaTexDesc = tex2DDesc;
+ uaTexDesc.Width = Math::Max(1, _desc._width >> 1);
+ uaTexDesc.Height = Math::Max(1, _desc._height >> 1);
+ uaTexDesc.MipLevels = uaMipLevels;
+ uaTexDesc.BindFlags = D3D11_BIND_UNORDERED_ACCESS;
+ // sRGB cannot be used with UAV:
+ switch (uaTexDesc.Format)
+ {
+ case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: uaTexDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; break;
+ case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: uaTexDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; break;
+ }
+
+ if (FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateTexture2D(&uaTexDesc, nullptr, &_pUaTexture)))
+ throw VERUS_RUNTIME_ERROR << "CreateTexture2D(UAV); hr=" << VERUS_HR(hr);
+ SetDebugObjectName(_pUaTexture.Get(), _C(_name + " (UAV)"));
+
+ _vCshGenerateMips.reserve(Math::DivideByMultiple(_desc._mipLevels, 4));
+ _vUAVs.resize(uaMipLevels * _desc._arrayLayers);
+ D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
+ uavDesc.Format = uaTexDesc.Format;
+ uavDesc.ViewDimension = (_desc._arrayLayers > 1) ? D3D11_UAV_DIMENSION_TEXTURE2DARRAY : D3D11_UAV_DIMENSION_TEXTURE2D;
+ VERUS_FOR(layer, _desc._arrayLayers)
+ {
+ VERUS_FOR(mip, uaMipLevels)
+ {
+ if (D3D11_UAV_DIMENSION_TEXTURE2D == uavDesc.ViewDimension)
+ {
+ uavDesc.Texture2D.MipSlice = mip;
+ if (FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateUnorderedAccessView(_pUaTexture.Get(), &uavDesc, &_vUAVs[mip])))
+ throw VERUS_RUNTIME_ERROR << "CreateUnorderedAccessView(TEXTURE2D); hr=" << VERUS_HR(hr);
+ }
+ else
+ {
+ uavDesc.Texture2DArray.MipSlice = mip;
+ uavDesc.Texture2DArray.FirstArraySlice = layer;
+ uavDesc.Texture2DArray.ArraySize = 1;
+ if (cubeMap)
+ {
+ const int cubeIndex = layer / +CubeMapFace::count;
+ const int faceIndex = layer % +CubeMapFace::count;
+ uavDesc.Texture2DArray.FirstArraySlice = (cubeIndex * +CubeMapFace::count) + ToNativeCubeMapFace(static_cast(faceIndex));
+ }
+ if (FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateUnorderedAccessView(_pUaTexture.Get(), &uavDesc, &_vUAVs[mip + layer * uaMipLevels])))
+ throw VERUS_RUNTIME_ERROR << "CreateUnorderedAccessView(TEXTURE2DARRAY); hr=" << VERUS_HR(hr);
+ }
+ }
+ }
+ }
+
+ // Optional readback texture:
+ if (_desc._readbackMip != SHRT_MAX)
+ {
+ if (_desc._readbackMip < 0)
+ _desc._readbackMip = _desc._mipLevels + _desc._readbackMip;
+ const int w = Math::Max(1, _desc._width >> _desc._readbackMip);
+ const int h = Math::Max(1, _desc._height >> _desc._readbackMip);
+ _vReadbackTextures.resize(BaseRenderer::s_ringBufferSize);
+ for (auto& readbackTexture : _vReadbackTextures)
+ {
+ D3D11_TEXTURE2D_DESC texDesc = {};
+ texDesc.Width = w;
+ texDesc.Height = h;
+ texDesc.MipLevels = 1;
+ texDesc.ArraySize = 1;
+ texDesc.Format = ToNativeFormat(_desc._format, false);
+ texDesc.SampleDesc.Count = 1;
+ texDesc.Usage = D3D11_USAGE_STAGING;
+ texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
+ if (FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateTexture2D(&texDesc, nullptr, &readbackTexture)))
+ throw VERUS_RUNTIME_ERROR << "CreateTexture2D(Readback); hr=" << VERUS_HR(hr);
+ SetDebugObjectName(readbackTexture.Get(), _C(_name + " (Readback)"));
+ }
+ }
+
+ // Create views:
+ if (renderTarget)
+ {
+ if (cubeMap)
+ {
+ _vRTVs.resize(+CubeMapFace::count);
+ D3D11_RENDER_TARGET_VIEW_DESC rtvDesc = {};
+ rtvDesc.Format = ToNativeFormat(_desc._format, false);
+ rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
+ VERUS_FOR(i, +CubeMapFace::count)
+ {
+ rtvDesc.Texture2DArray.FirstArraySlice = ToNativeCubeMapFace(static_cast(i));
+ rtvDesc.Texture2DArray.ArraySize = 1;
+ if (FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateRenderTargetView(GetD3DResource(), &rtvDesc, &_vRTVs[i])))
+ throw VERUS_RUNTIME_ERROR << "CreateRenderTargetView(cubeMap); hr=" << VERUS_HR(hr);
+ }
+ }
+ else
+ {
+ _vRTVs.resize(1);
+ if (FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateRenderTargetView(GetD3DResource(), nullptr, &_vRTVs[0])))
+ throw VERUS_RUNTIME_ERROR << "CreateRenderTargetView(); hr=" << VERUS_HR(hr);
+ }
+ }
+ if (depthFormat)
+ {
+ D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
+ dsvDesc.Format = ToNativeFormat(_desc._format, false);
+ dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
+ if (FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateDepthStencilView(GetD3DResource(), &dsvDesc, &_pDSV[0])))
+ throw VERUS_RUNTIME_ERROR << "CreateDepthStencilView(); hr=" << VERUS_HR(hr);
+ dsvDesc.Flags = D3D11_DSV_READ_ONLY_DEPTH | D3D11_DSV_READ_ONLY_STENCIL;
+ if (FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateDepthStencilView(GetD3DResource(), &dsvDesc, &_pDSV[1])))
+ throw VERUS_RUNTIME_ERROR << "CreateDepthStencilView(READ_ONLY); hr=" << VERUS_HR(hr);
+ if (depthSampled)
+ {
+ D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
+ srvDesc.Format = ToNativeSampledDepthFormat(_desc._format);
+ srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+ srvDesc.Texture2D.MipLevels = 1;
+ if (FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateShaderResourceView(GetD3DResource(), &srvDesc, &_pSRV)))
+ throw VERUS_RUNTIME_ERROR << "CreateShaderResourceView(depthSampled); hr=" << VERUS_HR(hr);
+ }
+ }
+ else
+ {
+ if (cubeMap)
+ {
+ D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
+ srvDesc.Format = ToNativeFormat(_desc._format, false);
+ if (_desc._arrayLayers > +CubeMapFace::count)
+ {
+ srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBEARRAY;
+ srvDesc.TextureCubeArray.MipLevels = _desc._mipLevels;
+ srvDesc.TextureCubeArray.NumCubes = _desc._arrayLayers / +CubeMapFace::count;
+ }
+ else
+ {
+ srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
+ srvDesc.TextureCube.MipLevels = _desc._mipLevels;
+ }
+ if (FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateShaderResourceView(GetD3DResource(), &srvDesc, &_pSRV)))
+ throw VERUS_RUNTIME_ERROR << "CreateShaderResourceView(cubeMap); hr=" << VERUS_HR(hr);
+ }
+ else
+ {
+ if (FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateShaderResourceView(GetD3DResource(), nullptr, &_pSRV)))
+ throw VERUS_RUNTIME_ERROR << "CreateShaderResourceView(); hr=" << VERUS_HR(hr);
+ }
+ }
+
+ // Custom sampler:
+ if (_desc._pSamplerDesc)
+ CreateSampler();
+}
+
+void TextureD3D11::Done()
+{
+ ForceScheduled();
+
+ _pSamplerState.Reset();
+
+ _pDSV[1].Reset();
+ _pDSV[0].Reset();
+
+ for (auto& x : _vRTVs)
+ x.Reset();
+ _vRTVs.clear();
+
+ for (auto& x : _vUAVs)
+ x.Reset();
+ _vUAVs.clear();
+
+ _pSRV.Reset();
+
+ _vCshGenerateMips.clear();
+
+ for (auto& x : _vReadbackTextures)
+ x.Reset();
+ _vReadbackTextures.clear();
+
+ _pUaTexture.Reset();
+ _pTexture3D.Reset();
+ _pTexture2D.Reset();
+
+ VERUS_DONE(TextureD3D11);
+}
+
+void TextureD3D11::UpdateSubresource(const void* p, int mipLevel, int arrayLayer, PBaseCommandBuffer pCB)
+{
+ VERUS_QREF_RENDERER;
+ HRESULT hr = 0;
+
+ const int w = Math::Max(1, _desc._width >> mipLevel);
+ const int h = Math::Max(1, _desc._height >> mipLevel);
+
+ if (!pCB)
+ pCB = renderer.GetCommandBuffer().Get();
+ auto pDeviceContext = static_cast(pCB)->GetD3DDeviceContext();
+
+ UINT rowPitch;
+ UINT depthPitch;
+ if (IsBC(_desc._format))
+ {
+ rowPitch = IO::DDSHeader::ComputeBcPitch(w, h, Is4BitsBC(_desc._format));
+ depthPitch = IO::DDSHeader::ComputeBcLevelSize(w, h, Is4BitsBC(_desc._format));
+ }
+ else
+ {
+ rowPitch = _bytesPerPixel * w;
+ depthPitch = _bytesPerPixel * w * h;
+ }
+ const UINT subresource = D3D11CalcSubresource(mipLevel, arrayLayer, _desc._mipLevels);
+ pDeviceContext->UpdateSubresource(
+ _pTexture2D.Get(), subresource, nullptr,
+ p, rowPitch, depthPitch);
+}
+
+bool TextureD3D11::ReadbackSubresource(void* p, bool recordCopyCommand, PBaseCommandBuffer pCB)
+{
+ VERUS_QREF_RENDERER;
+ HRESULT hr = 0;
+
+ if (!pCB)
+ pCB = renderer.GetCommandBuffer().Get();
+ auto pDeviceContext = static_cast(pCB)->GetD3DDeviceContext();
+
+ const int w = Math::Max(1, _desc._width >> _desc._readbackMip);
+ const int h = Math::Max(1, _desc._height >> _desc._readbackMip);
+ const UINT rowPitch = _bytesPerPixel * w;
+
+ auto& rt = _vReadbackTextures[renderer->GetRingBufferIndex()];
+
+ if (recordCopyCommand)
+ {
+ const UINT subresource = D3D11CalcSubresource(_desc._readbackMip, 0, _desc._mipLevels);
+ pDeviceContext->CopySubresourceRegion(
+ rt.Get(), 0,
+ 0, 0, 0,
+ GetD3DResource(), subresource,
+ nullptr);
+ }
+
+ if (p) // Read current data from readback texture:
+ {
+ D3D11_MAPPED_SUBRESOURCE ms = {};
+ if (FAILED(hr = pDeviceContext->Map(rt.Get(), 0, D3D11_MAP_READ, 0, &ms)))
+ throw VERUS_RUNTIME_ERROR << "Map(); hr=" << VERUS_HR(hr);
+ BYTE* pDst = static_cast(p);
+ BYTE* pSrc = static_cast(ms.pData);
+ VERUS_FOR(i, h)
+ {
+ memcpy(
+ pDst + i * _bytesPerPixel * w,
+ pSrc + i * rowPitch,
+ _bytesPerPixel * w);
+ }
+ pDeviceContext->Unmap(rt.Get(), 0);
+ }
+
+ return _initAtFrame + BaseRenderer::s_ringBufferSize < renderer.GetFrameCount();
+}
+
+void TextureD3D11::GenerateMips(PBaseCommandBuffer pCB)
+{
+ VERUS_RT_ASSERT(_desc._flags & TextureDesc::Flags::generateMips);
+ if (_desc._flags & TextureDesc::Flags::cubeMap)
+ return GenerateCubeMapMips(pCB);
+
+ VERUS_QREF_RENDERER;
+
+ if (!pCB)
+ pCB = renderer.GetCommandBuffer().Get();
+ auto pDeviceContext = static_cast(pCB)->GetD3DDeviceContext();
+ auto shader = renderer.GetShaderGenerateMips();
+ auto& ub = renderer.GetUbGenerateMips();
+ auto tex = TexturePtr::From(this);
+
+ const int maxMipLevel = _desc._mipLevels - 1;
+
+ pCB->BindPipeline(renderer.GetPipelineGenerateMips(!!(_desc._flags & TextureDesc::Flags::exposureMips)));
+
+ shader->BeginBindDescriptors();
+ int dispatchIndex = 0;
+ for (int srcMip = 0; srcMip < maxMipLevel;)
+ {
+ const int srcWidth = Math::Max(1, _desc._width >> srcMip);
+ const int srcHeight = Math::Max(1, _desc._height >> srcMip);
+ const int dstWidth = Math::Max(1, srcWidth >> 1);
+ const int dstHeight = Math::Max(1, srcHeight >> 1);
+
+ int dispatchMipCount = Math::LowestBit((dstWidth == 1 ? dstHeight : dstWidth) | (dstHeight == 1 ? dstWidth : dstHeight));
+ dispatchMipCount = Math::Min(4, dispatchMipCount + 1);
+ dispatchMipCount = ((srcMip + dispatchMipCount) >= _desc._mipLevels) ? _desc._mipLevels - srcMip - 1 : dispatchMipCount; // Edge case.
+
+ ub._srcMipLevel = srcMip;
+ ub._mipLevelCount = dispatchMipCount;
+ ub._srcDimensionCase = ((srcHeight & 1) << 1) | (srcWidth & 1);
+ ub._srgb = IsSRGBFormat(_desc._format);
+ ub._dstTexelSize.x = 1.f / dstWidth;
+ ub._dstTexelSize.y = 1.f / dstHeight;
+
+ int mipLevels[5] = { 0, -1, -1, -1, -1 }; // For input texture (always mip 0) and 4 UAV mips.
+ VERUS_FOR(i, dispatchMipCount)
+ mipLevels[i + 1] = srcMip + i;
+ const CSHandle complexSetHandle = shader->BindDescriptorSetTextures(0, { tex, tex, tex, tex, tex }, mipLevels);
+ _vCshGenerateMips.push_back(complexSetHandle);
+ pCB->BindDescriptors(shader, 0, complexSetHandle);
+
+ pCB->Dispatch(Math::DivideByMultiple(dstWidth, 8), Math::DivideByMultiple(dstHeight, 8));
+
+ VERUS_FOR(i, dispatchMipCount)
+ {
+ const int subUAV = srcMip + i;
+ const int subSRV = subUAV + 1;
+ pDeviceContext->CopySubresourceRegion(
+ GetD3DResource(), subSRV,
+ 0, 0, 0,
+ _pUaTexture.Get(), subUAV,
+ nullptr);
+ }
+
+ srcMip += dispatchMipCount;
+ dispatchIndex++;
+ }
+ shader->EndBindDescriptors();
+
+ ClearCshGenerateMips();
+}
+
+void TextureD3D11::GenerateCubeMapMips(PBaseCommandBuffer pCB)
+{
+ VERUS_QREF_RENDERER;
+
+ if (!pCB)
+ pCB = renderer.GetCommandBuffer().Get();
+ auto pDeviceContext = static_cast(pCB)->GetD3DDeviceContext();
+ auto shader = renderer.GetShaderGenerateCubeMapMips();
+ auto& ub = renderer.GetUbGenerateCubeMapMips();
+ auto tex = TexturePtr::From(this);
+
+ const int maxMipLevel = _desc._mipLevels - 1;
+
+ pCB->BindPipeline(renderer.GetPipelineGenerateCubeMapMips());
+
+ shader->BeginBindDescriptors();
+ int dispatchIndex = 0;
+ for (int srcMip = 0; srcMip < maxMipLevel;)
+ {
+ const int srcWidth = Math::Max(1, _desc._width >> srcMip);
+ const int srcHeight = Math::Max(1, _desc._height >> srcMip);
+ const int dstWidth = Math::Max(1, srcWidth >> 1);
+ const int dstHeight = Math::Max(1, srcHeight >> 1);
+
+ ub._srcMipLevel = srcMip;
+ ub._srgb = IsSRGBFormat(_desc._format);
+ ub._dstTexelSize.x = 1.f / dstWidth;
+ ub._dstTexelSize.y = 1.f / dstHeight;
+
+ int mipLevels[7] = {};
+ VERUS_FOR(i, +CubeMapFace::count)
+ mipLevels[i + 1] = srcMip;
+ int arrayLayers[7] = {};
+ VERUS_FOR(i, +CubeMapFace::count)
+ arrayLayers[i + 1] = ToNativeCubeMapFace(static_cast(i));
+ const CSHandle complexSetHandle = shader->BindDescriptorSetTextures(0, { tex, tex, tex, tex, tex, tex, tex }, mipLevels, arrayLayers);
+ _vCshGenerateMips.push_back(complexSetHandle);
+ pCB->BindDescriptors(shader, 0, complexSetHandle);
+
+ pCB->Dispatch(Math::DivideByMultiple(dstWidth, 8), Math::DivideByMultiple(dstHeight, 8));
+
+ VERUS_FOR(i, +CubeMapFace::count)
+ {
+ const int subUAV = D3D11CalcSubresource(srcMip, i, _desc._mipLevels - 1);
+ const int subSRV = D3D11CalcSubresource(srcMip + 1, i, _desc._mipLevels);
+ pDeviceContext->CopySubresourceRegion(
+ GetD3DResource(), subSRV,
+ 0, 0, 0,
+ _pUaTexture.Get(), subUAV,
+ nullptr);
+ }
+
+ srcMip++;
+ dispatchIndex++;
+ }
+ shader->EndBindDescriptors();
+
+ ClearCshGenerateMips();
+}
+
+Continue TextureD3D11::Scheduled_Update()
+{
+ return Continue::yes;
+}
+
+void TextureD3D11::ClearCshGenerateMips()
+{
+ if (!_vCshGenerateMips.empty())
+ {
+ VERUS_QREF_RENDERER;
+ auto shader = renderer.GetShaderGenerateMips();
+ for (auto& csh : _vCshGenerateMips)
+ shader->FreeDescriptorSet(csh);
+ _vCshGenerateMips.clear();
+ }
+}
+
+void TextureD3D11::CreateSampler()
+{
+ VERUS_QREF_RENDERER_D3D11;
+ VERUS_QREF_CONST_SETTINGS;
+ HRESULT hr = 0;
+
+ const bool tf = settings._gpuTrilinearFilter;
+
+ D3D11_SAMPLER_DESC samplerDesc = {};
+
+ samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
+ samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
+ if ('a' == _desc._pSamplerDesc->_filterMagMinMip[0])
+ {
+ if (settings._gpuAnisotropyLevel > 0)
+ samplerDesc.Filter = D3D11_FILTER_ANISOTROPIC;
+ else
+ samplerDesc.Filter = tf ? D3D11_FILTER_MIN_MAG_MIP_LINEAR : D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
+ }
+ else if ('s' == _desc._pSamplerDesc->_filterMagMinMip[0]) // Shadow map:
+ {
+ if (settings._sceneShadowQuality <= App::Settings::Quality::low)
+ samplerDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_MIP_POINT;
+ else
+ samplerDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT;
+ samplerDesc.ComparisonFunc = D3D11_COMPARISON_LESS;
+ }
+ else
+ {
+ if (!strcmp(_desc._pSamplerDesc->_filterMagMinMip, "nn"))
+ samplerDesc.Filter = tf ? D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR : D3D11_FILTER_MIN_MAG_MIP_POINT;
+ if (!strcmp(_desc._pSamplerDesc->_filterMagMinMip, "nl"))
+ samplerDesc.Filter = tf ? D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR : D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT;
+ if (!strcmp(_desc._pSamplerDesc->_filterMagMinMip, "ln"))
+ samplerDesc.Filter = tf ? D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR : D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
+ if (!strcmp(_desc._pSamplerDesc->_filterMagMinMip, "ll"))
+ samplerDesc.Filter = tf ? D3D11_FILTER_MIN_MAG_MIP_LINEAR : D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
+ }
+ samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
+ samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
+ samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
+ VERUS_FOR(i, 3)
+ {
+ if (!_desc._pSamplerDesc->_addressModeUVW[i])
+ break;
+ D3D11_TEXTURE_ADDRESS_MODE tam = D3D11_TEXTURE_ADDRESS_CLAMP;
+ switch (_desc._pSamplerDesc->_addressModeUVW[i])
+ {
+ case 'r': tam = D3D11_TEXTURE_ADDRESS_WRAP; break;
+ case 'm': tam = D3D11_TEXTURE_ADDRESS_MIRROR; break;
+ case 'c': tam = D3D11_TEXTURE_ADDRESS_CLAMP; break;
+ case 'b': tam = D3D11_TEXTURE_ADDRESS_BORDER; break;
+ }
+ switch (i)
+ {
+ case 0: samplerDesc.AddressU = tam; break;
+ case 1: samplerDesc.AddressV = tam; break;
+ case 2: samplerDesc.AddressW = tam; break;
+ }
+ }
+ samplerDesc.MipLODBias = _desc._pSamplerDesc->_mipLodBias;
+ samplerDesc.MaxAnisotropy = settings._gpuAnisotropyLevel;
+ samplerDesc.MinLOD = _desc._pSamplerDesc->_minLod;
+ samplerDesc.MaxLOD = _desc._pSamplerDesc->_maxLod;
+ memcpy(samplerDesc.BorderColor, _desc._pSamplerDesc->_borderColor.ToPointer(), sizeof(samplerDesc.BorderColor));
+
+ if (FAILED(hr = pRendererD3D11->GetD3DDevice()->CreateSamplerState(&samplerDesc, &_pSamplerState)))
+ throw VERUS_RUNTIME_ERROR << "CreateSamplerState(); hr=" << VERUS_HR(hr);
+
+ _desc._pSamplerDesc = nullptr;
+}
+
+ID3D11Resource* TextureD3D11::GetD3DResource() const
+{
+ if (_pTexture2D)
+ return _pTexture2D.Get();
+ else
+ return _pTexture3D.Get();
+}
diff --git a/RendererDirect3D11/src/CGI/TextureD3D11.h b/RendererDirect3D11/src/CGI/TextureD3D11.h
new file mode 100644
index 0000000..0772765
--- /dev/null
+++ b/RendererDirect3D11/src/CGI/TextureD3D11.h
@@ -0,0 +1,54 @@
+// Copyright (C) 2021-2022, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
+#pragma once
+
+namespace verus
+{
+ namespace CGI
+ {
+ class TextureD3D11 : public BaseTexture
+ {
+ ComPtr _pTexture2D;
+ ComPtr _pTexture3D;
+ ComPtr _pUaTexture;
+ Vector> _vReadbackTextures;
+ Vector _vCshGenerateMips;
+ ComPtr _pSRV;
+ Vector> _vUAVs;
+ Vector> _vRTVs;
+ ComPtr _pDSV[2];
+ ComPtr _pSamplerState;
+
+ public:
+ TextureD3D11();
+ virtual ~TextureD3D11() override;
+
+ virtual void Init(RcTextureDesc desc) override;
+ virtual void Done() override;
+
+ virtual void UpdateSubresource(const void* p, int mipLevel, int arrayLayer, PBaseCommandBuffer pCB) override;
+ virtual bool ReadbackSubresource(void* p, bool recordCopyCommand, PBaseCommandBuffer pCB) override;
+
+ virtual void GenerateMips(PBaseCommandBuffer pCB) override;
+ void GenerateCubeMapMips(PBaseCommandBuffer pCB);
+
+ virtual Continue Scheduled_Update() override;
+
+ //
+ // D3D11
+ //
+
+ void ClearCshGenerateMips();
+
+ void CreateSampler();
+
+ ID3D11Resource* GetD3DResource() const;
+
+ ID3D11ShaderResourceView* GetSRV() const { return _pSRV.Get(); }
+ ID3D11UnorderedAccessView* GetUAV(int index = 0) const { return _vUAVs[index].Get(); }
+ ID3D11RenderTargetView* GetRTV(int index = 0) const { return _vRTVs[index].Get(); }
+ ID3D11DepthStencilView* GetDSV(bool readOnly = false) const { return readOnly ? _pDSV[1].Get() : _pDSV[0].Get(); }
+ ID3D11SamplerState* GetD3DSamplerState() const { return _pSamplerState.Get(); }
+ };
+ VERUS_TYPEDEFS(TextureD3D11);
+ }
+}
diff --git a/RendererDirect3D11/src/ThirdParty/imgui/imgui_impl_dx11.cpp b/RendererDirect3D11/src/ThirdParty/imgui/imgui_impl_dx11.cpp
new file mode 100644
index 0000000..31ab662
--- /dev/null
+++ b/RendererDirect3D11/src/ThirdParty/imgui/imgui_impl_dx11.cpp
@@ -0,0 +1,595 @@
+// dear imgui: Renderer Backend for DirectX11
+// This needs to be used along with a Platform Backend (e.g. Win32)
+
+// Implemented features:
+// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
+// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
+
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
+// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
+// Read online: https://github.com/ocornut/imgui/tree/master/docs
+
+// CHANGELOG
+// (minor and older changes stripped away, please see git history for details)
+// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
+// 2021-05-19: DirectX11: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
+// 2021-02-18: DirectX11: Change blending equation to preserve alpha in output buffer.
+// 2019-08-01: DirectX11: Fixed code querying the Geometry Shader state (would generally error with Debug layer enabled).
+// 2019-07-21: DirectX11: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX10_RenderDrawData. Clearing Hull/Domain/Compute shaders without backup/restore.
+// 2019-05-29: DirectX11: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
+// 2019-04-30: DirectX11: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
+// 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile().
+// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
+// 2018-08-01: DirectX11: Querying for IDXGIFactory instead of IDXGIFactory1 to increase compatibility.
+// 2018-07-13: DirectX11: Fixed unreleased resources in Init and Shutdown functions.
+// 2018-06-08: Misc: Extracted imgui_impl_dx11.cpp/.h away from the old combined DX11+Win32 example.
+// 2018-06-08: DirectX11: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
+// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX11_RenderDrawData() in the .h file so you can call it yourself.
+// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
+// 2016-05-07: DirectX11: Disabling depth-write.
+
+#include "../../../../Verus/src/ThirdParty/imgui/imgui.h"
+#include "imgui_impl_dx11.h"
+
+// DirectX
+#include
+#include
+#include
+#ifdef _MSC_VER
+#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
+#endif
+
+// DirectX11 data
+struct ImGui_ImplDX11_Data
+{
+ ID3D11Device* pd3dDevice;
+ ID3D11DeviceContext* pd3dDeviceContext;
+ IDXGIFactory* pFactory;
+ ID3D11Buffer* pVB;
+ ID3D11Buffer* pIB;
+ ID3D11VertexShader* pVertexShader;
+ ID3D11InputLayout* pInputLayout;
+ ID3D11Buffer* pVertexConstantBuffer;
+ ID3D11PixelShader* pPixelShader;
+ ID3D11SamplerState* pFontSampler;
+ ID3D11ShaderResourceView* pFontTextureView;
+ ID3D11RasterizerState* pRasterizerState;
+ ID3D11BlendState* pBlendState;
+ ID3D11DepthStencilState* pDepthStencilState;
+ int VertexBufferSize;
+ int IndexBufferSize;
+
+ ImGui_ImplDX11_Data() { memset((void*)this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; }
+};
+
+struct VERTEX_CONSTANT_BUFFER_DX11
+{
+ float mvp[4][4];
+};
+
+// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
+// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
+static ImGui_ImplDX11_Data* ImGui_ImplDX11_GetBackendData()
+{
+ return ImGui::GetCurrentContext() ? (ImGui_ImplDX11_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
+}
+
+// Functions
+static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceContext* ctx)
+{
+ ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
+
+ // Setup viewport
+ D3D11_VIEWPORT vp;
+ memset(&vp, 0, sizeof(D3D11_VIEWPORT));
+ vp.Width = draw_data->DisplaySize.x;
+ vp.Height = draw_data->DisplaySize.y;
+ vp.MinDepth = 0.0f;
+ vp.MaxDepth = 1.0f;
+ vp.TopLeftX = vp.TopLeftY = 0;
+ ctx->RSSetViewports(1, &vp);
+
+ // Setup shader and vertex buffers
+ unsigned int stride = sizeof(ImDrawVert);
+ unsigned int offset = 0;
+ ctx->IASetInputLayout(bd->pInputLayout);
+ ctx->IASetVertexBuffers(0, 1, &bd->pVB, &stride, &offset);
+ ctx->IASetIndexBuffer(bd->pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);
+ ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+ ctx->VSSetShader(bd->pVertexShader, NULL, 0);
+ ctx->VSSetConstantBuffers(0, 1, &bd->pVertexConstantBuffer);
+ ctx->PSSetShader(bd->pPixelShader, NULL, 0);
+ ctx->PSSetSamplers(0, 1, &bd->pFontSampler);
+ ctx->GSSetShader(NULL, NULL, 0);
+ ctx->HSSetShader(NULL, NULL, 0); // In theory we should backup and restore this as well.. very infrequently used..
+ ctx->DSSetShader(NULL, NULL, 0); // In theory we should backup and restore this as well.. very infrequently used..
+ ctx->CSSetShader(NULL, NULL, 0); // In theory we should backup and restore this as well.. very infrequently used..
+
+ // Setup blend state
+ const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
+ ctx->OMSetBlendState(bd->pBlendState, blend_factor, 0xffffffff);
+ ctx->OMSetDepthStencilState(bd->pDepthStencilState, 0);
+ ctx->RSSetState(bd->pRasterizerState);
+}
+
+// Render function
+void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
+{
+ // Avoid rendering when minimized
+ if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
+ return;
+
+ ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
+ ID3D11DeviceContext* ctx = bd->pd3dDeviceContext;
+
+ // Create and grow vertex/index buffers if needed
+ if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount)
+ {
+ if (bd->pVB) { bd->pVB->Release(); bd->pVB = NULL; }
+ bd->VertexBufferSize = draw_data->TotalVtxCount + 5000;
+ D3D11_BUFFER_DESC desc;
+ memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
+ desc.Usage = D3D11_USAGE_DYNAMIC;
+ desc.ByteWidth = bd->VertexBufferSize * sizeof(ImDrawVert);
+ desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ desc.MiscFlags = 0;
+ if (bd->pd3dDevice->CreateBuffer(&desc, NULL, &bd->pVB) < 0)
+ return;
+ }
+ if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount)
+ {
+ if (bd->pIB) { bd->pIB->Release(); bd->pIB = NULL; }
+ bd->IndexBufferSize = draw_data->TotalIdxCount + 10000;
+ D3D11_BUFFER_DESC desc;
+ memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
+ desc.Usage = D3D11_USAGE_DYNAMIC;
+ desc.ByteWidth = bd->IndexBufferSize * sizeof(ImDrawIdx);
+ desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ if (bd->pd3dDevice->CreateBuffer(&desc, NULL, &bd->pIB) < 0)
+ return;
+ }
+
+ // Upload vertex/index data into a single contiguous GPU buffer
+ D3D11_MAPPED_SUBRESOURCE vtx_resource, idx_resource;
+ if (ctx->Map(bd->pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource) != S_OK)
+ return;
+ if (ctx->Map(bd->pIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource) != S_OK)
+ return;
+ ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource.pData;
+ ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource.pData;
+ for (int n = 0; n < draw_data->CmdListsCount; n++)
+ {
+ const ImDrawList* cmd_list = draw_data->CmdLists[n];
+ memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
+ memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
+ vtx_dst += cmd_list->VtxBuffer.Size;
+ idx_dst += cmd_list->IdxBuffer.Size;
+ }
+ ctx->Unmap(bd->pVB, 0);
+ ctx->Unmap(bd->pIB, 0);
+
+ // Setup orthographic projection matrix into our constant buffer
+ // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
+ {
+ D3D11_MAPPED_SUBRESOURCE mapped_resource;
+ if (ctx->Map(bd->pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
+ return;
+ VERTEX_CONSTANT_BUFFER_DX11* constant_buffer = (VERTEX_CONSTANT_BUFFER_DX11*)mapped_resource.pData;
+ float L = draw_data->DisplayPos.x;
+ float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
+ float T = draw_data->DisplayPos.y;
+ float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
+ float mvp[4][4] =
+ {
+ { 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
+ { 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
+ { 0.0f, 0.0f, 0.5f, 0.0f },
+ { (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
+ };
+ memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
+ ctx->Unmap(bd->pVertexConstantBuffer, 0);
+ }
+
+ // Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
+ struct BACKUP_DX11_STATE
+ {
+ UINT ScissorRectsCount, ViewportsCount;
+ D3D11_RECT ScissorRects[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
+ D3D11_VIEWPORT Viewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
+ ID3D11RasterizerState* RS;
+ ID3D11BlendState* BlendState;
+ FLOAT BlendFactor[4];
+ UINT SampleMask;
+ UINT StencilRef;
+ ID3D11DepthStencilState* DepthStencilState;
+ ID3D11ShaderResourceView* PSShaderResource;
+ ID3D11SamplerState* PSSampler;
+ ID3D11PixelShader* PS;
+ ID3D11VertexShader* VS;
+ ID3D11GeometryShader* GS;
+ UINT PSInstancesCount, VSInstancesCount, GSInstancesCount;
+ ID3D11ClassInstance *PSInstances[256], *VSInstances[256], *GSInstances[256]; // 256 is max according to PSSetShader documentation
+ D3D11_PRIMITIVE_TOPOLOGY PrimitiveTopology;
+ ID3D11Buffer* IndexBuffer, *VertexBuffer, *VSConstantBuffer;
+ UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset;
+ DXGI_FORMAT IndexBufferFormat;
+ ID3D11InputLayout* InputLayout;
+ };
+ BACKUP_DX11_STATE old = {};
+ old.ScissorRectsCount = old.ViewportsCount = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
+ ctx->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects);
+ ctx->RSGetViewports(&old.ViewportsCount, old.Viewports);
+ ctx->RSGetState(&old.RS);
+ ctx->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask);
+ ctx->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef);
+ ctx->PSGetShaderResources(0, 1, &old.PSShaderResource);
+ ctx->PSGetSamplers(0, 1, &old.PSSampler);
+ old.PSInstancesCount = old.VSInstancesCount = old.GSInstancesCount = 256;
+ ctx->PSGetShader(&old.PS, old.PSInstances, &old.PSInstancesCount);
+ ctx->VSGetShader(&old.VS, old.VSInstances, &old.VSInstancesCount);
+ ctx->VSGetConstantBuffers(0, 1, &old.VSConstantBuffer);
+ ctx->GSGetShader(&old.GS, old.GSInstances, &old.GSInstancesCount);
+
+ ctx->IAGetPrimitiveTopology(&old.PrimitiveTopology);
+ ctx->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset);
+ ctx->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset);
+ ctx->IAGetInputLayout(&old.InputLayout);
+
+ // Setup desired DX state
+ ImGui_ImplDX11_SetupRenderState(draw_data, ctx);
+
+ // Render command lists
+ // (Because we merged all buffers into a single one, we maintain our own offset into them)
+ int global_idx_offset = 0;
+ int global_vtx_offset = 0;
+ ImVec2 clip_off = draw_data->DisplayPos;
+ for (int n = 0; n < draw_data->CmdListsCount; n++)
+ {
+ const ImDrawList* cmd_list = draw_data->CmdLists[n];
+ for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
+ {
+ const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
+ if (pcmd->UserCallback != NULL)
+ {
+ // User callback, registered via ImDrawList::AddCallback()
+ // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
+ if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
+ ImGui_ImplDX11_SetupRenderState(draw_data, ctx);
+ else
+ pcmd->UserCallback(cmd_list, pcmd);
+ }
+ else
+ {
+ // Project scissor/clipping rectangles into framebuffer space
+ ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
+ ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
+ if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
+ continue;
+
+ // Apply scissor/clipping rectangle
+ const D3D11_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
+ ctx->RSSetScissorRects(1, &r);
+
+ // Bind texture, Draw
+ ID3D11ShaderResourceView* texture_srv = (ID3D11ShaderResourceView*)pcmd->GetTexID();
+ ctx->PSSetShaderResources(0, 1, &texture_srv);
+ ctx->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset);
+ }
+ }
+ global_idx_offset += cmd_list->IdxBuffer.Size;
+ global_vtx_offset += cmd_list->VtxBuffer.Size;
+ }
+
+ // Restore modified DX state
+ ctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects);
+ ctx->RSSetViewports(old.ViewportsCount, old.Viewports);
+ ctx->RSSetState(old.RS); if (old.RS) old.RS->Release();
+ ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release();
+ ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release();
+ ctx->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release();
+ ctx->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release();
+ ctx->PSSetShader(old.PS, old.PSInstances, old.PSInstancesCount); if (old.PS) old.PS->Release();
+ for (UINT i = 0; i < old.PSInstancesCount; i++) if (old.PSInstances[i]) old.PSInstances[i]->Release();
+ ctx->VSSetShader(old.VS, old.VSInstances, old.VSInstancesCount); if (old.VS) old.VS->Release();
+ ctx->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release();
+ ctx->GSSetShader(old.GS, old.GSInstances, old.GSInstancesCount); if (old.GS) old.GS->Release();
+ for (UINT i = 0; i < old.VSInstancesCount; i++) if (old.VSInstances[i]) old.VSInstances[i]->Release();
+ ctx->IASetPrimitiveTopology(old.PrimitiveTopology);
+ ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release();
+ ctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release();
+ ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release();
+}
+
+static void ImGui_ImplDX11_CreateFontsTexture()
+{
+ // Build texture atlas
+ ImGuiIO& io = ImGui::GetIO();
+ ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
+ unsigned char* pixels;
+ int width, height;
+ io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
+
+ // Upload texture to graphics system
+ {
+ D3D11_TEXTURE2D_DESC desc;
+ ZeroMemory(&desc, sizeof(desc));
+ desc.Width = width;
+ desc.Height = height;
+ desc.MipLevels = 1;
+ desc.ArraySize = 1;
+ desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ desc.SampleDesc.Count = 1;
+ desc.Usage = D3D11_USAGE_DEFAULT;
+ desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+ desc.CPUAccessFlags = 0;
+
+ ID3D11Texture2D* pTexture = NULL;
+ D3D11_SUBRESOURCE_DATA subResource;
+ subResource.pSysMem = pixels;
+ subResource.SysMemPitch = desc.Width * 4;
+ subResource.SysMemSlicePitch = 0;
+ bd->pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
+ IM_ASSERT(pTexture != NULL);
+
+ // Create texture view
+ D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
+ ZeroMemory(&srvDesc, sizeof(srvDesc));
+ srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+ srvDesc.Texture2D.MipLevels = desc.MipLevels;
+ srvDesc.Texture2D.MostDetailedMip = 0;
+ bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &bd->pFontTextureView);
+ pTexture->Release();
+ }
+
+ // Store our identifier
+ io.Fonts->SetTexID((ImTextureID)bd->pFontTextureView);
+
+ // Create texture sampler
+ // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
+ {
+ D3D11_SAMPLER_DESC desc;
+ ZeroMemory(&desc, sizeof(desc));
+ desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
+ desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
+ desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
+ desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
+ desc.MipLODBias = 0.f;
+ desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
+ desc.MinLOD = 0.f;
+ desc.MaxLOD = 0.f;
+ bd->pd3dDevice->CreateSamplerState(&desc, &bd->pFontSampler);
+ }
+}
+
+bool ImGui_ImplDX11_CreateDeviceObjects()
+{
+ ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
+ if (!bd->pd3dDevice)
+ return false;
+ if (bd->pFontSampler)
+ ImGui_ImplDX11_InvalidateDeviceObjects();
+
+ // By using D3DCompile() from / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
+ // If you would like to use this DX11 sample code but remove this dependency you can:
+ // 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution]
+ // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
+ // See https://github.com/ocornut/imgui/pull/638 for sources and details.
+
+ // Create the vertex shader
+ {
+ static const char* vertexShader =
+ "cbuffer vertexBuffer : register(b0) \
+ {\
+ float4x4 ProjectionMatrix; \
+ };\
+ struct VS_INPUT\
+ {\
+ float2 pos : POSITION;\
+ float4 col : COLOR0;\
+ float2 uv : TEXCOORD0;\
+ };\
+ \
+ struct PS_INPUT\
+ {\
+ float4 pos : SV_POSITION;\
+ float4 col : COLOR0;\
+ float2 uv : TEXCOORD0;\
+ };\
+ \
+ PS_INPUT main(VS_INPUT input)\
+ {\
+ PS_INPUT output;\
+ output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\
+ output.col = input.col;\
+ output.uv = input.uv;\
+ return output;\
+ }";
+
+ ID3DBlob* vertexShaderBlob;
+ if (FAILED(D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_4_0", 0, 0, &vertexShaderBlob, NULL)))
+ return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
+ if (bd->pd3dDevice->CreateVertexShader(vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), NULL, &bd->pVertexShader) != S_OK)
+ {
+ vertexShaderBlob->Release();
+ return false;
+ }
+
+ // Create the input layout
+ D3D11_INPUT_ELEMENT_DESC local_layout[] =
+ {
+ { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, pos), D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, uv), D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)IM_OFFSETOF(ImDrawVert, col), D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ };
+ if (bd->pd3dDevice->CreateInputLayout(local_layout, 3, vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), &bd->pInputLayout) != S_OK)
+ {
+ vertexShaderBlob->Release();
+ return false;
+ }
+ vertexShaderBlob->Release();
+
+ // Create the constant buffer
+ {
+ D3D11_BUFFER_DESC desc;
+ desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER_DX11);
+ desc.Usage = D3D11_USAGE_DYNAMIC;
+ desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ desc.MiscFlags = 0;
+ bd->pd3dDevice->CreateBuffer(&desc, NULL, &bd->pVertexConstantBuffer);
+ }
+ }
+
+ // Create the pixel shader
+ {
+ static const char* pixelShader =
+ "struct PS_INPUT\
+ {\
+ float4 pos : SV_POSITION;\
+ float4 col : COLOR0;\
+ float2 uv : TEXCOORD0;\
+ };\
+ sampler sampler0;\
+ Texture2D texture0;\
+ \
+ float4 main(PS_INPUT input) : SV_Target\
+ {\
+ float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \
+ return out_col; \
+ }";
+
+ ID3DBlob* pixelShaderBlob;
+ if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_4_0", 0, 0, &pixelShaderBlob, NULL)))
+ return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
+ if (bd->pd3dDevice->CreatePixelShader(pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize(), NULL, &bd->pPixelShader) != S_OK)
+ {
+ pixelShaderBlob->Release();
+ return false;
+ }
+ pixelShaderBlob->Release();
+ }
+
+ // Create the blending setup
+ {
+ D3D11_BLEND_DESC desc;
+ ZeroMemory(&desc, sizeof(desc));
+ desc.AlphaToCoverageEnable = false;
+ desc.RenderTarget[0].BlendEnable = true;
+ desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
+ desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
+ desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
+ desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
+ desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
+ desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
+ desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
+ bd->pd3dDevice->CreateBlendState(&desc, &bd->pBlendState);
+ }
+
+ // Create the rasterizer state
+ {
+ D3D11_RASTERIZER_DESC desc;
+ ZeroMemory(&desc, sizeof(desc));
+ desc.FillMode = D3D11_FILL_SOLID;
+ desc.CullMode = D3D11_CULL_NONE;
+ desc.ScissorEnable = true;
+ desc.DepthClipEnable = true;
+ bd->pd3dDevice->CreateRasterizerState(&desc, &bd->pRasterizerState);
+ }
+
+ // Create depth-stencil State
+ {
+ D3D11_DEPTH_STENCIL_DESC desc;
+ ZeroMemory(&desc, sizeof(desc));
+ desc.DepthEnable = false;
+ desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
+ desc.DepthFunc = D3D11_COMPARISON_ALWAYS;
+ desc.StencilEnable = false;
+ desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
+ desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
+ desc.BackFace = desc.FrontFace;
+ bd->pd3dDevice->CreateDepthStencilState(&desc, &bd->pDepthStencilState);
+ }
+
+ ImGui_ImplDX11_CreateFontsTexture();
+
+ return true;
+}
+
+void ImGui_ImplDX11_InvalidateDeviceObjects()
+{
+ ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
+ if (!bd->pd3dDevice)
+ return;
+
+ if (bd->pFontSampler) { bd->pFontSampler->Release(); bd->pFontSampler = NULL; }
+ if (bd->pFontTextureView) { bd->pFontTextureView->Release(); bd->pFontTextureView = NULL; ImGui::GetIO().Fonts->SetTexID(NULL); } // We copied data->pFontTextureView to io.Fonts->TexID so let's clear that as well.
+ if (bd->pIB) { bd->pIB->Release(); bd->pIB = NULL; }
+ if (bd->pVB) { bd->pVB->Release(); bd->pVB = NULL; }
+ if (bd->pBlendState) { bd->pBlendState->Release(); bd->pBlendState = NULL; }
+ if (bd->pDepthStencilState) { bd->pDepthStencilState->Release(); bd->pDepthStencilState = NULL; }
+ if (bd->pRasterizerState) { bd->pRasterizerState->Release(); bd->pRasterizerState = NULL; }
+ if (bd->pPixelShader) { bd->pPixelShader->Release(); bd->pPixelShader = NULL; }
+ if (bd->pVertexConstantBuffer) { bd->pVertexConstantBuffer->Release(); bd->pVertexConstantBuffer = NULL; }
+ if (bd->pInputLayout) { bd->pInputLayout->Release(); bd->pInputLayout = NULL; }
+ if (bd->pVertexShader) { bd->pVertexShader->Release(); bd->pVertexShader = NULL; }
+}
+
+bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context)
+{
+ ImGuiIO& io = ImGui::GetIO();
+ IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
+
+ // Setup backend capabilities flags
+ ImGui_ImplDX11_Data* bd = IM_NEW(ImGui_ImplDX11_Data)();
+ io.BackendRendererUserData = (void*)bd;
+ io.BackendRendererName = "imgui_impl_dx11";
+ io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
+
+ // Get factory from device
+ IDXGIDevice* pDXGIDevice = NULL;
+ IDXGIAdapter* pDXGIAdapter = NULL;
+ IDXGIFactory* pFactory = NULL;
+
+ if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK)
+ if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)
+ if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)
+ {
+ bd->pd3dDevice = device;
+ bd->pd3dDeviceContext = device_context;
+ bd->pFactory = pFactory;
+ }
+ if (pDXGIDevice) pDXGIDevice->Release();
+ if (pDXGIAdapter) pDXGIAdapter->Release();
+ bd->pd3dDevice->AddRef();
+ bd->pd3dDeviceContext->AddRef();
+
+ return true;
+}
+
+void ImGui_ImplDX11_Shutdown()
+{
+ ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
+ IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
+ ImGuiIO& io = ImGui::GetIO();
+
+ ImGui_ImplDX11_InvalidateDeviceObjects();
+ if (bd->pFactory) { bd->pFactory->Release(); }
+ if (bd->pd3dDevice) { bd->pd3dDevice->Release(); }
+ if (bd->pd3dDeviceContext) { bd->pd3dDeviceContext->Release(); }
+ io.BackendRendererName = NULL;
+ io.BackendRendererUserData = NULL;
+ IM_DELETE(bd);
+}
+
+void ImGui_ImplDX11_NewFrame()
+{
+ ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
+ IM_ASSERT(bd != NULL && "Did you call ImGui_ImplDX11_Init()?");
+
+ if (!bd->pFontSampler)
+ ImGui_ImplDX11_CreateDeviceObjects();
+}
diff --git a/RendererDirect3D11/src/ThirdParty/imgui/imgui_impl_dx11.h b/RendererDirect3D11/src/ThirdParty/imgui/imgui_impl_dx11.h
new file mode 100644
index 0000000..95f7531
--- /dev/null
+++ b/RendererDirect3D11/src/ThirdParty/imgui/imgui_impl_dx11.h
@@ -0,0 +1,25 @@
+// dear imgui: Renderer Backend for DirectX11
+// This needs to be used along with a Platform Backend (e.g. Win32)
+
+// Implemented features:
+// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
+// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
+
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
+// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
+// Read online: https://github.com/ocornut/imgui/tree/master/docs
+
+#pragma once
+
+struct ID3D11Device;
+struct ID3D11DeviceContext;
+
+IMGUI_IMPL_API bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context);
+IMGUI_IMPL_API void ImGui_ImplDX11_Shutdown();
+IMGUI_IMPL_API void ImGui_ImplDX11_NewFrame();
+IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data);
+
+// Use if you want to reset your rendering device without losing Dear ImGui state.
+IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects();
+IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects();
diff --git a/RendererDirect3D11/src/main.cpp b/RendererDirect3D11/src/main.cpp
new file mode 100644
index 0000000..2917ba2
--- /dev/null
+++ b/RendererDirect3D11/src/main.cpp
@@ -0,0 +1,42 @@
+// Copyright (C) 2021-2022, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
+#include "pch.h"
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
+{
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ break;
+ case DLL_THREAD_ATTACH:
+ break;
+ case DLL_THREAD_DETACH:
+ break;
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
+
+extern "C"
+{
+ VERUS_DLL_EXPORT verus::CGI::PBaseRenderer CreateRenderer(UINT32 version, verus::CGI::PBaseRendererDesc pDesc)
+ {
+ using namespace verus;
+
+ if (VERUS_SDK_VERSION != version)
+ {
+ VERUS_RT_FAIL("CreateRenderer(); Wrong version.");
+ return nullptr;
+ }
+
+ pDesc->_gvc.Paste();
+
+ CGI::RendererD3D11::Make();
+ VERUS_QREF_RENDERER_D3D11;
+
+ pRendererD3D11->SetDesc(*pDesc);
+ pRendererD3D11->Init();
+
+ return pRendererD3D11;
+ }
+}
diff --git a/RendererDirect3D11/src/pch.cpp b/RendererDirect3D11/src/pch.cpp
new file mode 100644
index 0000000..2b43100
--- /dev/null
+++ b/RendererDirect3D11/src/pch.cpp
@@ -0,0 +1,2 @@
+// Copyright (C) 2021-2022, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
+#include "pch.h"
diff --git a/RendererDirect3D11/src/pch.h b/RendererDirect3D11/src/pch.h
new file mode 100644
index 0000000..8869ea0
--- /dev/null
+++ b/RendererDirect3D11/src/pch.h
@@ -0,0 +1,9 @@
+// Copyright (C) 2021-2022, Dmitry Maluev (dmaluev@gmail.com). All rights reserved.
+#pragma once
+
+#define SDL_VIDEO_DRIVER_WINRT 1
+#define VERUS_INCLUDE_D3D11
+#include
+
+#include "ThirdParty/imgui/imgui_impl_dx11.h"
+#include "CGI/CGI.h"
diff --git a/RendererDirect3D12/src/CGI/CommandBufferD3D12.cpp b/RendererDirect3D12/src/CGI/CommandBufferD3D12.cpp
index 272fb6e..c3295b3 100644
--- a/RendererDirect3D12/src/CGI/CommandBufferD3D12.cpp
+++ b/RendererDirect3D12/src/CGI/CommandBufferD3D12.cpp
@@ -22,7 +22,7 @@ void CommandBufferD3D12::Init()
_vAttachmentStates.reserve(4);
_vBarriers.reserve(VERUS_MAX_FB_ATTACH);
VERUS_FOR(i, BaseRenderer::s_ringBufferSize)
- _pCommandLists[i] = pRendererD3D12->CreateCommandList(D3D12_COMMAND_LIST_TYPE_DIRECT, pRendererD3D12->GetD3DCommandAllocator(i));
+ _pCommandLists[i] = pRendererD3D12->CreateD3DCommandList(D3D12_COMMAND_LIST_TYPE_DIRECT, pRendererD3D12->GetD3DCommandAllocator(i));
}
void CommandBufferD3D12::Done()
@@ -34,6 +34,7 @@ void CommandBufferD3D12::Done()
}
VERUS_RT_ASSERT(_vAttachmentStates.capacity() < 100);
VERUS_RT_ASSERT(_vBarriers.capacity() < 1000);
+
VERUS_DONE(CommandBufferD3D12);
}
@@ -41,8 +42,9 @@ void CommandBufferD3D12::InitOneTimeSubmit()
{
VERUS_QREF_RENDERER;
VERUS_QREF_RENDERER_D3D12;
- _pOneTimeCommandAllocator = pRendererD3D12->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT);
- auto pCmdList = pRendererD3D12->CreateCommandList(D3D12_COMMAND_LIST_TYPE_DIRECT, _pOneTimeCommandAllocator);
+
+ _pOneTimeCommandAllocator = pRendererD3D12->CreateD3DCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT);
+ auto pCmdList = pRendererD3D12->CreateD3DCommandList(D3D12_COMMAND_LIST_TYPE_DIRECT, _pOneTimeCommandAllocator);
VERUS_FOR(i, BaseRenderer::s_ringBufferSize)
_pCommandLists[i] = pCmdList;
_pOneTimeCommandAllocator->Reset();
@@ -54,9 +56,10 @@ void CommandBufferD3D12::DoneOneTimeSubmit()
{
VERUS_QREF_RENDERER;
VERUS_QREF_RENDERER_D3D12;
+
End();
ID3D12CommandList* ppCommandLists[] = { _pCommandLists[0].Get() };
- pRendererD3D12->GetCommandQueue()->ExecuteCommandLists(VERUS_COUNT_OF(ppCommandLists), ppCommandLists);
+ pRendererD3D12->GetD3DCommandQueue()->ExecuteCommandLists(VERUS_COUNT_OF(ppCommandLists), ppCommandLists);
pRendererD3D12->QueueWaitIdle();
_pOneTimeCommandAllocator.Reset();
VERUS_FOR(i, BaseRenderer::s_ringBufferSize)
@@ -66,6 +69,7 @@ void CommandBufferD3D12::DoneOneTimeSubmit()
void CommandBufferD3D12::Begin()
{
VERUS_QREF_RENDERER_D3D12;
+
HRESULT hr = 0;
if (FAILED(hr = GetD3DGraphicsCommandList()->Reset(
_pOneTimeCommandAllocator ? _pOneTimeCommandAllocator.Get() : pRendererD3D12->GetD3DCommandAllocator(pRendererD3D12->GetRingBufferIndex()),
@@ -108,7 +112,7 @@ void CommandBufferD3D12::BeginRenderPass(RPHandle renderPassHandle, FBHandle fra
VERUS_RT_ASSERT(_pRenderPass->_vAttachments.size() == ilClearValues.size());
_vClearValues.clear();
- for (auto x : ilClearValues)
+ for (const auto& x : ilClearValues)
{
auto pColor = x.ToPointer();
_vClearValues.push_back(pColor[0]);
@@ -184,7 +188,7 @@ void CommandBufferD3D12::BindPipeline(PipelinePtr pipe)
else
{
pCmdList->SetGraphicsRootSignature(pipeD3D12.GetD3DRootSignature());
- pCmdList->IASetPrimitiveTopology(pipeD3D12.GetPrimitiveTopology());
+ pCmdList->IASetPrimitiveTopology(pipeD3D12.GetD3DPrimitiveTopology());
}
}
@@ -199,7 +203,7 @@ void CommandBufferD3D12::SetViewport(std::initializer_list il, float mi
VERUS_RT_ASSERT(il.size() <= VERUS_MAX_CA);
CD3DX12_VIEWPORT vpD3D12[VERUS_MAX_CA];
- int count = 0;
+ UINT count = 0;
for (const auto& rc : il)
vpD3D12[count++] = CD3DX12_VIEWPORT(rc.getX(), rc.getY(), rc.Width(), rc.Height(), minDepth, maxDepth);
GetD3DGraphicsCommandList()->RSSetViewports(count, vpD3D12);
@@ -209,7 +213,7 @@ void CommandBufferD3D12::SetScissor(std::initializer_list il)
{
VERUS_RT_ASSERT(il.size() <= VERUS_MAX_CA);
CD3DX12_RECT rcD3D12[VERUS_MAX_CA];
- int count = 0;
+ UINT count = 0;
for (const auto& rc : il)
rcD3D12[count++] = CD3DX12_RECT(
static_cast(rc.getX()),
@@ -250,20 +254,11 @@ void CommandBufferD3D12::BindIndexBuffer(GeometryPtr geo)
bool CommandBufferD3D12::BindDescriptors(ShaderPtr shader, int setNumber, CSHandle complexSetHandle)
{
- bool copyDescOnly = false;
- if (setNumber < 0)
- {
- // On a Resource Binding Tier 2 hardware, all descriptor tables of type CBV and UAV declared in the currently set Root Signature
- // must be populated, even if the shaders do not need the descriptor.
- setNumber = -setNumber;
- copyDescOnly = true;
- }
-
auto& shaderD3D12 = static_cast(*shader);
if (shaderD3D12.TryRootConstants(setNumber, *this))
return true;
- const D3D12_GPU_DESCRIPTOR_HANDLE hGPU = shaderD3D12.UpdateUniformBuffer(setNumber, complexSetHandle.Get(), copyDescOnly);
+ const D3D12_GPU_DESCRIPTOR_HANDLE hGPU = shaderD3D12.UpdateUniformBuffer(setNumber, complexSetHandle.Get());
if (!hGPU.ptr)
return false;
diff --git a/RendererDirect3D12/src/CGI/GeometryD3D12.cpp b/RendererDirect3D12/src/CGI/GeometryD3D12.cpp
index 259a109..3cc6ce1 100644
--- a/RendererDirect3D12/src/CGI/GeometryD3D12.cpp
+++ b/RendererDirect3D12/src/CGI/GeometryD3D12.cpp
@@ -22,7 +22,7 @@ void GeometryD3D12::Init(RcGeometryDesc desc)
_dynBindingsMask = desc._dynBindingsMask;
_32BitIndices = desc._32BitIndices;
- _vInputElementDesc.reserve(GetVertexInputAttrDescCount(desc._pVertexInputAttrDesc));
+ _vInputElementDescs.reserve(GetVertexInputAttrDescCount(desc._pVertexInputAttrDesc));
int i = 0;
while (desc._pVertexInputAttrDesc[i]._offset >= 0)
{
@@ -46,7 +46,7 @@ void GeometryD3D12::Init(RcGeometryDesc desc)
inputClassification,
instanceDataStepRate
};
- _vInputElementDesc.push_back(ieDesc);
+ _vInputElementDescs.push_back(ieDesc);
i++;
}
@@ -146,6 +146,7 @@ void GeometryD3D12::UpdateVertexBuffer(const void* p, int binding, PBaseCommandB
auto& vb = _vVertexBuffers[binding];
const int elementSize = _vStrides[binding];
size = size ? size * elementSize : vb._bufferSize;
+
CD3DX12_RANGE readRange(0, 0);
void* pData = nullptr;
if (FAILED(hr = vb._pBuffer->Map(0, &readRange, &pData)))
@@ -183,6 +184,7 @@ void GeometryD3D12::UpdateVertexBuffer(const void* p, int binding, PBaseCommandB
if (!pCB)
pCB = renderer.GetCommandBuffer().Get();
auto pCmdList = static_cast(pCB)->GetD3DGraphicsCommandList();
+
if (revertState)
{
const CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(
@@ -195,8 +197,8 @@ void GeometryD3D12::UpdateVertexBuffer(const void* p, int binding, PBaseCommandB
sd.SlicePitch = sd.RowPitch;
UpdateSubresources<1>(pCmdList,
vb._pBuffer.Get(),
- svb._pBuffer.Get(),
- 0, 0, 1, &sd);
+ svb._pBuffer.Get(), 0,
+ 0, 1, &sd);
const CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(
vb._pBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
pCmdList->ResourceBarrier(1, &barrier);
@@ -266,6 +268,7 @@ void GeometryD3D12::UpdateIndexBuffer(const void* p, PBaseCommandBuffer pCB, INT
{
const int elementSize = _32BitIndices ? sizeof(UINT32) : sizeof(UINT16);
size = size ? size * elementSize : _indexBuffer._bufferSize;
+
CD3DX12_RANGE readRange(0, 0);
void* pData = nullptr;
if (FAILED(hr = _indexBuffer._pBuffer->Map(0, &readRange, &pData)))
@@ -298,6 +301,7 @@ void GeometryD3D12::UpdateIndexBuffer(const void* p, PBaseCommandBuffer pCB, INT
if (!pCB)
pCB = renderer.GetCommandBuffer().Get();
auto pCmdList = static_cast(pCB)->GetD3DGraphicsCommandList();
+
if (revertState)
{
const CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(
@@ -310,8 +314,8 @@ void GeometryD3D12::UpdateIndexBuffer(const void* p, PBaseCommandBuffer pCB, INT
sd.SlicePitch = sd.RowPitch;
UpdateSubresources<1>(pCmdList,
_indexBuffer._pBuffer.Get(),
- _stagingIndexBuffer._pBuffer.Get(),
- 0, 0, 1, &sd);
+ _stagingIndexBuffer._pBuffer.Get(), 0,
+ 0, 1, &sd);
const CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(
_indexBuffer._pBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_INDEX_BUFFER);
pCmdList->ResourceBarrier(1, &barrier);
@@ -339,13 +343,13 @@ Continue GeometryD3D12::Scheduled_Update()
return Continue::no;
}
-D3D12_INPUT_LAYOUT_DESC GeometryD3D12::GetD3DInputLayoutDesc(UINT32 bindingsFilter, Vector& vInputElementDesc) const
+D3D12_INPUT_LAYOUT_DESC GeometryD3D12::GetD3DInputLayoutDesc(UINT32 bindingsFilter, Vector& vInputElementDescs) const
{
if (UINT32_MAX == bindingsFilter)
- return { _vInputElementDesc.data(), Utils::Cast32(_vInputElementDesc.size()) };
+ return { _vInputElementDescs.data(), Utils::Cast32(_vInputElementDescs.size()) };
- uint32_t replaceBinding[VERUS_MAX_VB] = {}; // For bindings compaction.
- int binding = 0;
+ UINT replaceBinding[VERUS_MAX_VB] = {}; // For bindings compaction.
+ UINT binding = 0;
VERUS_FOR(i, VERUS_MAX_VB)
{
replaceBinding[i] = binding;
@@ -353,17 +357,17 @@ D3D12_INPUT_LAYOUT_DESC GeometryD3D12::GetD3DInputLayoutDesc(UINT32 bindingsFilt
binding++;
}
- vInputElementDesc.reserve(_vInputElementDesc.size());
- for (const auto& x : _vInputElementDesc)
+ vInputElementDescs.reserve(_vInputElementDescs.size());
+ for (const auto& x : _vInputElementDescs)
{
if ((bindingsFilter >> x.InputSlot) & 0x1)
{
- vInputElementDesc.push_back(x);
- vInputElementDesc.back().InputSlot = replaceBinding[x.InputSlot];
+ vInputElementDescs.push_back(x);
+ vInputElementDescs.back().InputSlot = replaceBinding[x.InputSlot];
}
}
- return { vInputElementDesc.data(), Utils::Cast32(vInputElementDesc.size()) };
+ return { vInputElementDescs.data(), Utils::Cast32(vInputElementDescs.size()) };
}
const D3D12_VERTEX_BUFFER_VIEW* GeometryD3D12::GetD3DVertexBufferView(int binding) const
diff --git a/RendererDirect3D12/src/CGI/GeometryD3D12.h b/RendererDirect3D12/src/CGI/GeometryD3D12.h
index c0cbcb2..c87d8ce 100644
--- a/RendererDirect3D12/src/CGI/GeometryD3D12.h
+++ b/RendererDirect3D12/src/CGI/GeometryD3D12.h
@@ -9,8 +9,8 @@ namespace verus
{
struct BufferEx
{
- ComPtr _pBuffer;
D3D12MA::Allocation* _pMaAllocation = nullptr;
+ ComPtr _pBuffer;
UINT64 _bufferSize = 0;
D3D12_VERTEX_BUFFER_VIEW _bufferView[BaseRenderer::s_ringBufferSize] = {};
INT64 _utilization = -1;
@@ -21,7 +21,7 @@ namespace verus
Vector _vStagingVertexBuffers;
BufferEx _stagingIndexBuffer;
D3D12_INDEX_BUFFER_VIEW _indexBufferView[BaseRenderer::s_ringBufferSize] = {};
- Vector _vInputElementDesc;
+ Vector _vInputElementDescs;
Vector _vStrides;
public:
@@ -43,7 +43,7 @@ namespace verus
// D3D12
//
- D3D12_INPUT_LAYOUT_DESC GetD3DInputLayoutDesc(UINT32 bindingsFilter, Vector& vInputElementDesc) const;
+ D3D12_INPUT_LAYOUT_DESC GetD3DInputLayoutDesc(UINT32 bindingsFilter, Vector& vInputElementDescs) const;
int GetVertexBufferCount() const { return Utils::Cast32(_vVertexBuffers.size()); }
const D3D12_VERTEX_BUFFER_VIEW* GetD3DVertexBufferView(int binding) const;
diff --git a/RendererDirect3D12/src/CGI/Native.cpp b/RendererDirect3D12/src/CGI/Native.cpp
index 2787b25..2412db1 100644
--- a/RendererDirect3D12/src/CGI/Native.cpp
+++ b/RendererDirect3D12/src/CGI/Native.cpp
@@ -143,7 +143,7 @@ DXGI_FORMAT CGI::ToNativeFormat(Format format, bool typeless)
case Format::srgbBC7: return DXGI_FORMAT_BC7_UNORM_SRGB;
default: throw VERUS_RECOVERABLE << "ToNativeFormat()";
- };
+ }
}
DXGI_FORMAT CGI::ToNativeSampledDepthFormat(Format format)
@@ -155,7 +155,7 @@ DXGI_FORMAT CGI::ToNativeSampledDepthFormat(Format format)
case Format::floatD32: return DXGI_FORMAT_R32_FLOAT;
default: throw VERUS_RECOVERABLE << "ToNativeSampledDepthFormat()";
- };
+ }
}
CSZ CGI::ToNativeSemanticName(ViaUsage usage)
diff --git a/RendererDirect3D12/src/CGI/PipelineD3D12.cpp b/RendererDirect3D12/src/CGI/PipelineD3D12.cpp
index ef88eb2..89b61ba 100644
--- a/RendererDirect3D12/src/CGI/PipelineD3D12.cpp
+++ b/RendererDirect3D12/src/CGI/PipelineD3D12.cpp
@@ -86,8 +86,8 @@ void PipelineD3D12::Init(RcPipelineDesc desc)
gpsDesc.DepthStencilState.StencilEnable = desc._stencilTestEnable;
}
- Vector vInputElementDesc;
- gpsDesc.InputLayout = geo.GetD3DInputLayoutDesc(_vertexInputBindingsFilter, vInputElementDesc);
+ Vector vInputElementDescs;
+ gpsDesc.InputLayout = geo.GetD3DInputLayoutDesc(_vertexInputBindingsFilter, vInputElementDescs);
gpsDesc.IBStripCutValue = desc._primitiveRestartEnable ? GetStripCutValue() : D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED;
gpsDesc.PrimitiveTopologyType = ToNativePrimitiveTopologyType(desc._topology);
diff --git a/RendererDirect3D12/src/CGI/PipelineD3D12.h b/RendererDirect3D12/src/CGI/PipelineD3D12.h
index e045049..28bf067 100644
--- a/RendererDirect3D12/src/CGI/PipelineD3D12.h
+++ b/RendererDirect3D12/src/CGI/PipelineD3D12.h
@@ -29,7 +29,7 @@ namespace verus
bool IsCompute() const { return _compute; }
ID3D12PipelineState* GetD3DPipelineState() const { return _pPipelineState.Get(); }
ID3D12RootSignature* GetD3DRootSignature() const { return _pRootSignature; }
- D3D_PRIMITIVE_TOPOLOGY GetPrimitiveTopology() const { return _topology; }
+ D3D_PRIMITIVE_TOPOLOGY GetD3DPrimitiveTopology() const { return _topology; }
void FillBlendStateRenderTargets(RcPipelineDesc desc, int attachmentCount, D3D12_BLEND_DESC& blendDesc);
};
VERUS_TYPEDEFS(PipelineD3D12);
diff --git a/RendererDirect3D12/src/CGI/RendererD3D12.cpp b/RendererDirect3D12/src/CGI/RendererD3D12.cpp
index ea0a618..7e6dcd8 100644
--- a/RendererDirect3D12/src/CGI/RendererD3D12.cpp
+++ b/RendererDirect3D12/src/CGI/RendererD3D12.cpp
@@ -90,26 +90,26 @@ void RendererD3D12::EnableDebugLayer()
#endif
}
-ComPtr RendererD3D12::CreateDXGIFactory()
+ComPtr RendererD3D12::CreateFactory()
{
HRESULT hr = 0;
- ComPtr pFactory;
+ ComPtr pFactory;
UINT flags = 0;
#if defined(_DEBUG) || defined(VERUS_RELEASE_DEBUG)
flags = DXGI_CREATE_FACTORY_DEBUG;
#endif
- if (FAILED(hr = CreateDXGIFactory2(flags, IID_PPV_ARGS(&pFactory))))
+ if (FAILED(hr = CreateDXGIFactory2(flags, IID_PPV_ARGS(&pFactory)))) // DXGI 1.3, Windows 8.1.
throw VERUS_RUNTIME_ERROR << "CreateDXGIFactory2(); hr=" << VERUS_HR(hr);
return pFactory;
}
-ComPtr RendererD3D12::GetAdapter(ComPtr pFactory, D3D_FEATURE_LEVEL featureLevel)
+ComPtr RendererD3D12::GetAdapter(ComPtr pFactory, D3D_FEATURE_LEVEL featureLevel)
{
ComPtr pAdapter;
for (UINT index = 0; SUCCEEDED(pFactory->EnumAdapterByGpuPreference(index, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, IID_PPV_ARGS(&pAdapter))); ++index)
{
- DXGI_ADAPTER_DESC1 adapterDesc = {};
- pAdapter->GetDesc1(&adapterDesc);
+ DXGI_ADAPTER_DESC3 adapterDesc = {};
+ pAdapter->GetDesc3(&adapterDesc);
if (adapterDesc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
continue;
if (SUCCEEDED(D3D12CreateDevice(pAdapter.Get(), featureLevel, _uuidof(ID3D12Device), nullptr)))
@@ -120,14 +120,14 @@ ComPtr RendererD3D12::GetAdapter(ComPtr pFactory,
if (!pAdapter)
throw VERUS_RUNTIME_ERROR << "GetAdapter(); Adapter not found";
- DXGI_ADAPTER_DESC1 adapterDesc = {};
- pAdapter->GetDesc1(&adapterDesc);
+ DXGI_ADAPTER_DESC3 adapterDesc = {};
+ pAdapter->GetDesc3(&adapterDesc);
const String description = Str::WideToUtf8(adapterDesc.Description);
VERUS_LOG_INFO("Adapter desc: " << description);
return pAdapter;
}
-bool RendererD3D12::CheckFeatureSupportAllowTearing(ComPtr pFactory)
+bool RendererD3D12::CheckFeatureSupportAllowTearing(ComPtr pFactory)
{
BOOL featureSupportData = FALSE;
if (FAILED(pFactory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &featureSupportData, sizeof(featureSupportData))))
@@ -145,10 +145,10 @@ void RendererD3D12::CreateSwapChainBuffersRTVs()
ComPtr pBuffer;
if (FAILED(hr = _pSwapChain->GetBuffer(i, IID_PPV_ARGS(&pBuffer))))
throw VERUS_RUNTIME_ERROR << "GetBuffer(); hr=" << VERUS_HR(hr);
- D3D12_RENDER_TARGET_VIEW_DESC desc = {};
- desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
- desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
- _pDevice->CreateRenderTargetView(pBuffer.Get(), &desc, _dhSwapChainBuffersRTVs.AtCPU(i));
+ D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
+ rtvDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
+ rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
+ _pDevice->CreateRenderTargetView(pBuffer.Get(), &rtvDesc, _dhSwapChainBuffersRTVs.AtCPU(i));
_vSwapChainBuffers[i] = pBuffer;
}
}
@@ -157,32 +157,39 @@ void RendererD3D12::InitD3D()
{
VERUS_QREF_RENDERER;
VERUS_QREF_CONST_SETTINGS;
-
HRESULT hr = 0;
+ //
+ SDL_Window* pWnd = renderer.GetMainWindow()->GetSDL();
+ VERUS_RT_ASSERT(pWnd);
+ SDL_SysWMinfo wmInfo = {};
+ SDL_VERSION(&wmInfo.version);
+ if (!SDL_GetWindowWMInfo(pWnd, &wmInfo))
+ throw VERUS_RUNTIME_ERROR << "SDL_GetWindowWMInfo()";
+ //
+
#if defined(_DEBUG) || defined(VERUS_RELEASE_DEBUG)
EnableDebugLayer();
#endif
- const D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_11_0;
+ _featureLevel = D3D_FEATURE_LEVEL_11_0;
- ComPtr pFactory = CreateDXGIFactory();
+ ComPtr pFactory = CreateFactory();
+ ComPtr pAdapter = GetAdapter(pFactory, _featureLevel);
- ComPtr pAdapter = GetAdapter(pFactory, featureLevel);
-
- hr = D3D12CreateDevice(pAdapter.Get(), featureLevel, IID_PPV_ARGS(&_pDevice));
+ hr = D3D12CreateDevice(pAdapter.Get(), _featureLevel, IID_PPV_ARGS(&_pDevice));
#if defined(_DEBUG) || defined(VERUS_RELEASE_DEBUG)
if (FAILED(hr))
{
if (FAILED(hr = pFactory->EnumWarpAdapter(IID_PPV_ARGS(&pAdapter))))
throw VERUS_RUNTIME_ERROR << "EnumWarpAdapter(); hr=" << VERUS_HR(hr);
- hr = D3D12CreateDevice(pAdapter.Get(), featureLevel, IID_PPV_ARGS(&_pDevice));
+ hr = D3D12CreateDevice(pAdapter.Get(), _featureLevel, IID_PPV_ARGS(&_pDevice));
}
#endif
if (FAILED(hr))
throw VERUS_RUNTIME_ERROR << "D3D12CreateDevice(); hr=" << VERUS_HR(hr);
- VERUS_RT_ASSERT(D3D_FEATURE_LEVEL_11_0 == featureLevel);
+ VERUS_RT_ASSERT(D3D_FEATURE_LEVEL_11_0 == _featureLevel);
VERUS_LOG_INFO("Using feature level: 11_0");
D3D12MA::ALLOCATOR_DESC allocatorDesc = {};
@@ -201,7 +208,7 @@ void RendererD3D12::InitD3D()
}
#endif
- _pCommandQueue = CreateCommandQueue(D3D12_COMMAND_LIST_TYPE_DIRECT);
+ _pCommandQueue = CreateD3DCommandQueue(D3D12_COMMAND_LIST_TYPE_DIRECT);
const bool allowTearing = CheckFeatureSupportAllowTearing(pFactory);
@@ -210,23 +217,13 @@ void RendererD3D12::InitD3D()
_swapChainDesc.Width = renderer.GetSwapChainWidth();
_swapChainDesc.Height = renderer.GetSwapChainHeight();
_swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
- _swapChainDesc.Stereo = FALSE;
_swapChainDesc.SampleDesc.Count = 1;
_swapChainDesc.SampleDesc.Quality = 0;
_swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
_swapChainDesc.BufferCount = _swapChainBufferCount;
- _swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
_swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
- _swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
_swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT | (allowTearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0);
- SDL_Window* pWnd = renderer.GetMainWindow()->GetSDL();
- VERUS_RT_ASSERT(pWnd);
- SDL_SysWMinfo wmInfo = {};
- SDL_VERSION(&wmInfo.version);
- if (!SDL_GetWindowWMInfo(pWnd, &wmInfo))
- throw VERUS_RUNTIME_ERROR << "SDL_GetWindowWMInfo()";
-
ComPtr pSwapChain1;
switch (settings._platform)
{
@@ -255,16 +252,15 @@ void RendererD3D12::InitD3D()
CreateSwapChainBuffersRTVs();
VERUS_FOR(i, s_ringBufferSize)
- _mapCommandAllocators[i][std::this_thread::get_id()] = CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT);
+ _mapCommandAllocators[i][std::this_thread::get_id()] = CreateD3DCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT);
- _pFence = CreateFence();
+ _pFence = CreateD3DFence();
_hFence = CreateEvent(nullptr, FALSE, FALSE, nullptr);
if (!_hFence)
{
hr = HRESULT_FROM_WIN32(GetLastError());
throw VERUS_RUNTIME_ERROR << "CreateEvent(); hr=" << VERUS_HR(hr);
}
- _fenceValues[_ringBufferIndex]++;
_dhViews.Create(_pDevice.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, settings.GetLimits()._d3d12_dhViewsCapacity, 16, true);
_dhSamplers.Create(_pDevice.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, settings.GetLimits()._d3d12_dhSamplersCapacity, 0, true);
@@ -279,7 +275,7 @@ void RendererD3D12::WaitForFrameLatencyWaitableObject()
throw VERUS_RUNTIME_ERROR << "WaitForFrameLatencyWaitableObject(); ret=" << VERUS_HR(ret);
}
-ComPtr RendererD3D12::CreateCommandQueue(D3D12_COMMAND_LIST_TYPE type)
+ComPtr RendererD3D12::CreateD3DCommandQueue(D3D12_COMMAND_LIST_TYPE type)
{
HRESULT hr = 0;
ComPtr pCommandQueue;
@@ -292,7 +288,7 @@ ComPtr RendererD3D12::CreateCommandQueue(D3D12_COMMAND_LIST_
return pCommandQueue;
}
-ComPtr RendererD3D12::CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE type)
+ComPtr RendererD3D12::CreateD3DCommandAllocator(D3D12_COMMAND_LIST_TYPE type)
{
HRESULT hr = 0;
ComPtr pCommandAllocator;
@@ -301,7 +297,7 @@ ComPtr RendererD3D12::CreateCommandAllocator(D3D12_COMMA
return pCommandAllocator;
}
-ComPtr RendererD3D12::CreateCommandList(D3D12_COMMAND_LIST_TYPE type, ComPtr pCommandAllocator)
+ComPtr RendererD3D12::CreateD3DCommandList(D3D12_COMMAND_LIST_TYPE type, ComPtr pCommandAllocator)
{
HRESULT hr = 0;
ComPtr pGraphicsCommandList;
@@ -312,7 +308,7 @@ ComPtr RendererD3D12::CreateCommandList(D3D12_COMMAN
return pGraphicsCommandList;
}
-ComPtr RendererD3D12::CreateFence()
+ComPtr RendererD3D12::CreateD3DFence()
{
HRESULT hr = 0;
ComPtr pFence;
@@ -324,7 +320,7 @@ ComPtr RendererD3D12::CreateFence()
UINT64 RendererD3D12::QueueSignal()
{
HRESULT hr = 0;
- const UINT64 value = _fenceValues[_ringBufferIndex];
+ const UINT64 value = _nextFenceValue++;
if (FAILED(hr = _pCommandQueue->Signal(_pFence.Get(), value)))
throw VERUS_RUNTIME_ERROR << "Signal(); hr=" << VERUS_HR(hr);
return value;
@@ -344,10 +340,7 @@ void RendererD3D12::WaitForFenceValue(UINT64 value)
void RendererD3D12::QueueWaitIdle()
{
if (_pCommandQueue)
- {
WaitForFenceValue(QueueSignal());
- _fenceValues[_ringBufferIndex]++;
- }
}
void RendererD3D12::CreateSamplers()
@@ -444,7 +437,7 @@ void RendererD3D12::CreateSamplers()
//
}
-D3D12_STATIC_SAMPLER_DESC RendererD3D12::GetStaticSamplerDesc(Sampler s) const
+D3D12_STATIC_SAMPLER_DESC RendererD3D12::GetD3DStaticSamplerDesc(Sampler s) const
{
return _vSamplers[+s];
}
@@ -496,32 +489,34 @@ void RendererD3D12::ImGuiRenderDrawData()
void RendererD3D12::ResizeSwapChain()
{
VERUS_QREF_RENDERER;
+ HRESULT hr = 0;
_dhSwapChainBuffersRTVs.Reset();
_vSwapChainBuffers.clear();
- _pSwapChain->ResizeBuffers(
+ if (FAILED(hr = _pSwapChain->ResizeBuffers(
_swapChainDesc.BufferCount,
renderer.GetSwapChainWidth(),
renderer.GetSwapChainHeight(),
_swapChainDesc.Format,
- _swapChainDesc.Flags);
+ _swapChainDesc.Flags)))
+ throw VERUS_RUNTIME_ERROR << "ResizeBuffers(); hr=" << VERUS_HR(hr);
_swapChainBufferIndex = _pSwapChain->GetCurrentBackBufferIndex();
CreateSwapChainBuffersRTVs();
}
-void RendererD3D12::BeginFrame(bool present)
+void RendererD3D12::BeginFrame()
{
VERUS_QREF_RENDERER;
HRESULT hr = 0;
- if (present)
- {
- WaitForFrameLatencyWaitableObject();
- _swapChainBufferIndex = _pSwapChain->GetCurrentBackBufferIndex();
- }
+ //
+ WaitForFenceValue(_fenceValues[_ringBufferIndex]);
+ //
+
+ _swapChainBufferIndex = -1;
auto pCommandAllocator = _mapCommandAllocators[_ringBufferIndex][std::this_thread::get_id()];
if (FAILED(hr = pCommandAllocator->Reset()))
@@ -536,9 +531,17 @@ void RendererD3D12::BeginFrame(bool present)
ImGui::NewFrame();
}
-void RendererD3D12::EndFrame(bool present)
+void RendererD3D12::AcquireSwapChainImage()
{
+ WaitForFrameLatencyWaitableObject();
+ _swapChainBufferIndex = _pSwapChain->GetCurrentBackBufferIndex();
+}
+
+void RendererD3D12::EndFrame()
+{
+ VERUS_QREF_CONST_SETTINGS;
VERUS_QREF_RENDERER;
+ HRESULT hr = 0;
UpdateScheduled();
@@ -547,30 +550,25 @@ void RendererD3D12::EndFrame(bool present)
auto cb = renderer.GetCommandBuffer();
cb->End();
+ //
ID3D12CommandList* ppCommandLists[] = { static_cast(cb.Get())->GetD3DGraphicsCommandList() };
_pCommandQueue->ExecuteCommandLists(VERUS_COUNT_OF(ppCommandLists), ppCommandLists);
-}
-
-void RendererD3D12::Present()
-{
- VERUS_QREF_CONST_SETTINGS;
- HRESULT hr = 0;
-
- UINT syncInterval = settings._displayVSync ? 1 : 0;
- const bool allowTearing = !!(_swapChainDesc.Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING);
- UINT flags = 0;
- if (!syncInterval && allowTearing && App::DisplayMode::exclusiveFullscreen != settings._displayMode)
- flags |= DXGI_PRESENT_ALLOW_TEARING;
- if (FAILED(hr = _pSwapChain->Present(syncInterval, flags)))
- throw VERUS_RUNTIME_ERROR << "Present(); hr=" << VERUS_HR(hr);
-}
-
-void RendererD3D12::Sync(bool present)
-{
- const UINT64 currentFenceValue = QueueSignal();
+ _fenceValues[_ringBufferIndex] = QueueSignal();
_ringBufferIndex = (_ringBufferIndex + 1) % s_ringBufferSize;
- WaitForFenceValue(_fenceValues[_ringBufferIndex]);
- _fenceValues[_ringBufferIndex] = currentFenceValue + 1;
+ //
+
+ //
+ if (_swapChainBufferIndex >= 0)
+ {
+ UINT syncInterval = settings._displayVSync ? 1 : 0;
+ const bool allowTearing = !!(_swapChainDesc.Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING);
+ UINT flags = 0;
+ if (!syncInterval && allowTearing && App::DisplayMode::exclusiveFullscreen != settings._displayMode)
+ flags |= DXGI_PRESENT_ALLOW_TEARING;
+ if (FAILED(hr = _pSwapChain->Present(syncInterval, flags)))
+ throw VERUS_RUNTIME_ERROR << "Present(); hr=" << VERUS_HR(hr);
+ }
+ //
}
void RendererD3D12::WaitIdle()
@@ -578,6 +576,12 @@ void RendererD3D12::WaitIdle()
QueueWaitIdle();
}
+void RendererD3D12::OnMinimized()
+{
+ WaitIdle();
+ _pSwapChain->Present(0, 0);
+}
+
// Resources:
PBaseCommandBuffer RendererD3D12::InsertCommandBuffer()
diff --git a/RendererDirect3D12/src/CGI/RendererD3D12.h b/RendererDirect3D12/src/CGI/RendererD3D12.h
index 887f831..b2ac227 100644
--- a/RendererDirect3D12/src/CGI/RendererD3D12.h
+++ b/RendererDirect3D12/src/CGI/RendererD3D12.h
@@ -15,22 +15,26 @@ namespace verus
{
typedef Map> TMapCommandAllocators;
+ D3D12MA::Allocator* _pMaAllocator = nullptr;
ComPtr _pDevice;
ComPtr _pCommandQueue;
- D3D12MA::Allocator* _pMaAllocator = nullptr;
ComPtr _pSwapChain;
Vector> _vSwapChainBuffers;
DescriptorHeap _dhSwapChainBuffersRTVs;
+
DynamicDescriptorHeap _dhViews;
DynamicDescriptorHeap _dhSamplers;
TMapCommandAllocators _mapCommandAllocators[s_ringBufferSize];
ComPtr _pFence;
HANDLE _hFence = INVALID_HANDLE_VALUE;
HANDLE _hFrameLatencyWaitableObject = INVALID_HANDLE_VALUE;
+ UINT64 _nextFenceValue = 1;
UINT64 _fenceValues[s_ringBufferSize] = {};
+
Vector _vSamplers;
Vector _vRenderPasses;
Vector _vFramebuffers;
+ D3D_FEATURE_LEVEL _featureLevel = D3D_FEATURE_LEVEL_11_0;
DXGI_SWAP_CHAIN_DESC1 _swapChainDesc = {};
public:
@@ -44,28 +48,30 @@ namespace verus
private:
static void EnableDebugLayer();
- static ComPtr CreateDXGIFactory();
- static ComPtr GetAdapter(ComPtr pFactory, D3D_FEATURE_LEVEL featureLevel);
- static bool CheckFeatureSupportAllowTearing(ComPtr pFactory);
+ static ComPtr CreateFactory();
+ static ComPtr GetAdapter(ComPtr pFactory, D3D_FEATURE_LEVEL featureLevel);
+ static bool CheckFeatureSupportAllowTearing(ComPtr pFactory);
void CreateSwapChainBuffersRTVs();
void InitD3D();
void WaitForFrameLatencyWaitableObject();
public:
- ComPtr CreateCommandQueue(D3D12_COMMAND_LIST_TYPE type);
- ComPtr CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE type);
- ComPtr CreateCommandList(D3D12_COMMAND_LIST_TYPE type, ComPtr pCommandAllocator);
- ComPtr CreateFence();
+ //
+ ComPtr CreateD3DCommandQueue(D3D12_COMMAND_LIST_TYPE type);
+ ComPtr CreateD3DCommandAllocator(D3D12_COMMAND_LIST_TYPE type);
+ ComPtr CreateD3DCommandList(D3D12_COMMAND_LIST_TYPE type, ComPtr pCommandAllocator);
+ ComPtr CreateD3DFence();
UINT64 QueueSignal();
void WaitForFenceValue(UINT64 value);
void QueueWaitIdle();
void CreateSamplers();
ID3D12Device3* GetD3DDevice() const { return _pDevice.Get(); }
- ID3D12CommandQueue* GetCommandQueue() const { return _pCommandQueue.Get(); }
+ ID3D12CommandQueue* GetD3DCommandQueue() const { return _pCommandQueue.Get(); }
D3D12MA::Allocator* GetMaAllocator() const { return _pMaAllocator; }
ID3D12CommandAllocator* GetD3DCommandAllocator(int ringBufferIndex) const { return _mapCommandAllocators[ringBufferIndex].at(std::this_thread::get_id()).Get(); }
- D3D12_STATIC_SAMPLER_DESC GetStaticSamplerDesc(Sampler s) const;
+ D3D12_STATIC_SAMPLER_DESC GetD3DStaticSamplerDesc(Sampler s) const;
+ //
virtual void ImGuiInit(RPHandle renderPassHandle) override;
virtual void ImGuiRenderDrawData() override;
@@ -76,11 +82,11 @@ namespace verus
virtual Gapi GetGapi() override { return Gapi::direct3D12; }
//
- virtual void BeginFrame(bool present) override;
- virtual void EndFrame(bool present) override;
- virtual void Present() override;
- virtual void Sync(bool present) override;
+ virtual void BeginFrame() override;
+ virtual void AcquireSwapChainImage() override;
+ virtual void EndFrame() override;
virtual void WaitIdle() override;
+ virtual void OnMinimized() override;
//
//
diff --git a/RendererDirect3D12/src/CGI/ShaderD3D12.cpp b/RendererDirect3D12/src/CGI/ShaderD3D12.cpp
index e913d71..563c62e 100644
--- a/RendererDirect3D12/src/CGI/ShaderD3D12.cpp
+++ b/RendererDirect3D12/src/CGI/ShaderD3D12.cpp
@@ -119,6 +119,7 @@ void ShaderD3D12::Init(CSZ source, CSZ sourceName, CSZ* branches)
vDefines.push_back({ "VERUS_MAX_BONES", defMaxNumBones });
}
vDefines.push_back({ "_DIRECT3D", "1" });
+ vDefines.push_back({ "_DIRECT3D12", "1" });
const int typeIndex = Utils::Cast32(vDefines.size());
vDefines.push_back({ "_XS", "1" });
vDefines.push_back({});
@@ -211,9 +212,9 @@ void ShaderD3D12::Done()
void ShaderD3D12::CreateDescriptorSet(int setNumber, const void* pSrc, int size, int capacity, std::initializer_list il, ShaderStageFlags stageFlags)
{
VERUS_QREF_RENDERER_D3D12;
- HRESULT hr = 0;
VERUS_RT_ASSERT(_vDescriptorSetDesc.size() == setNumber);
VERUS_RT_ASSERT(!(reinterpret_cast(pSrc) & 0xF));
+ HRESULT hr = 0;
DescriptorSetDesc dsd;
dsd._vSamplers.assign(il);
@@ -335,7 +336,7 @@ void ShaderD3D12::CreatePipelineLayout()
Sampler s = dsd._vSamplers[i];
if (Sampler::input == s)
s = Sampler::nearestMipN;
- D3D12_STATIC_SAMPLER_DESC samplerDesc = pRendererD3D12->GetStaticSamplerDesc(s);
+ D3D12_STATIC_SAMPLER_DESC samplerDesc = pRendererD3D12->GetD3DStaticSamplerDesc(s);
samplerDesc.ShaderRegister = i + 1;
samplerDesc.RegisterSpace = space;
samplerDesc.ShaderVisibility = visibility;
@@ -405,6 +406,7 @@ CSHandle ShaderD3D12::BindDescriptorSetTextures(int setNumber, std::initializer_
{
VERUS_QREF_RENDERER_D3D12;
+ //
int complexSetHandle = -1;
VERUS_FOR(i, _vComplexSets.size())
{
@@ -419,6 +421,7 @@ CSHandle ShaderD3D12::BindDescriptorSetTextures(int setNumber, std::initializer_
complexSetHandle = Utils::Cast32(_vComplexSets.size());
_vComplexSets.resize(complexSetHandle + 1);
}
+ //
bool toViewHeap = false;
if (setNumber & ShaderD3D12::SET_MOD_TO_VIEW_HEAP)
@@ -427,14 +430,14 @@ CSHandle ShaderD3D12::BindDescriptorSetTextures(int setNumber, std::initializer_
toViewHeap = true;
}
- auto& dsd = _vDescriptorSetDesc[setNumber];
+ const auto& dsd = _vDescriptorSetDesc[setNumber];
VERUS_RT_ASSERT(dsd._vSamplers.size() == il.size());
RComplexSet complexSet = _vComplexSets[complexSetHandle];
complexSet._vTextures.reserve(il.size());
- if (toViewHeap)
+ if (toViewHeap) // Copy directly to view heap? This will work only during this frame.
complexSet._hpBase = pRendererD3D12->GetViewHeap().GetNextHandlePair(1 + Utils::Cast32(il.size()));
- else
+ else // Create yet another descriptor heap? There is a limit on their number.
complexSet._dhViews.Create(pRendererD3D12->GetD3DDevice(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, Utils::Cast32(il.size()));
if (!dsd._staticSamplersOnly)
complexSet._dhSamplers.Create(pRendererD3D12->GetD3DDevice(), D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, Utils::Cast32(il.size()));
@@ -469,14 +472,14 @@ CSHandle ShaderD3D12::BindDescriptorSetTextures(int setNumber, std::initializer_
{
pRendererD3D12->GetD3DDevice()->CopyDescriptorsSimple(1,
CD3DX12_CPU_DESCRIPTOR_HANDLE(complexSet._hpBase._hCPU, 1 + index, pRendererD3D12->GetViewHeap().GetHandleIncrementSize()),
- texD3D12.GetDescriptorHeapSRV().AtCPU(mipLevel + arrayLayer * mipLevelCount),
+ texD3D12.GetDescriptorHeapSRV().AtCPU(0),
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
}
else
{
pRendererD3D12->GetD3DDevice()->CopyDescriptorsSimple(1,
complexSet._dhViews.AtCPU(index),
- texD3D12.GetDescriptorHeapSRV().AtCPU(mipLevel + arrayLayer * mipLevelCount),
+ texD3D12.GetDescriptorHeapSRV().AtCPU(0),
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
}
if (Sampler::custom == dsd._vSamplers[index])
@@ -497,9 +500,11 @@ void ShaderD3D12::FreeDescriptorSet(CSHandle& complexSetHandle)
{
if (complexSetHandle.IsSet() && complexSetHandle.Get() < _vComplexSets.size())
{
- _vComplexSets[complexSetHandle.Get()]._vTextures.clear();
- _vComplexSets[complexSetHandle.Get()]._dhViews.Reset();
- _vComplexSets[complexSetHandle.Get()]._dhSamplers.Reset();
+ auto& complexSet = _vComplexSets[complexSetHandle.Get()];
+ complexSet._vTextures.clear();
+ complexSet._dhViews.Reset();
+ complexSet._dhSamplers.Reset();
+ complexSet._hpBase = HandlePair();
}
complexSetHandle = CSHandle();
}
@@ -551,7 +556,7 @@ UINT ShaderD3D12::ToRootParameterIndex(int setNumber) const
bool ShaderD3D12::TryRootConstants(int setNumber, RBaseCommandBuffer cb)
{
- auto& dsd = _vDescriptorSetDesc[setNumber];
+ const auto& dsd = _vDescriptorSetDesc[setNumber];
if (!dsd._capacity)
{
auto& cbD3D12 = static_cast(cb);
@@ -565,31 +570,23 @@ bool ShaderD3D12::TryRootConstants(int setNumber, RBaseCommandBuffer cb)
return false;
}
-CD3DX12_GPU_DESCRIPTOR_HANDLE ShaderD3D12::UpdateUniformBuffer(int setNumber, int complexSetHandle, bool copyDescOnly)
+CD3DX12_GPU_DESCRIPTOR_HANDLE ShaderD3D12::UpdateUniformBuffer(int setNumber, int complexSetHandle)
{
VERUS_QREF_RENDERER_D3D12;
auto& dsd = _vDescriptorSetDesc[setNumber];
- int at = 0;
- if (copyDescOnly)
+ if (dsd._offset + dsd._alignedSize > dsd._capacityInBytes)
{
- at = dsd._capacity * pRendererD3D12->GetRingBufferIndex();
+ VERUS_RT_FAIL("UniformBuffer is full.");
+ return CD3DX12_GPU_DESCRIPTOR_HANDLE(D3D12_DEFAULT);
}
- else
- {
- if (dsd._offset + dsd._alignedSize > dsd._capacityInBytes)
- {
- VERUS_RT_FAIL("UniformBuffer is full.");
- return CD3DX12_GPU_DESCRIPTOR_HANDLE(D3D12_DEFAULT);
- }
- VERUS_RT_ASSERT(dsd._pMappedData);
- at = dsd._capacity * pRendererD3D12->GetRingBufferIndex() + dsd._index;
- memcpy(dsd._pMappedData + dsd._offset, dsd._pSrc, dsd._size);
- dsd._offset += dsd._alignedSize;
- dsd._peakLoad = Math::Max(dsd._peakLoad, dsd._offset);
- dsd._index++;
- }
+ VERUS_RT_ASSERT(dsd._pMappedData);
+ const int at = dsd._capacity * pRendererD3D12->GetRingBufferIndex() + dsd._index;
+ memcpy(dsd._pMappedData + dsd._offset, dsd._pSrc, dsd._size);
+ dsd._offset += dsd._alignedSize;
+ dsd._peakLoad = Math::Max(dsd._peakLoad, dsd._offset);
+ dsd._index++;
bool hpBaseUsed = false;
HandlePair hpBase;
@@ -629,7 +626,7 @@ CD3DX12_GPU_DESCRIPTOR_HANDLE ShaderD3D12::UpdateSamplers(int setNumber, int com
VERUS_QREF_RENDERER_D3D12;
VERUS_RT_ASSERT(complexSetHandle >= 0);
- auto& dsd = _vDescriptorSetDesc[setNumber];
+ const auto& dsd = _vDescriptorSetDesc[setNumber];
if (dsd._staticSamplersOnly)
return CD3DX12_GPU_DESCRIPTOR_HANDLE(D3D12_DEFAULT);
@@ -656,6 +653,7 @@ CD3DX12_GPU_DESCRIPTOR_HANDLE ShaderD3D12::UpdateSamplers(int setNumber, int com
void ShaderD3D12::OnError(CSZ s)
{
VERUS_QREF_RENDERER;
+
if (strstr(s, "HS': entrypoint not found"))
return;
if (strstr(s, "DS': entrypoint not found"))
@@ -786,6 +784,7 @@ void ShaderD3D12::UpdateDebugInfo(
void ShaderD3D12::UpdateUtilization()
{
VERUS_QREF_RENDERER;
+
int setNumber = 0;
for (const auto& dsd : _vDescriptorSetDesc)
{
diff --git a/RendererDirect3D12/src/CGI/ShaderD3D12.h b/RendererDirect3D12/src/CGI/ShaderD3D12.h
index 57664bc..9e11da0 100644
--- a/RendererDirect3D12/src/CGI/ShaderD3D12.h
+++ b/RendererDirect3D12/src/CGI/ShaderD3D12.h
@@ -21,6 +21,11 @@ namespace verus
class ShaderD3D12 : public BaseShader
{
public:
+ enum SET_MOD
+ {
+ SET_MOD_TO_VIEW_HEAP = 0x10000
+ };
+
struct Compiled
{
ComPtr _pBlobs[+Stage::count];
@@ -29,11 +34,6 @@ namespace verus
};
VERUS_TYPEDEFS(Compiled);
- enum SET_MOD
- {
- SET_MOD_TO_VIEW_HEAP = 0x10000
- };
-
private:
typedef Map TMapCompiled;
@@ -98,7 +98,7 @@ namespace verus
UINT ToRootParameterIndex(int setNumber) const;
bool TryRootConstants(int setNumber, RBaseCommandBuffer cb);
- CD3DX12_GPU_DESCRIPTOR_HANDLE UpdateUniformBuffer(int setNumber, int complexSetHandle, bool copyDescOnly = false);
+ CD3DX12_GPU_DESCRIPTOR_HANDLE UpdateUniformBuffer(int setNumber, int complexSetHandle);
CD3DX12_GPU_DESCRIPTOR_HANDLE UpdateSamplers(int setNumber, int complexSetHandle);
int GetDescriptorSetCount() const { return static_cast(_vDescriptorSetDesc.size()); }
bool IsCompute() const { return _compute; }
diff --git a/RendererDirect3D12/src/CGI/TextureD3D12.cpp b/RendererDirect3D12/src/CGI/TextureD3D12.cpp
index 06338fc..fd73bc7 100644
--- a/RendererDirect3D12/src/CGI/TextureD3D12.cpp
+++ b/RendererDirect3D12/src/CGI/TextureD3D12.cpp
@@ -89,25 +89,25 @@ void TextureD3D12::Init(RcTextureDesc desc)
if (_desc._flags & TextureDesc::Flags::generateMips)
{
VERUS_RT_ASSERT(_desc._mipLevels > 1);
- // Create storage image for compute shader's output. No need to have the first mip level.
- const int uavMipLevels = Math::Max(1, _desc._mipLevels - 1);
- D3D12_RESOURCE_DESC resDescUAV = resDesc;
- resDescUAV.Width = Math::Max(1, _desc._width >> 1);
- resDescUAV.Height = Math::Max(1, _desc._height >> 1);
- resDescUAV.MipLevels = uavMipLevels;
- resDescUAV.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
+ // Create storage image for compute shader. First mip level is not required.
+ const int uaMipLevels = Math::Max(1, _desc._mipLevels - 1);
+ D3D12_RESOURCE_DESC uaResDesc = resDesc;
+ uaResDesc.Width = Math::Max(1, _desc._width >> 1);
+ uaResDesc.Height = Math::Max(1, _desc._height >> 1);
+ uaResDesc.MipLevels = uaMipLevels;
+ uaResDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
// sRGB cannot be used with UAV:
- switch (resDescUAV.Format)
+ switch (uaResDesc.Format)
{
- case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: resDescUAV.Format = DXGI_FORMAT_R8G8B8A8_UNORM; break;
- case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: resDescUAV.Format = DXGI_FORMAT_B8G8R8A8_UNORM; break;
+ case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: uaResDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; break;
+ case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: uaResDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; break;
}
D3D12MA::ALLOCATION_DESC allocDesc = {};
allocDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT;
if (FAILED(hr = pRendererD3D12->GetMaAllocator()->CreateResource(
&allocDesc,
- &resDescUAV,
+ &uaResDesc,
D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
nullptr,
&_uaResource._pMaAllocation,
@@ -116,13 +116,13 @@ void TextureD3D12::Init(RcTextureDesc desc)
_uaResource._pResource->SetName(_C(Str::Utf8ToWide(_name + " (UAV)")));
_vCshGenerateMips.reserve(Math::DivideByMultiple(_desc._mipLevels, 4));
- _dhUAV.Create(pRendererD3D12->GetD3DDevice(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, uavMipLevels * _desc._arrayLayers);
+ _dhUAV.Create(pRendererD3D12->GetD3DDevice(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, uaMipLevels * _desc._arrayLayers);
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
- uavDesc.Format = resDescUAV.Format;
+ uavDesc.Format = uaResDesc.Format;
uavDesc.ViewDimension = (_desc._arrayLayers > 1) ? D3D12_UAV_DIMENSION_TEXTURE2DARRAY : D3D12_UAV_DIMENSION_TEXTURE2D;
VERUS_FOR(layer, _desc._arrayLayers)
{
- VERUS_FOR(mip, uavMipLevels)
+ VERUS_FOR(mip, uaMipLevels)
{
if (D3D12_UAV_DIMENSION_TEXTURE2D == uavDesc.ViewDimension)
{
@@ -140,7 +140,7 @@ void TextureD3D12::Init(RcTextureDesc desc)
const int faceIndex = layer % +CubeMapFace::count;
uavDesc.Texture2DArray.FirstArraySlice = (cubeIndex * +CubeMapFace::count) + ToNativeCubeMapFace(static_cast(faceIndex));
}
- pRendererD3D12->GetD3DDevice()->CreateUnorderedAccessView(_uaResource._pResource.Get(), nullptr, &uavDesc, _dhUAV.AtCPU(mip + layer * uavMipLevels));
+ pRendererD3D12->GetD3DDevice()->CreateUnorderedAccessView(_uaResource._pResource.Get(), nullptr, &uavDesc, _dhUAV.AtCPU(mip + layer * uaMipLevels));
}
}
}
@@ -155,7 +155,7 @@ void TextureD3D12::Init(RcTextureDesc desc)
const int h = Math::Max(1, _desc._height >> _desc._readbackMip);
const UINT64 bufferSize = _bytesPerPixel * w * h;
_vReadbackBuffers.resize(BaseRenderer::s_ringBufferSize);
- for (auto& x : _vReadbackBuffers)
+ for (auto& readbackBuffer : _vReadbackBuffers)
{
D3D12MA::ALLOCATION_DESC allocDesc = {};
allocDesc.HeapType = D3D12_HEAP_TYPE_READBACK;
@@ -165,10 +165,10 @@ void TextureD3D12::Init(RcTextureDesc desc)
&resDesc,
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
- &x._pMaAllocation,
- IID_PPV_ARGS(&x._pResource))))
+ &readbackBuffer._pMaAllocation,
+ IID_PPV_ARGS(&readbackBuffer._pResource))))
throw VERUS_RUNTIME_ERROR << "CreateResource(D3D12_HEAP_TYPE_READBACK); hr=" << VERUS_HR(hr);
- x._pResource->SetName(_C(Str::Utf8ToWide(_name + " (Readback)")));
+ readbackBuffer._pResource->SetName(_C(Str::Utf8ToWide(_name + " (Readback)")));
}
}
@@ -181,7 +181,6 @@ void TextureD3D12::Init(RcTextureDesc desc)
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
rtvDesc.Format = ToNativeFormat(_desc._format, false);
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
- rtvDesc.Texture2DArray.MipSlice = 0;
VERUS_FOR(i, +CubeMapFace::count)
{
rtvDesc.Texture2DArray.FirstArraySlice = ToNativeCubeMapFace(static_cast(i));
@@ -200,16 +199,14 @@ void TextureD3D12::Init(RcTextureDesc desc)
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
dsvDesc.Format = clearValue.Format;
dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
- dsvDesc.Texture2D.MipSlice = 0;
_dhDSV.Create(pRendererD3D12->GetD3DDevice(), D3D12_DESCRIPTOR_HEAP_TYPE_DSV, 1);
- pRendererD3D12->GetD3DDevice()->CreateDepthStencilView(_resource._pResource.Get(), depthSampled ? &dsvDesc : nullptr, _dhDSV.AtCPU(0));
+ pRendererD3D12->GetD3DDevice()->CreateDepthStencilView(_resource._pResource.Get(), &dsvDesc, _dhDSV.AtCPU(0));
if (depthSampled)
{
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
srvDesc.Format = ToNativeSampledDepthFormat(_desc._format);
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
- srvDesc.Texture2D.MostDetailedMip = 0;
srvDesc.Texture2D.MipLevels = 1;
_dhSRV.Create(pRendererD3D12->GetD3DDevice(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 1);
pRendererD3D12->GetD3DDevice()->CreateShaderResourceView(_resource._pResource.Get(), &srvDesc, _dhSRV.AtCPU(0));
@@ -225,14 +222,12 @@ void TextureD3D12::Init(RcTextureDesc desc)
if (_desc._arrayLayers > +CubeMapFace::count)
{
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBEARRAY;
- srvDesc.TextureCubeArray.MostDetailedMip = 0;
srvDesc.TextureCubeArray.MipLevels = _desc._mipLevels;
srvDesc.TextureCubeArray.NumCubes = _desc._arrayLayers / +CubeMapFace::count;
}
else
{
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
- srvDesc.TextureCube.MostDetailedMip = 0;
srvDesc.TextureCube.MipLevels = _desc._mipLevels;
}
_dhSRV.Create(pRendererD3D12->GetD3DDevice(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 1);
@@ -256,6 +251,14 @@ void TextureD3D12::Done()
{
ForceScheduled();
+ _dhSampler.Reset();
+ _dhDSV.Reset();
+ _dhRTV.Reset();
+ _dhUAV.Reset();
+ _dhSRV.Reset();
+
+ _vCshGenerateMips.clear();
+
for (auto& x : _vReadbackBuffers)
{
VERUS_SMART_RELEASE(x._pMaAllocation);
@@ -263,10 +266,7 @@ void TextureD3D12::Done()
x._pResource.Reset();
}
_vReadbackBuffers.clear();
- _dhSampler.Reset();
- _dhDSV.Reset();
- _dhRTV.Reset();
- _dhSRV.Reset();
+
VERUS_SMART_RELEASE(_uaResource._pMaAllocation);
VERUS_COM_RELEASE_CHECK(_uaResource._pResource.Get());
_uaResource._pResource.Reset();
@@ -330,11 +330,8 @@ void TextureD3D12::UpdateSubresource(const void* p, int mipLevel, int arrayLayer
UpdateSubresources<1>(
pCmdList,
_resource._pResource.Get(),
- sb._pResource.Get(),
- 0,
- subresource,
- 1,
- &sd);
+ sb._pResource.Get(), 0,
+ subresource, 1, &sd);
pCB->PipelineImageMemoryBarrier(TexturePtr::From(this), ImageLayout::transferDst, _mainLayout, mipLevel, arrayLayer);
Schedule();
diff --git a/RendererDirect3D12/src/ThirdParty/imgui/imgui_impl_dx12.cpp b/RendererDirect3D12/src/ThirdParty/imgui/imgui_impl_dx12.cpp
index 9e87f81..c662cba 100644
--- a/RendererDirect3D12/src/ThirdParty/imgui/imgui_impl_dx12.cpp
+++ b/RendererDirect3D12/src/ThirdParty/imgui/imgui_impl_dx12.cpp
@@ -71,10 +71,10 @@ struct ImGui_ImplDX12_Data
UINT numFramesInFlight;
UINT frameIndex;
- ImGui_ImplDX12_Data() { memset(this, 0, sizeof(*this)); frameIndex = UINT_MAX; }
+ ImGui_ImplDX12_Data() { memset((void*)this, 0, sizeof(*this)); frameIndex = UINT_MAX; }
};
-struct VERTEX_CONSTANT_BUFFER
+struct VERTEX_CONSTANT_BUFFER_DX12
{
float mvp[4][4];
};
@@ -93,7 +93,7 @@ static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12Graphic
// Setup orthographic projection matrix into our constant buffer
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right).
- VERTEX_CONSTANT_BUFFER vertex_constant_buffer;
+ VERTEX_CONSTANT_BUFFER_DX12 vertex_constant_buffer;
{
float L = draw_data->DisplayPos.x;
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
@@ -466,6 +466,7 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
param[1].DescriptorTable.pDescriptorRanges = &descRange;
param[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
+ // Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling.
D3D12_STATIC_SAMPLER_DESC staticSampler = {};
staticSampler.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
staticSampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
diff --git a/RendererDirect3D12/src/main.cpp b/RendererDirect3D12/src/main.cpp
index 95c51bf..d6ed995 100644
--- a/RendererDirect3D12/src/main.cpp
+++ b/RendererDirect3D12/src/main.cpp
@@ -25,7 +25,7 @@ extern "C"
if (VERUS_SDK_VERSION != version)
{
- VERUS_RT_FAIL("CreateRenderer(), Wrong version.");
+ VERUS_RT_FAIL("CreateRenderer(); Wrong version.");
return nullptr;
}
diff --git a/RendererVulkan/src/CGI/CommandBufferVulkan.cpp b/RendererVulkan/src/CGI/CommandBufferVulkan.cpp
index a0ec904..1df6ab0 100644
--- a/RendererVulkan/src/CGI/CommandBufferVulkan.cpp
+++ b/RendererVulkan/src/CGI/CommandBufferVulkan.cpp
@@ -19,7 +19,7 @@ void CommandBufferVulkan::Init()
VERUS_QREF_RENDERER_VULKAN;
VERUS_FOR(i, BaseRenderer::s_ringBufferSize)
- _commandBuffers[i] = pRendererVulkan->CreateCommandBuffer(pRendererVulkan->GetVkCommandPool(i));
+ _commandBuffers[i] = pRendererVulkan->CreateVkCommandBuffer(pRendererVulkan->GetVkCommandPool(i));
}
void CommandBufferVulkan::Done()
@@ -31,9 +31,10 @@ void CommandBufferVulkan::InitOneTimeSubmit()
{
VERUS_QREF_RENDERER;
VERUS_QREF_RENDERER_VULKAN;
+
_oneTimeSubmit = true;
auto commandPool = pRendererVulkan->GetVkCommandPool(renderer->GetRingBufferIndex());
- auto commandBuffer = pRendererVulkan->CreateCommandBuffer(commandPool);
+ auto commandBuffer = pRendererVulkan->CreateVkCommandBuffer(commandPool);
VERUS_FOR(i, BaseRenderer::s_ringBufferSize)
_commandBuffers[i] = commandBuffer;
Begin();
@@ -43,9 +44,9 @@ void CommandBufferVulkan::DoneOneTimeSubmit()
{
VERUS_QREF_RENDERER;
VERUS_QREF_RENDERER_VULKAN;
+
End();
- VkSubmitInfo submitInfo = {};
- submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+ VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = _commandBuffers;
vkQueueSubmit(pRendererVulkan->GetVkGraphicsQueue(), 1, &submitInfo, VK_NULL_HANDLE);
@@ -58,8 +59,7 @@ void CommandBufferVulkan::DoneOneTimeSubmit()
void CommandBufferVulkan::Begin()
{
VkResult res = VK_SUCCESS;
- VkCommandBufferBeginInfo vkcbbi = {};
- vkcbbi.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+ VkCommandBufferBeginInfo vkcbbi = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
if (_oneTimeSubmit)
vkcbbi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
if (VK_SUCCESS != (res = vkBeginCommandBuffer(GetVkCommandBuffer(), &vkcbbi)))
@@ -80,8 +80,7 @@ void CommandBufferVulkan::PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; // Which stage is waiting to start (BOTTOM_OF_PIPE means nothing is waiting).
const VkPipelineStageFlags dstStageMaskXS = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
- VkImageMemoryBarrier vkimb = {};
- vkimb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+ VkImageMemoryBarrier vkimb = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
vkimb.oldLayout = ToNativeImageLayout(oldLayout);
vkimb.newLayout = ToNativeImageLayout(newLayout);
vkimb.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
@@ -186,10 +185,10 @@ void CommandBufferVulkan::PipelineImageMemoryBarrier(TexturePtr tex, ImageLayout
void CommandBufferVulkan::BeginRenderPass(RPHandle renderPassHandle, FBHandle framebufferHandle, std::initializer_list ilClearValues, bool setViewportAndScissor)
{
VERUS_QREF_RENDERER_VULKAN;
+
RendererVulkan::RcFramebuffer framebuffer = pRendererVulkan->GetFramebuffer(framebufferHandle);
// The application must ensure (using scissor if necessary) that all rendering is contained within the render area.
- VkRenderPassBeginInfo vkrpbi = {};
- vkrpbi.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+ VkRenderPassBeginInfo vkrpbi = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
vkrpbi.renderPass = pRendererVulkan->GetRenderPass(renderPassHandle);
vkrpbi.framebuffer = framebuffer._framebuffer;
vkrpbi.renderArea.extent.width = framebuffer._width;
@@ -308,12 +307,10 @@ void CommandBufferVulkan::BindIndexBuffer(GeometryPtr geo)
bool CommandBufferVulkan::BindDescriptors(ShaderPtr shader, int setNumber, CSHandle complexSetHandle)
{
- if (setNumber < 0)
- return true;
-
auto& shaderVulkan = static_cast(*shader);
if (shaderVulkan.TryPushConstants(setNumber, *this))
return true;
+
const int offset = shaderVulkan.UpdateUniformBuffer(setNumber);
if (offset < 0)
return false;
diff --git a/RendererVulkan/src/CGI/GeometryVulkan.cpp b/RendererVulkan/src/CGI/GeometryVulkan.cpp
index 177b462..1752bfa 100644
--- a/RendererVulkan/src/CGI/GeometryVulkan.cpp
+++ b/RendererVulkan/src/CGI/GeometryVulkan.cpp
@@ -84,6 +84,7 @@ void GeometryVulkan::Done()
VERUS_VULKAN_DESTROY(_indexBuffer._buffer, vmaDestroyBuffer(pRendererVulkan->GetVmaAllocator(), _indexBuffer._buffer, _indexBuffer._vmaAllocation));
for (auto& x : _vVertexBuffers)
VERUS_VULKAN_DESTROY(x._buffer, vmaDestroyBuffer(pRendererVulkan->GetVmaAllocator(), x._buffer, x._vmaAllocation));
+ _vVertexBuffers.clear();
VERUS_DONE(GeometryVulkan);
}
@@ -121,6 +122,7 @@ void GeometryVulkan::UpdateVertexBuffer(const void* p, int binding, PBaseCommand
auto& vb = _vVertexBuffers[binding];
const int elementSize = _vStrides[binding];
size = size ? size * elementSize : vb._bufferSize;
+
void* pData = nullptr;
if (VK_SUCCESS != (res = vmaMapMemory(pRendererVulkan->GetVmaAllocator(), vb._vmaAllocation, &pData)))
throw VERUS_RECOVERABLE << "vmaMapMemory(); res=" << res;
@@ -182,6 +184,7 @@ void GeometryVulkan::UpdateIndexBuffer(const void* p, PBaseCommandBuffer pCB, IN
{
const int elementSize = _32BitIndices ? sizeof(UINT32) : sizeof(UINT16);
size = size ? size * elementSize : _indexBuffer._bufferSize;
+
void* pData = nullptr;
if (VK_SUCCESS != (res = vmaMapMemory(pRendererVulkan->GetVmaAllocator(), _indexBuffer._vmaAllocation, &pData)))
throw VERUS_RECOVERABLE << "vmaMapMemory(); res=" << res;
@@ -219,6 +222,7 @@ Continue GeometryVulkan::Scheduled_Update()
VERUS_VULKAN_DESTROY(_stagingIndexBuffer._buffer, vmaDestroyBuffer(pRendererVulkan->GetVmaAllocator(), _stagingIndexBuffer._buffer, _stagingIndexBuffer._vmaAllocation));
for (auto& x : _vStagingVertexBuffers)
VERUS_VULKAN_DESTROY(x._buffer, vmaDestroyBuffer(pRendererVulkan->GetVmaAllocator(), x._buffer, x._vmaAllocation));
+ _vStagingVertexBuffers.clear();
return Continue::no;
}
@@ -228,8 +232,7 @@ VkPipelineVertexInputStateCreateInfo GeometryVulkan::GetVkPipelineVertexInputSta
{
if (UINT32_MAX == bindingsFilter)
{
- VkPipelineVertexInputStateCreateInfo vertexInputState = {};
- vertexInputState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+ VkPipelineVertexInputStateCreateInfo vertexInputState = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
vertexInputState.vertexBindingDescriptionCount = Utils::Cast32(_vVertexInputBindingDesc.size());
vertexInputState.pVertexBindingDescriptions = _vVertexInputBindingDesc.data();
vertexInputState.vertexAttributeDescriptionCount = Utils::Cast32(_vVertexInputAttributeDesc.size());
@@ -265,8 +268,7 @@ VkPipelineVertexInputStateCreateInfo GeometryVulkan::GetVkPipelineVertexInputSta
}
}
- VkPipelineVertexInputStateCreateInfo vertexInputState = {};
- vertexInputState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+ VkPipelineVertexInputStateCreateInfo vertexInputState = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
vertexInputState.vertexBindingDescriptionCount = Utils::Cast32(vVertexInputBindingDesc.size());
vertexInputState.pVertexBindingDescriptions = vVertexInputBindingDesc.data();
vertexInputState.vertexAttributeDescriptionCount = Utils::Cast32(vVertexInputAttributeDesc.size());
diff --git a/RendererVulkan/src/CGI/GeometryVulkan.h b/RendererVulkan/src/CGI/GeometryVulkan.h
index a6989cd..4b40edf 100644
--- a/RendererVulkan/src/CGI/GeometryVulkan.h
+++ b/RendererVulkan/src/CGI/GeometryVulkan.h
@@ -7,18 +7,18 @@ namespace verus
{
class GeometryVulkan : public BaseGeometry
{
- struct VkBufferEx
+ struct BufferEx
{
- VkBuffer _buffer = VK_NULL_HANDLE;
VmaAllocation _vmaAllocation = VK_NULL_HANDLE;
+ VkBuffer _buffer = VK_NULL_HANDLE;
VkDeviceSize _bufferSize = 0;
INT64 _utilization = -1;
};
- Vector _vVertexBuffers;
- VkBufferEx _indexBuffer;
- Vector _vStagingVertexBuffers;
- VkBufferEx _stagingIndexBuffer;
+ Vector _vVertexBuffers;
+ BufferEx _indexBuffer;
+ Vector _vStagingVertexBuffers;
+ BufferEx _stagingIndexBuffer;
Vector _vVertexInputBindingDesc;
Vector _vVertexInputAttributeDesc;
Vector _vStrides;
diff --git a/RendererVulkan/src/CGI/Native.cpp b/RendererVulkan/src/CGI/Native.cpp
index e3bb04e..364d105 100644
--- a/RendererVulkan/src/CGI/Native.cpp
+++ b/RendererVulkan/src/CGI/Native.cpp
@@ -114,6 +114,10 @@ VkShaderStageFlags CGI::ToNativeStageFlags(ShaderStageFlags stageFlags)
ret |= VK_SHADER_STAGE_INTERSECTION_BIT_KHR;
if (stageFlags & ShaderStageFlags::rtc)
ret |= VK_SHADER_STAGE_CALLABLE_BIT_KHR;
+ if (stageFlags & ShaderStageFlags::ts)
+ ret |= VK_SHADER_STAGE_TASK_BIT_NV;
+ if (stageFlags & ShaderStageFlags::ms)
+ ret |= VK_SHADER_STAGE_MESH_BIT_NV;
return ret;
}
diff --git a/RendererVulkan/src/CGI/PipelineVulkan.cpp b/RendererVulkan/src/CGI/PipelineVulkan.cpp
index fd291a6..d238775 100644
--- a/RendererVulkan/src/CGI/PipelineVulkan.cpp
+++ b/RendererVulkan/src/CGI/PipelineVulkan.cpp
@@ -51,8 +51,7 @@ void PipelineVulkan::Init(RcPipelineDesc desc)
entryNames[+stage] = compiled._entry + suffix;
if (shaderModule != VK_NULL_HANDLE)
{
- VkPipelineShaderStageCreateInfo vkpssci = {};
- vkpssci.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ VkPipelineShaderStageCreateInfo vkpssci = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
vkpssci.stage = shaderStageFlagBits;
vkpssci.module = shaderModule;
vkpssci.pName = _C(entryNames[+stage]);
@@ -70,31 +69,26 @@ void PipelineVulkan::Init(RcPipelineDesc desc)
VkPipelineVertexInputStateCreateInfo vertexInputState = geo.GetVkPipelineVertexInputStateCreateInfo(_vertexInputBindingsFilter,
vVertexInputBindingDesc, vVertexInputAttributeDesc);
- VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = {};
- inputAssemblyState.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+ VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
inputAssemblyState.topology = ToNativePrimitiveTopology(desc._topology);
inputAssemblyState.primitiveRestartEnable = desc._primitiveRestartEnable;
- VkPipelineTessellationStateCreateInfo tessellationState = {};
- tessellationState.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
+ VkPipelineTessellationStateCreateInfo tessellationState = { VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO };
tessellationState.patchControlPoints = 3;
switch (desc._topology)
{
case PrimitiveTopology::patchList4: tessellationState.patchControlPoints = 4; break;
}
- VkPipelineViewportStateCreateInfo viewportState = {};
- viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
+ VkPipelineViewportStateCreateInfo viewportState = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
viewportState.viewportCount = 1;
viewportState.scissorCount = 1;
- VkPipelineRasterizationLineStateCreateInfoEXT rasterizationLineState = {};
- rasterizationLineState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT;
+ VkPipelineRasterizationLineStateCreateInfoEXT rasterizationLineState = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT };
rasterizationLineState.lineRasterizationMode = VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT;
if (desc._colorAttachBlendEqs[0] == VERUS_COLOR_BLEND_ALPHA)
rasterizationLineState.lineRasterizationMode = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT;
- VkPipelineRasterizationStateCreateInfo rasterizationState = {};
- rasterizationState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+ VkPipelineRasterizationStateCreateInfo rasterizationState = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
rasterizationState.pNext = pRendererVulkan->IsAdvancedLineRasterizationSupported() ? &rasterizationLineState : nullptr;
rasterizationState.depthClampEnable = VK_FALSE;
rasterizationState.polygonMode = ToNativePolygonMode(desc._rasterizationState._polygonMode);
@@ -106,12 +100,10 @@ void PipelineVulkan::Init(RcPipelineDesc desc)
rasterizationState.depthBiasSlopeFactor = desc._rasterizationState._depthBiasSlopeFactor;
rasterizationState.lineWidth = 1;
- VkPipelineMultisampleStateCreateInfo multisampleState = {};
- multisampleState.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+ VkPipelineMultisampleStateCreateInfo multisampleState = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
multisampleState.rasterizationSamples = ToNativeSampleCount(desc._sampleCount);
- VkPipelineDepthStencilStateCreateInfo depthStencilState = {};
- depthStencilState.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
+ VkPipelineDepthStencilStateCreateInfo depthStencilState = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO };
depthStencilState.depthTestEnable = desc._depthTestEnable;
depthStencilState.depthWriteEnable = desc._depthWriteEnable;
depthStencilState.depthCompareOp = ToNativeCompareOp(desc._depthCompareOp);
@@ -119,8 +111,7 @@ void PipelineVulkan::Init(RcPipelineDesc desc)
VkPipelineColorBlendAttachmentState vkpcbas[VERUS_MAX_CA] = {};
FillColorBlendAttachmentStates(desc, attachmentCount, vkpcbas);
- VkPipelineColorBlendStateCreateInfo colorBlendState = {};
- colorBlendState.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+ VkPipelineColorBlendStateCreateInfo colorBlendState = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };
colorBlendState.logicOpEnable = VK_FALSE;
colorBlendState.logicOp = VK_LOGIC_OP_CLEAR;
colorBlendState.attachmentCount = attachmentCount;
@@ -131,13 +122,11 @@ void PipelineVulkan::Init(RcPipelineDesc desc)
colorBlendState.blendConstants[3] = 1;
VkDynamicState dynamicStates[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_BLEND_CONSTANTS };
- VkPipelineDynamicStateCreateInfo dynamicState = {};
- dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
+ VkPipelineDynamicStateCreateInfo dynamicState = { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO };
dynamicState.dynamicStateCount = VERUS_COUNT_OF(dynamicStates);
dynamicState.pDynamicStates = dynamicStates;
- VkGraphicsPipelineCreateInfo vkgpci = {};
- vkgpci.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+ VkGraphicsPipelineCreateInfo vkgpci = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };
vkgpci.stageCount = Utils::Cast32(vShaderStages.size());
vkgpci.pStages = vShaderStages.data();
vkgpci.pVertexInputState = &vertexInputState;
@@ -177,8 +166,7 @@ void PipelineVulkan::InitCompute(RcPipelineDesc desc)
const VkShaderModule shaderModule = compiled._shaderModules[+BaseShader::Stage::cs];
String entryName = compiled._entry + "CS";
- VkComputePipelineCreateInfo vkcpci = {};
- vkcpci.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
+ VkComputePipelineCreateInfo vkcpci = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO };
vkcpci.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
vkcpci.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT;
vkcpci.stage.module = shaderModule;
diff --git a/RendererVulkan/src/CGI/RendererVulkan.cpp b/RendererVulkan/src/CGI/RendererVulkan.cpp
index 3e476a9..4660fdc 100644
--- a/RendererVulkan/src/CGI/RendererVulkan.cpp
+++ b/RendererVulkan/src/CGI/RendererVulkan.cpp
@@ -251,27 +251,24 @@ void RendererVulkan::CreateInstance()
const int patch = (VERUS_SDK_VERSION) & 0xFFFF;
VkValidationFeatureEnableEXT enabledValidationFeatures[] = { VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT };
- VkValidationFeaturesEXT vkvf = {};
- vkvf.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT;
+ VkValidationFeaturesEXT vkvf = { VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT };
vkvf.enabledValidationFeatureCount = VERUS_COUNT_OF(enabledValidationFeatures);
vkvf.pEnabledValidationFeatures = enabledValidationFeatures;
- VkApplicationInfo vkai = {};
- vkai.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
+ VkApplicationInfo vkai = { VK_STRUCTURE_TYPE_APPLICATION_INFO };
vkai.pApplicationName = "Game";
vkai.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
vkai.pEngineName = "Verus";
vkai.engineVersion = VK_MAKE_VERSION(major, minor, patch);
vkai.apiVersion = s_apiVersion;
- VkInstanceCreateInfo vkici = {};
- vkici.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
+ VkInstanceCreateInfo vkici = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
vkici.pApplicationInfo = &vkai;
vkici.enabledExtensionCount = Utils::Cast32(vExtensions.size());
vkici.ppEnabledExtensionNames = vExtensions.data();
#if defined(_DEBUG) || defined(VERUS_RELEASE_DEBUG)
vkici.pNext = &vkvf;
- VkDebugUtilsMessengerCreateInfoEXT vkdumci = {};
+ VkDebugUtilsMessengerCreateInfoEXT vkdumci = { VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT };
FillDebugUtilsMessengerCreateInfo(vkdumci);
vkvf.pNext = &vkdumci;
vkici.enabledLayerCount = VERUS_COUNT_OF(s_requiredValidationLayers);
@@ -283,7 +280,6 @@ void RendererVulkan::CreateInstance()
void RendererVulkan::FillDebugUtilsMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& vkdumci)
{
- vkdumci.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
vkdumci.messageSeverity =
#if defined(_DEBUG) || defined(VERUS_RELEASE_DEBUG)
VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
@@ -405,10 +401,8 @@ void RendererVulkan::CreateDevice()
VERUS_QREF_CONST_SETTINGS;
VkResult res = VK_SUCCESS;
- VkPhysicalDeviceLineRasterizationFeaturesEXT lineRasterizationFeatures = {};
- lineRasterizationFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT;
- VkPhysicalDeviceFeatures2 vkpdf2 = {};
- vkpdf2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+ VkPhysicalDeviceLineRasterizationFeaturesEXT lineRasterizationFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT };
+ VkPhysicalDeviceFeatures2 vkpdf2 = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 };
vkpdf2.pNext = &lineRasterizationFeatures;
vkGetPhysicalDeviceFeatures2(_physicalDevice, &vkpdf2);
@@ -428,8 +422,7 @@ void RendererVulkan::CreateDevice()
const float queuePriorities[] = { 1.0f };
for (int queueFamilyIndex : setUniqueQueueFamilies)
{
- VkDeviceQueueCreateInfo vkdqci = {};
- vkdqci.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
+ VkDeviceQueueCreateInfo vkdqci = { VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO };
vkdqci.queueFamilyIndex = queueFamilyIndex;
vkdqci.queueCount = 1;
vkdqci.pQueuePriorities = queuePriorities;
@@ -446,8 +439,7 @@ void RendererVulkan::CreateDevice()
physicalDeviceFeatures.shaderImageGatherExtended = VK_TRUE; // 94%
physicalDeviceFeatures.tessellationShader = settings._gpuTessellation ? VK_TRUE : VK_FALSE; // 81%
- VkDeviceCreateInfo vkdci = {};
- vkdci.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
+ VkDeviceCreateInfo vkdci = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
vkdci.pNext = &lineRasterizationFeatures;
vkdci.queueCreateInfoCount = Utils::Cast32(vDeviceQueueCreateInfos.size());
vkdci.pQueueCreateInfos = vDeviceQueueCreateInfos.data();
@@ -507,8 +499,7 @@ void RendererVulkan::CreateSwapChain(VkSwapchainKHR oldSwapchain)
const uint32_t height = Math::Clamp(renderer.GetSwapChainHeight(),
swapChainInfo._surfaceCapabilities.minImageExtent.height, swapChainInfo._surfaceCapabilities.maxImageExtent.height);
- VkSwapchainCreateInfoKHR vksci = {};
- vksci.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
+ VkSwapchainCreateInfoKHR vksci = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR };
vksci.surface = _surface;
vksci.minImageCount = _swapChainBufferCount;
vksci.imageFormat = VK_FORMAT_B8G8R8A8_SRGB;
@@ -553,8 +544,7 @@ void RendererVulkan::CreateImageViews()
_vSwapChainImageViews.resize(_swapChainBufferCount);
VERUS_FOR(i, _swapChainBufferCount)
{
- VkImageViewCreateInfo vkivci = {};
- vkivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ VkImageViewCreateInfo vkivci = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
vkivci.image = _vSwapChainImages[i];
vkivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
vkivci.format = VK_FORMAT_B8G8R8A8_SRGB;
@@ -577,8 +567,7 @@ void RendererVulkan::CreateCommandPools()
VkResult res = VK_SUCCESS;
VERUS_FOR(i, s_ringBufferSize)
{
- VkCommandPoolCreateInfo vkcpci = {};
- vkcpci.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
+ VkCommandPoolCreateInfo vkcpci = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
vkcpci.queueFamilyIndex = _queueFamilyIndices._graphicsFamilyIndex;
if (VK_SUCCESS != (res = vkCreateCommandPool(_device, &vkcpci, GetAllocator(), &_commandPools[i])))
throw VERUS_RUNTIME_ERROR << "vkCreateCommandPool(); res=" << res;
@@ -588,10 +577,8 @@ void RendererVulkan::CreateCommandPools()
void RendererVulkan::CreateSyncObjects()
{
VkResult res = VK_SUCCESS;
- VkSemaphoreCreateInfo vksci = {};
- vksci.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
- VkFenceCreateInfo vkfci = {};
- vkfci.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
+ VkSemaphoreCreateInfo vksci = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
+ VkFenceCreateInfo vkfci = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
vkfci.flags = VK_FENCE_CREATE_SIGNALED_BIT;
VERUS_FOR(i, s_ringBufferSize)
{
@@ -612,9 +599,8 @@ void RendererVulkan::CreateSamplers()
_vSamplers.resize(+Sampler::count);
- VkSamplerCreateInfo vksci = {};
- VkSamplerCreateInfo init = {};
- init.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
+ VkSamplerCreateInfo vksci = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
+ VkSamplerCreateInfo init = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
init.magFilter = VK_FILTER_LINEAR;
init.minFilter = VK_FILTER_LINEAR;
init.mipmapMode = tf ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST;
@@ -719,11 +705,10 @@ void RendererVulkan::CreateSamplers()
//
}
-VkCommandBuffer RendererVulkan::CreateCommandBuffer(VkCommandPool commandPool)
+VkCommandBuffer RendererVulkan::CreateVkCommandBuffer(VkCommandPool commandPool)
{
VkResult res = VK_SUCCESS;
- VkCommandBufferAllocateInfo vkcbai = {};
- vkcbai.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+ VkCommandBufferAllocateInfo vkcbai = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
vkcbai.commandPool = commandPool;
vkcbai.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
vkcbai.commandBufferCount = 1;
@@ -748,8 +733,7 @@ void RendererVulkan::ImGuiInit(RPHandle renderPassHandle)
{
VkResult res = VK_SUCCESS;
VkDescriptorPoolSize vkdps = { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 };
- VkDescriptorPoolCreateInfo vkdpci = {};
- vkdpci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
+ VkDescriptorPoolCreateInfo vkdpci = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
vkdpci.maxSets = 1;
vkdpci.poolSizeCount = 1;
vkdpci.pPoolSizes = &vkdps;
@@ -822,20 +806,19 @@ void RendererVulkan::ResizeSwapChain()
VERUS_VULKAN_DESTROY(oldSwapchain, vkDestroySwapchainKHR(_device, oldSwapchain, GetAllocator()));
}
-void RendererVulkan::BeginFrame(bool present)
+void RendererVulkan::BeginFrame()
{
VERUS_QREF_RENDERER;
VkResult res = VK_SUCCESS;
+ //
+ if (VK_SUCCESS != (res = vkWaitForFences(_device, 1, &_queueSubmitFences[_ringBufferIndex], VK_TRUE, UINT64_MAX)))
+ throw VERUS_RUNTIME_ERROR << "vkWaitForFences(); res=" << res;
if (VK_SUCCESS != (res = vkResetFences(_device, 1, &_queueSubmitFences[_ringBufferIndex])))
throw VERUS_RUNTIME_ERROR << "vkResetFences(); res=" << res;
- if (present)
- {
- uint32_t imageIndex = _swapChainBufferIndex;
- if (VK_SUCCESS != (res = vkAcquireNextImageKHR(_device, _swapChain, UINT64_MAX, _acquireNextImageSemaphores[_ringBufferIndex], VK_NULL_HANDLE, &imageIndex)))
- throw VERUS_RUNTIME_ERROR << "vkAcquireNextImageKHR(); res=" << res;
- _swapChainBufferIndex = imageIndex;
- }
+ //
+
+ _swapChainBufferIndex = -1;
vmaSetCurrentFrameIndex(_vmaAllocator, static_cast(renderer.GetFrameCount()));
@@ -849,7 +832,17 @@ void RendererVulkan::BeginFrame(bool present)
ImGui::NewFrame();
}
-void RendererVulkan::EndFrame(bool present)
+void RendererVulkan::AcquireSwapChainImage()
+{
+ VkResult res = VK_SUCCESS;
+
+ uint32_t imageIndex = _swapChainBufferIndex;
+ if (VK_SUCCESS != (res = vkAcquireNextImageKHR(_device, _swapChain, UINT64_MAX, _acquireNextImageSemaphores[_ringBufferIndex], VK_NULL_HANDLE, &imageIndex)))
+ throw VERUS_RUNTIME_ERROR << "vkAcquireNextImageKHR(); res=" << res;
+ _swapChainBufferIndex = imageIndex;
+}
+
+void RendererVulkan::EndFrame()
{
VERUS_QREF_RENDERER;
VkResult res = VK_SUCCESS;
@@ -861,13 +854,13 @@ void RendererVulkan::EndFrame(bool present)
auto cb = renderer.GetCommandBuffer();
cb->End();
+ //
const VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
_acquireNextImageSemaphore = _acquireNextImageSemaphores[_ringBufferIndex];
_queueSubmitSemaphore = _queueSubmitSemaphores[_ringBufferIndex];
VkCommandBuffer commandBuffer = static_cast(cb.Get())->GetVkCommandBuffer();
- VkSubmitInfo vksi = {};
- vksi.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- if (present)
+ VkSubmitInfo vksi = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
+ if (_swapChainBufferIndex >= 0)
{
vksi.waitSemaphoreCount = 1;
vksi.pWaitSemaphores = &_acquireNextImageSemaphore;
@@ -882,40 +875,30 @@ void RendererVulkan::EndFrame(bool present)
}
if (VK_SUCCESS != (res = vkQueueSubmit(_graphicsQueue, 1, &vksi, _queueSubmitFences[_ringBufferIndex])))
throw VERUS_RUNTIME_ERROR << "vkQueueSubmit(); res=" << res;
-}
-
-void RendererVulkan::Present()
-{
- VkResult res = VK_SUCCESS;
-
- const VkSwapchainKHR swapChains[] = { _swapChain };
-
- const uint32_t imageIndex = _swapChainBufferIndex;
- VkPresentInfoKHR vkpi = {};
- vkpi.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
- if (!_queueFamilyIndices.IsSameQueue())
- {
- vkpi.waitSemaphoreCount = 1;
- vkpi.pWaitSemaphores = &_queueSubmitSemaphore;
- }
- vkpi.swapchainCount = VERUS_COUNT_OF(swapChains);
- vkpi.pSwapchains = swapChains;
- vkpi.pImageIndices = &imageIndex;
- if (VK_SUCCESS != (res = vkQueuePresentKHR(_presentQueue, &vkpi)))
- {
- if (res != VK_ERROR_OUT_OF_DATE_KHR)
- throw VERUS_RUNTIME_ERROR << "vkQueuePresentKHR(); res=" << res;
- }
-}
-
-void RendererVulkan::Sync(bool present)
-{
- VkResult res = VK_SUCCESS;
-
_ringBufferIndex = (_ringBufferIndex + 1) % s_ringBufferSize;
+ //
- if (VK_SUCCESS != (res = vkWaitForFences(_device, 1, &_queueSubmitFences[_ringBufferIndex], VK_TRUE, UINT64_MAX)))
- throw VERUS_RUNTIME_ERROR << "vkWaitForFences(); res=" << res;
+ //
+ if (_swapChainBufferIndex >= 0)
+ {
+ const VkSwapchainKHR swapChains[] = { _swapChain };
+ const uint32_t imageIndex = _swapChainBufferIndex;
+ VkPresentInfoKHR vkpi = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
+ if (!_queueFamilyIndices.IsSameQueue())
+ {
+ vkpi.waitSemaphoreCount = 1;
+ vkpi.pWaitSemaphores = &_queueSubmitSemaphore;
+ }
+ vkpi.swapchainCount = VERUS_COUNT_OF(swapChains);
+ vkpi.pSwapchains = swapChains;
+ vkpi.pImageIndices = &imageIndex;
+ if (VK_SUCCESS != (res = vkQueuePresentKHR(_presentQueue, &vkpi)))
+ {
+ if (res != VK_ERROR_OUT_OF_DATE_KHR)
+ throw VERUS_RUNTIME_ERROR << "vkQueuePresentKHR(); res=" << res;
+ }
+ }
+ //
}
void RendererVulkan::WaitIdle()
@@ -924,6 +907,11 @@ void RendererVulkan::WaitIdle()
vkDeviceWaitIdle(_device);
}
+void RendererVulkan::OnMinimized()
+{
+ WaitIdle();
+}
+
// Resources:
PBaseCommandBuffer RendererVulkan::InsertCommandBuffer()
@@ -1164,8 +1152,7 @@ RPHandle RendererVulkan::CreateRenderPass(std::initializer_list
}
VkRenderPass renderPass = VK_NULL_HANDLE;
- VkRenderPassCreateInfo vkrpci = {};
- vkrpci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+ VkRenderPassCreateInfo vkrpci = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
vkrpci.attachmentCount = Utils::Cast32(vAttachmentDesc.size());
vkrpci.pAttachments = vAttachmentDesc.data();
vkrpci.subpassCount = Utils::Cast32(vSubpassDesc.size());
@@ -1190,8 +1177,7 @@ FBHandle RendererVulkan::CreateFramebuffer(RPHandle renderPassHandle, std::initi
VkImageView imageViews[VERUS_MAX_FB_ATTACH] = {};
VkFramebuffer framebuffer = VK_NULL_HANDLE;
- VkFramebufferCreateInfo vkfci = {};
- vkfci.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+ VkFramebufferCreateInfo vkfci = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
vkfci.renderPass = GetRenderPass(renderPassHandle);
int count = 0;
if (swapChainBufferIndex >= 0)
@@ -1298,8 +1284,7 @@ void RendererVulkan::CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, H
{
VkResult res = VK_SUCCESS;
- VkBufferCreateInfo vkbci = {};
- vkbci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+ VkBufferCreateInfo vkbci = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
vkbci.size = size;
vkbci.usage = usage;
VmaAllocationCreateInfo vmaaci = {};
diff --git a/RendererVulkan/src/CGI/RendererVulkan.h b/RendererVulkan/src/CGI/RendererVulkan.h
index 6b49ed8..86aad21 100644
--- a/RendererVulkan/src/CGI/RendererVulkan.h
+++ b/RendererVulkan/src/CGI/RendererVulkan.h
@@ -64,8 +64,6 @@ namespace verus
static CSZ s_requiredValidationLayers[];
static CSZ s_requiredDeviceExtensions[];
- typedef Map TMapRenderPasses;
-
VkInstance _instance = VK_NULL_HANDLE;
VkDebugUtilsMessengerEXT _debugUtilsMessenger = VK_NULL_HANDLE;
VkSurfaceKHR _surface = VK_NULL_HANDLE;
@@ -129,7 +127,8 @@ namespace verus
void CreateSamplers();
public:
- VkCommandBuffer CreateCommandBuffer(VkCommandPool commandPool);
+ //