Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

#include "EngineD3D12ImplTraits.hpp"
#include "PipelineStateCacheBase.hpp"
#include <mutex>

namespace Diligent
{
Expand All @@ -53,11 +54,17 @@ class PipelineStateCacheD3D12Impl final : public PipelineStateCacheBase<EngineD3

CComPtr<ID3D12DeviceChild> LoadComputePipeline(const wchar_t* Name, const D3D12_COMPUTE_PIPELINE_STATE_DESC& Desc);
CComPtr<ID3D12DeviceChild> LoadGraphicsPipeline(const wchar_t* Name, const D3D12_GRAPHICS_PIPELINE_STATE_DESC& Desc);
#ifdef D3D12_H_HAS_MESH_SHADER
CComPtr<ID3D12DeviceChild> LoadPipeline(const wchar_t* Name, const D3D12_PIPELINE_STATE_STREAM_DESC& Desc);
#endif

bool StorePipeline(const wchar_t* Name, ID3D12DeviceChild* pPSO);

private:
CComPtr<ID3D12PipelineLibrary> m_pLibrary;
RefCntAutoPtr<IDataBlob> m_pInitialData;
CComPtr<ID3D12PipelineLibrary> m_pLibrary;
CComPtr<ID3D12PipelineLibrary1> m_pLibrary1;
std::mutex m_LibraryMtx;
};

} // namespace Diligent
83 changes: 65 additions & 18 deletions Graphics/GraphicsEngineD3D12/src/PipelineStateCacheD3D12Impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,39 @@ PipelineStateCacheD3D12Impl::PipelineStateCacheD3D12Impl(IReferenceCounters*
}
// clang-format on
{
HRESULT hr = pRenderDeviceD3D12->GetD3D12Device1()->CreatePipelineLibrary(nullptr, 0, IID_PPV_ARGS(&m_pLibrary));
auto* pDevice1 = pRenderDeviceD3D12->GetD3D12Device1();
if (pDevice1 == nullptr)
{
LOG_WARNING_MESSAGE("D3D12 pipeline libraries are unavailable; native caching is disabled.");
return;
}

// D3D12 does not copy the serialized data: retain our own copy until the library is released.
if (CreateInfo.pCacheData != nullptr && CreateInfo.CacheDataSize != 0)
{
m_pInitialData = DataBlobImpl::Create(CreateInfo.CacheDataSize, CreateInfo.pCacheData);
const HRESULT LoadResult = pDevice1->CreatePipelineLibrary(m_pInitialData->GetConstDataPtr(), m_pInitialData->GetSize(), IID_PPV_ARGS(&m_pLibrary));
if (FAILED(LoadResult))
{
LOG_WARNING_MESSAGE("D3D12 pipeline library data is invalid or incompatible; using an empty cache (HRESULT ", LoadResult, ").");
m_pInitialData.Release();
}
}

HRESULT hr = m_pLibrary ? S_OK : pDevice1->CreatePipelineLibrary(nullptr, 0, IID_PPV_ARGS(&m_pLibrary));
if (FAILED(hr))
LOG_ERROR_AND_THROW("Failed to create D3D12 pipeline library");
{
LOG_WARNING_MESSAGE("D3D12 pipeline library is unavailable; native caching is disabled (HRESULT ", hr, ").");
return;
}
m_pLibrary->QueryInterface(IID_PPV_ARGS(&m_pLibrary1));
}

PipelineStateCacheD3D12Impl::~PipelineStateCacheD3D12Impl()
{
// D3D12 object can only be destroyed when it is no longer used by the GPU
GetDevice()->SafeReleaseDeviceObject(std::move(m_pLibrary), ~Uint64{0});
m_pLibrary1.Release();
GetDevice()->SafeReleaseDeviceObject(std::make_pair(std::move(m_pInitialData), std::move(m_pLibrary)), ~Uint64{0});
}

CComPtr<ID3D12DeviceChild> PipelineStateCacheD3D12Impl::LoadComputePipeline(const wchar_t* Name, const D3D12_COMPUTE_PIPELINE_STATE_DESC& Desc)
Expand All @@ -65,14 +89,15 @@ CComPtr<ID3D12DeviceChild> PipelineStateCacheD3D12Impl::LoadComputePipeline(cons
return {};
}

CComPtr<ID3D12DeviceChild> d3d12PSO;
if ((m_Desc.Mode & PSO_CACHE_MODE_LOAD) != 0)
CComPtr<ID3D12PipelineState> d3d12PSO;
if (m_pLibrary && (m_Desc.Mode & PSO_CACHE_MODE_LOAD) != 0)
{
HRESULT hr = m_pLibrary->LoadComputePipeline(Name, &Desc, IID_PPV_ARGS(&d3d12PSO));
if (FAILED(hr) && (m_Desc.Flags & PSO_CACHE_FLAG_VERBOSE) != 0)
LOG_ERROR_MESSAGE("Failed to load compute pipeline '", NarrowString(Name), "' from the library");
std::lock_guard<std::mutex> Lock{m_LibraryMtx};
HRESULT hr = m_pLibrary->LoadComputePipeline(Name, &Desc, IID_PPV_ARGS(&d3d12PSO));
if ((m_Desc.Flags & PSO_CACHE_FLAG_VERBOSE) != 0)
LOG_INFO_MESSAGE(SUCCEEDED(hr) ? "PSO cache hit (compute): " : "PSO cache miss (compute): ", NarrowString(Name));
}
return d3d12PSO;
return CComPtr<ID3D12DeviceChild>{d3d12PSO.p};
}

CComPtr<ID3D12DeviceChild> PipelineStateCacheD3D12Impl::LoadGraphicsPipeline(const wchar_t* Name, const D3D12_GRAPHICS_PIPELINE_STATE_DESC& Desc)
Expand All @@ -83,25 +108,43 @@ CComPtr<ID3D12DeviceChild> PipelineStateCacheD3D12Impl::LoadGraphicsPipeline(con
return {};
}

CComPtr<ID3D12DeviceChild> d3d12PSO;
if ((m_Desc.Mode & PSO_CACHE_MODE_LOAD) != 0)
CComPtr<ID3D12PipelineState> d3d12PSO;
if (m_pLibrary && (m_Desc.Mode & PSO_CACHE_MODE_LOAD) != 0)
{
HRESULT hr = m_pLibrary->LoadGraphicsPipeline(Name, &Desc, IID_PPV_ARGS(&d3d12PSO));
if (FAILED(hr) && (m_Desc.Flags & PSO_CACHE_FLAG_VERBOSE) != 0)
LOG_ERROR_MESSAGE("Failed to load graphics pipeline '", NarrowString(Name), "' from the library");
std::lock_guard<std::mutex> Lock{m_LibraryMtx};
HRESULT hr = m_pLibrary->LoadGraphicsPipeline(Name, &Desc, IID_PPV_ARGS(&d3d12PSO));
if ((m_Desc.Flags & PSO_CACHE_FLAG_VERBOSE) != 0)
LOG_INFO_MESSAGE(SUCCEEDED(hr) ? "PSO cache hit (graphics): " : "PSO cache miss (graphics): ", NarrowString(Name));
}
return d3d12PSO;
return CComPtr<ID3D12DeviceChild>{d3d12PSO.p};
}

#ifdef D3D12_H_HAS_MESH_SHADER
CComPtr<ID3D12DeviceChild> PipelineStateCacheD3D12Impl::LoadPipeline(const wchar_t* Name, const D3D12_PIPELINE_STATE_STREAM_DESC& Desc)
{
VERIFY_EXPR(Name != nullptr);
CComPtr<ID3D12PipelineState> d3d12PSO;
if (m_pLibrary1 && (m_Desc.Mode & PSO_CACHE_MODE_LOAD) != 0)
{
std::lock_guard<std::mutex> Lock{m_LibraryMtx};
const HRESULT hr = m_pLibrary1->LoadPipeline(Name, &Desc, IID_PPV_ARGS(&d3d12PSO));
if ((m_Desc.Flags & PSO_CACHE_FLAG_VERBOSE) != 0)
LOG_INFO_MESSAGE(SUCCEEDED(hr) ? "PSO cache hit (mesh): " : "PSO cache miss (mesh): ", NarrowString(Name), " (HRESULT ", hr, ")");
}
return CComPtr<ID3D12DeviceChild>{d3d12PSO.p};
}
#endif

bool PipelineStateCacheD3D12Impl::StorePipeline(const wchar_t* Name, ID3D12DeviceChild* pPSO)
{
VERIFY_EXPR(Name != nullptr);
if ((m_Desc.Mode & PSO_CACHE_MODE_STORE) == 0)
if (!m_pLibrary || (m_Desc.Mode & PSO_CACHE_MODE_STORE) == 0)
return false;

HRESULT hr = m_pLibrary->StorePipeline(Name, static_cast<ID3D12PipelineState*>(pPSO));
std::lock_guard<std::mutex> Lock{m_LibraryMtx};
HRESULT hr = m_pLibrary->StorePipeline(Name, static_cast<ID3D12PipelineState*>(pPSO));
if (FAILED(hr) && (m_Desc.Flags & PSO_CACHE_FLAG_VERBOSE) != 0)
LOG_ERROR_MESSAGE("Failed to add pipeline '", NarrowString(Name), "' to the library");
LOG_INFO_MESSAGE("PSO cache store failed: ", NarrowString(Name), " (HRESULT ", hr, "; it may already be stored).");

return SUCCEEDED(hr);
}
Expand All @@ -110,6 +153,10 @@ void PipelineStateCacheD3D12Impl::GetData(IDataBlob** ppBlob)
{
DEV_CHECK_ERR(ppBlob != nullptr, "ppBlob must not be null");
*ppBlob = nullptr;
if (!m_pLibrary)
return;

std::lock_guard<std::mutex> Lock{m_LibraryMtx};

RefCntAutoPtr<DataBlobImpl> pDataBlob = DataBlobImpl::Create(m_pLibrary->GetSerializedSize());

Expand Down
133 changes: 105 additions & 28 deletions Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
#include "DynamicLinearAllocator.hpp"
#include "D3DShaderResourceValidation.hpp"
#include "DataBlobImpl.hpp"
#include "HashUtils.hpp"

#include "DXBCUtils.hpp"
#include "DXCompiler.hpp"
Expand All @@ -63,6 +64,66 @@ constexpr INTERFACE_ID PipelineStateD3D12Impl::IID_InternalImpl;

namespace
{
struct PipelineCacheHasher
{
template <typename T>
void Update(const T& Value)
{
if constexpr (std::is_fundamental<T>::value || std::is_enum<T>::value)
UpdateRaw(&Value, sizeof(Value));
else
HashCombiner<PipelineCacheHasher, T>{*this}(Value);
}

void Update(const char* Value)
{
const Uint64 Length = Value != nullptr ? std::strlen(Value) : 0;
Update(Length);
UpdateRaw(Value, Length);
}

template <typename... Args>
void operator()(const Args&... Values)
{
(Update(Values), ...);
}

void UpdateRaw(const void* pData, Uint64 Size)
{
const auto* Bytes = static_cast<const Uint8*>(pData);
for (Uint64 i = 0; i < Size; ++i)
{
m_Hash ^= Bytes[i];
m_Hash *= FNVPrime;
}
}

Uint64 Get() const { return m_Hash; }

private:
static constexpr Uint64 FNVOffsetBasis = 14695981039346656037ull;
static constexpr Uint64 FNVPrime = 1099511628211ull;
Uint64 m_Hash = FNVOffsetBasis;
};

template <typename ShaderStagesType>
std::wstring GetPipelineCacheName(const RootSignatureD3D12& RootSig, const ShaderStagesType& ShaderStages, const GraphicsPipelineDesc* pGraphics = nullptr)
{
// Hash the effective pipeline after binding remapping. Archive unpacking changes
// create-info flags/signatures and shader bindings, but not the native pipeline.
PipelineCacheHasher Hasher;
Hasher(RootSig.GetHash(), pGraphics != nullptr);
if (pGraphics != nullptr)
Hasher(*pGraphics);
for (const auto& Stage : ShaderStages)
{
Hasher(Stage.Type);
for (const auto& Bytecode : Stage.ByteCodes)
Hasher.UpdateRaw(Bytecode->GetConstDataPtr(), Bytecode->GetSize());
}
return L"PSO_2_" + std::to_wstring(Hasher.Get());
}

#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable : 4324) // warning C4324: structure was padded due to alignment specifier
Expand Down Expand Up @@ -641,6 +702,9 @@ void PipelineStateD3D12Impl::InitializePipeline(const GraphicsPipelineStateCreat
TShaderStages ShaderStages;
InitInternalObjects(CreateInfo, ShaderStages);

PipelineStateCacheD3D12Impl* const pPSOCacheD3D12 = ClassPtrCast<PipelineStateCacheD3D12Impl>(CreateInfo.pPSOCache);
const std::wstring CacheName = pPSOCacheD3D12 ? GetPipelineCacheName(*m_RootSig, ShaderStages, &m_pGraphicsPipelineData->Desc) : std::wstring{};

ID3D12Device* pd3d12Device = m_pDevice->GetD3D12Device();
if (m_Desc.PipelineType == PIPELINE_TYPE_GRAPHICS)
{
Expand Down Expand Up @@ -727,9 +791,8 @@ void PipelineStateD3D12Impl::InitializePipeline(const GraphicsPipelineStateCreat
d3d12PSODesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;

// Try to load from the cache
PipelineStateCacheD3D12Impl* const pPSOCacheD3D12 = ClassPtrCast<PipelineStateCacheD3D12Impl>(CreateInfo.pPSOCache);
if (pPSOCacheD3D12 != nullptr && !WName.empty())
m_pd3d12PSO = pPSOCacheD3D12->LoadGraphicsPipeline(WName.c_str(), d3d12PSODesc);
if (pPSOCacheD3D12 != nullptr)
m_pd3d12PSO = pPSOCacheD3D12->LoadGraphicsPipeline(CacheName.c_str(), d3d12PSODesc);
if (!m_pd3d12PSO)
{
// Note: renderdoc frame capture fails if any interface but IID_ID3D12PipelineState is requested
Expand All @@ -738,8 +801,8 @@ void PipelineStateD3D12Impl::InitializePipeline(const GraphicsPipelineStateCreat
LOG_ERROR_AND_THROW("Failed to create pipeline state");

// Add to the cache
if (pPSOCacheD3D12 != nullptr && !WName.empty())
pPSOCacheD3D12->StorePipeline(WName.c_str(), m_pd3d12PSO);
if (pPSOCacheD3D12 != nullptr)
pPSOCacheD3D12->StorePipeline(CacheName.c_str(), m_pd3d12PSO);
}
}
#ifdef D3D12_H_HAS_MESH_SHADER
Expand All @@ -749,20 +812,21 @@ void PipelineStateD3D12Impl::InitializePipeline(const GraphicsPipelineStateCreat

struct MESH_SHADER_PIPELINE_STATE_DESC
{
PSS_SubObject<D3D12_PIPELINE_STATE_FLAGS, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_FLAGS> Flags;
PSS_SubObject<UINT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_NODE_MASK> NodeMask;
PSS_SubObject<ID3D12RootSignature*, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> pRootSignature;
PSS_SubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS> PS;
PSS_SubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS> AS;
PSS_SubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS> MS;
PSS_SubObject<D3D12_BLEND_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND> BlendState;
PSS_SubObject<D3D12_DEPTH_STENCIL_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL> DepthStencilState;
PSS_SubObject<D3D12_RASTERIZER_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER> RasterizerState;
PSS_SubObject<DXGI_SAMPLE_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC> SampleDesc;
PSS_SubObject<UINT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK> SampleMask;
PSS_SubObject<DXGI_FORMAT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT> DSVFormat;
PSS_SubObject<D3D12_RT_FORMAT_ARRAY, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS> RTVFormatArray;
PSS_SubObject<D3D12_CACHED_PIPELINE_STATE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CACHED_PSO> CachedPSO;
PSS_SubObject<D3D12_PIPELINE_STATE_FLAGS, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_FLAGS> Flags;
PSS_SubObject<UINT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_NODE_MASK> NodeMask;
PSS_SubObject<ID3D12RootSignature*, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> pRootSignature;
PSS_SubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS> PS;
PSS_SubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS> AS;
PSS_SubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS> MS;
PSS_SubObject<D3D12_BLEND_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND> BlendState;
PSS_SubObject<D3D12_DEPTH_STENCIL_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL> DepthStencilState;
PSS_SubObject<D3D12_RASTERIZER_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER> RasterizerState;
PSS_SubObject<DXGI_SAMPLE_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC> SampleDesc;
PSS_SubObject<UINT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK> SampleMask;
PSS_SubObject<D3D12_PRIMITIVE_TOPOLOGY_TYPE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY> PrimitiveTopologyType;
PSS_SubObject<DXGI_FORMAT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT> DSVFormat;
PSS_SubObject<D3D12_RT_FORMAT_ARRAY, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS> RTVFormatArray;
PSS_SubObject<D3D12_CACHED_PIPELINE_STATE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CACHED_PSO> CachedPSO;
};
MESH_SHADER_PIPELINE_STATE_DESC d3d12PSODesc = {};

Expand Down Expand Up @@ -791,6 +855,11 @@ void PipelineStateD3D12Impl::InitializePipeline(const GraphicsPipelineStateCreat
BlendStateDesc_To_D3D12_BLEND_DESC(GraphicsPipeline.BlendDesc, *d3d12PSODesc.BlendState);
d3d12PSODesc.SampleMask = GraphicsPipeline.SampleMask;

// Explicit topology keeps CreatePipelineState and PipelineLibrary::LoadPipeline
// descriptions identical; creation may infer topology from the mesh shader.
static const PrimitiveTopology_To_D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimTopologyToD3D12TopologyType;
d3d12PSODesc.PrimitiveTopologyType = PrimTopologyToD3D12TopologyType[GraphicsPipeline.PrimitiveTopology];

RasterizerStateDesc_To_D3D12_RASTERIZER_DESC(GraphicsPipeline.RasterizerDesc, *d3d12PSODesc.RasterizerState);
DepthStencilStateDesc_To_D3D12_DEPTH_STENCIL_DESC(GraphicsPipeline.DepthStencilDesc, *d3d12PSODesc.DepthStencilState);

Expand Down Expand Up @@ -819,11 +888,18 @@ void PipelineStateD3D12Impl::InitializePipeline(const GraphicsPipelineStateCreat
streamDesc.SizeInBytes = sizeof(d3d12PSODesc);
streamDesc.pPipelineStateSubobjectStream = &d3d12PSODesc;

ID3D12Device2* pd3d12Device2 = m_pDevice->GetD3D12Device2();
// Note: renderdoc frame capture fails if any interface but IID_ID3D12PipelineState is requested
HRESULT hr = pd3d12Device2->CreatePipelineState(&streamDesc, __uuidof(ID3D12PipelineState), IID_PPV_ARGS_Helper(&m_pd3d12PSO));
if (FAILED(hr))
LOG_ERROR_AND_THROW("Failed to create pipeline state");
if (pPSOCacheD3D12 != nullptr)
m_pd3d12PSO = pPSOCacheD3D12->LoadPipeline(CacheName.c_str(), streamDesc);
if (!m_pd3d12PSO)
{
ID3D12Device2* pd3d12Device2 = m_pDevice->GetD3D12Device2();
// Note: renderdoc frame capture fails if any interface but IID_ID3D12PipelineState is requested
HRESULT hr = pd3d12Device2->CreatePipelineState(&streamDesc, __uuidof(ID3D12PipelineState), IID_PPV_ARGS_Helper(&m_pd3d12PSO));
if (FAILED(hr))
LOG_ERROR_AND_THROW("Failed to create pipeline state");
if (pPSOCacheD3D12 != nullptr)
pPSOCacheD3D12->StorePipeline(CacheName.c_str(), m_pd3d12PSO);
}
}
#endif // D3D12_H_HAS_MESH_SHADER
else
Expand Down Expand Up @@ -868,8 +944,9 @@ void PipelineStateD3D12Impl::InitializePipeline(const ComputePipelineStateCreate
// Try to load from the cache
const std::wstring WName = WidenString(m_Desc.Name);
PipelineStateCacheD3D12Impl* const pPSOCacheD3D12 = ClassPtrCast<PipelineStateCacheD3D12Impl>(CreateInfo.pPSOCache);
if (pPSOCacheD3D12 != nullptr && !WName.empty())
m_pd3d12PSO = pPSOCacheD3D12->LoadComputePipeline(WName.c_str(), d3d12PSODesc);
const std::wstring CacheName = pPSOCacheD3D12 ? GetPipelineCacheName(*m_RootSig, ShaderStages) : std::wstring{};
if (pPSOCacheD3D12 != nullptr)
m_pd3d12PSO = pPSOCacheD3D12->LoadComputePipeline(CacheName.c_str(), d3d12PSODesc);
if (!m_pd3d12PSO)
{
// Note: renderdoc frame capture fails if any interface but IID_ID3D12PipelineState is requested
Expand All @@ -878,8 +955,8 @@ void PipelineStateD3D12Impl::InitializePipeline(const ComputePipelineStateCreate
LOG_ERROR_AND_THROW("Failed to create pipeline state");

// Add to the cache
if (pPSOCacheD3D12 != nullptr && !WName.empty())
pPSOCacheD3D12->StorePipeline(WName.c_str(), m_pd3d12PSO);
if (pPSOCacheD3D12 != nullptr)
pPSOCacheD3D12->StorePipeline(CacheName.c_str(), m_pd3d12PSO);
}

if (!WName.empty())
Expand Down
1 change: 1 addition & 0 deletions Graphics/GraphicsTools/src/RenderStateCacheImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -833,6 +833,7 @@ bool RenderStateCacheImpl::CreatePipelineStateInternal(const CreateInfoType& PSO
UnpackInfo.PipelineType = PSOCreateInfo.PSODesc.PipelineType;
UnpackInfo.Name = HashStr.c_str();
UnpackInfo.pDevice = m_pDevice;
UnpackInfo.pCache = PSOCreateInfo.pPSOCache;
UnpackInfo.ModifyPipelineStateCreateInfo = Callback;
UnpackInfo.pUserData = Callback;
RefCntAutoPtr<IPipelineState> pPSO;
Expand Down
Loading