verus/RendererDirect3D11/src/CGI/RendererD3D11.cpp

676 lines
19 KiB
C++

// 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<IDXGIFactory1> RendererD3D11::CreateFactory()
{
HRESULT hr = 0;
ComPtr<IDXGIFactory1> 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<IDXGIAdapter1> RendererD3D11::GetAdapter(ComPtr<IDXGIFactory1> pFactory)
{
ComPtr<IDXGIAdapter1> 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>
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()";
// </SDL>
_featureLevel = D3D_FEATURE_LEVEL_11_0;
ComPtr<IDXGIFactory1> pFactory = CreateFactory();
ComPtr<IDXGIAdapter1> 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<ID3D11InfoQueue> 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<D3D11_FILTER>(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);
// <Wrap>
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);
// </Wrap>
// <Clamp>
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);
// </Clamp>
}
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<BYTE> 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<float>(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;
// <Present>
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);
}
// </Present>
}
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<PCommandBufferD3D11>(p));
}
void RendererD3D11::DeleteGeometry(PBaseGeometry p)
{
TStoreGeometry::Delete(static_cast<PGeometryD3D11>(p));
}
void RendererD3D11::DeletePipeline(PBasePipeline p)
{
TStorePipelines::Delete(static_cast<PPipelineD3D11>(p));
}
void RendererD3D11::DeleteShader(PBaseShader p)
{
TStoreShaders::Delete(static_cast<PShaderD3D11>(p));
}
void RendererD3D11::DeleteTexture(PBaseTexture p)
{
TStoreTextures::Delete(static_cast<PTextureD3D11>(p));
}
RPHandle RendererD3D11::CreateRenderPass(std::initializer_list<RP::Attachment> ilA, std::initializer_list<RP::Subpass> ilS, std::initializer_list<RP::Dependency> 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<TexturePtr> 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<TexturePtr> vTex(il);
auto GetRTV = [this, &vTex, swapChainBufferIndex, cubeMapFace](int index) -> ID3D11RenderTargetView*
{
if (swapChainBufferIndex >= 0)
{
if (index)
{
auto& texD3D11 = static_cast<RTextureD3D11>(*vTex[index - 1]);
return texD3D11.GetRTV();
}
else
{
return _pSwapChainBufferRTV.Get();
}
}
else
{
auto& texD3D11 = static_cast<RTextureD3D11>(*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<RTextureD3D11>(*vTex[index - 1]);
return texD3D11.GetDSV(depthStencilReadOnly);
}
else
{
VERUS_RT_ASSERT("Using swapChainBufferIndex for DSV");
return nullptr;
}
}
else
{
auto& texD3D11 = static_cast<RTextureD3D11>(*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()];
}