3094 строки
109 KiB
C++
3094 строки
109 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// DxilContainerReflection.cpp //
|
|
// Copyright (C) Microsoft Corporation. All rights reserved. //
|
|
// This file is distributed under the University of Illinois Open Source //
|
|
// License. See LICENSE.TXT for details. //
|
|
// //
|
|
// Provides support for reading DXIL container structures. //
|
|
// //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "dxc/DXIL/DxilCounters.h"
|
|
#include "dxc/DXIL/DxilFunctionProps.h"
|
|
#include "dxc/DXIL/DxilInstructions.h"
|
|
#include "dxc/DXIL/DxilModule.h"
|
|
#include "dxc/DXIL/DxilOperations.h"
|
|
#include "dxc/DXIL/DxilPDB.h"
|
|
#include "dxc/DXIL/DxilShaderModel.h"
|
|
#include "dxc/DXIL/DxilUtil.h"
|
|
#include "dxc/DxilContainer/DxilContainer.h"
|
|
#include "dxc/HLSL/HLMatrixType.h"
|
|
#include "dxc/Support/FileIOHelper.h"
|
|
#include "dxc/Support/Global.h"
|
|
#include "dxc/Support/Unicode.h"
|
|
#include "dxc/Support/WinIncludes.h"
|
|
#include "dxc/Support/dxcapi.impl.h"
|
|
#include "dxc/Support/microcom.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/Bitcode/ReaderWriter.h"
|
|
#include "llvm/IR/InstIterator.h"
|
|
#include "llvm/IR/LLVMContext.h"
|
|
#include "llvm/IR/Operator.h"
|
|
|
|
#include "llvm/ADT/SetVector.h"
|
|
#include <unordered_set>
|
|
|
|
#include "dxc/dxcapi.h"
|
|
|
|
#include "dxc/Support/D3DReflection.h"
|
|
#ifdef _WIN32
|
|
#include "d3d11shader.h" // for compatibility
|
|
#else
|
|
// Dummy D3D11 struct to allow nix-dead code to compile
|
|
struct D3D11_SHADER_INPUT_BIND_DESC {
|
|
int dummy;
|
|
};
|
|
#include "dxc/WinAdapter.h"
|
|
#endif
|
|
|
|
#include "dxc/DxilContainer/DxilRuntimeReflection.h"
|
|
|
|
// Remove this workaround once newer version of d3dcommon.h can be compiled
|
|
// against
|
|
#define ADD_16_64_BIT_TYPES
|
|
#define ADD_SVC_BIT_FIELD
|
|
|
|
const GUID IID_ID3D11ShaderReflection_43 = {
|
|
0x0a233719,
|
|
0x3960,
|
|
0x4578,
|
|
{0x9d, 0x7c, 0x20, 0x3b, 0x8b, 0x1d, 0x9c, 0xc1}};
|
|
const GUID IID_ID3D11ShaderReflection_47 = {
|
|
0x8d536ca1,
|
|
0x0cca,
|
|
0x4956,
|
|
{0xa8, 0x37, 0x78, 0x69, 0x63, 0x75, 0x55, 0x84}};
|
|
|
|
using namespace llvm;
|
|
using namespace hlsl;
|
|
using namespace hlsl::DXIL;
|
|
|
|
class DxilContainerReflection : public IDxcContainerReflection {
|
|
private:
|
|
DXC_MICROCOM_TM_REF_FIELDS()
|
|
CComPtr<IDxcBlob> m_container;
|
|
const DxilContainerHeader *m_pHeader = nullptr;
|
|
uint32_t m_headerLen = 0;
|
|
bool IsLoaded() const { return m_pHeader != nullptr; }
|
|
|
|
public:
|
|
DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
|
|
DXC_MICROCOM_TM_CTOR(DxilContainerReflection)
|
|
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid,
|
|
void **ppvObject) override {
|
|
return DoBasicQueryInterface<IDxcContainerReflection>(this, iid, ppvObject);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE Load(IDxcBlob *pContainer) override;
|
|
HRESULT STDMETHODCALLTYPE GetPartCount(UINT32 *pResult) override;
|
|
HRESULT STDMETHODCALLTYPE GetPartKind(UINT32 idx, UINT32 *pResult) override;
|
|
HRESULT STDMETHODCALLTYPE GetPartContent(UINT32 idx,
|
|
IDxcBlob **ppResult) override;
|
|
HRESULT STDMETHODCALLTYPE FindFirstPartKind(UINT32 kind,
|
|
UINT32 *pResult) override;
|
|
HRESULT STDMETHODCALLTYPE GetPartReflection(UINT32 idx, REFIID iid,
|
|
void **ppvObject) override;
|
|
};
|
|
|
|
class CShaderReflectionConstantBuffer;
|
|
class CShaderReflectionType;
|
|
|
|
enum class PublicAPI { D3D12 = 0, D3D11_47 = 1, D3D11_43 = 2, Invalid };
|
|
|
|
#ifdef ADD_16_64_BIT_TYPES
|
|
// Disable warning about value not being valid in enum
|
|
#pragma warning(disable : 4063)
|
|
#define D3D_SVT_INT16 ((D3D_SHADER_VARIABLE_TYPE)58)
|
|
#define D3D_SVT_UINT16 ((D3D_SHADER_VARIABLE_TYPE)59)
|
|
#define D3D_SVT_FLOAT16 ((D3D_SHADER_VARIABLE_TYPE)60)
|
|
#define D3D_SVT_INT64 ((D3D_SHADER_VARIABLE_TYPE)61)
|
|
#define D3D_SVT_UINT64 ((D3D_SHADER_VARIABLE_TYPE)62)
|
|
#endif // ADD_16_64_BIT_TYPES
|
|
|
|
#ifdef ADD_SVC_BIT_FIELD
|
|
// Disable warning about value not being valid in enum
|
|
#pragma warning(disable : 4063)
|
|
// FIXME: remove the define once D3D_SVC_BIT_FIELD added into
|
|
// D3D_SHADER_VARIABLE_CLASS.
|
|
#define D3D_SVC_BIT_FIELD \
|
|
((D3D_SHADER_VARIABLE_CLASS)(D3D_SVC_INTERFACE_POINTER + 1))
|
|
#endif
|
|
|
|
class DxilModuleReflection {
|
|
public:
|
|
hlsl::RDAT::DxilRuntimeData m_RDAT;
|
|
LLVMContext Context;
|
|
std::unique_ptr<Module> m_pModule; // Must come after LLVMContext, otherwise
|
|
// unique_ptr will over-delete.
|
|
DxilModule *m_pDxilModule = nullptr;
|
|
bool m_bUsageInMetadata = false;
|
|
std::vector<std::unique_ptr<CShaderReflectionConstantBuffer>> m_CBs;
|
|
std::vector<D3D12_SHADER_INPUT_BIND_DESC> m_Resources;
|
|
std::vector<std::unique_ptr<CShaderReflectionType>> m_Types;
|
|
|
|
// Key strings owned by CShaderReflectionConstantBuffer objects
|
|
std::map<StringRef, UINT> m_CBsByName;
|
|
// Due to the possibility of overlapping names between CB and other resources,
|
|
// m_StructuredBufferCBsByName is the index into m_CBs corresponding to
|
|
// StructuredBuffer resources, separately from CB resources.
|
|
std::map<StringRef, UINT> m_StructuredBufferCBsByName;
|
|
|
|
void CreateReflectionObjects();
|
|
void CreateReflectionObjectForResource(DxilResourceBase *R);
|
|
|
|
HRESULT LoadRDAT(const DxilPartHeader *pPart);
|
|
HRESULT LoadProgramHeader(const DxilProgramHeader *pProgramHeader);
|
|
|
|
// Common code
|
|
ID3D12ShaderReflectionConstantBuffer *_GetConstantBufferByIndex(UINT Index);
|
|
ID3D12ShaderReflectionConstantBuffer *_GetConstantBufferByName(LPCSTR Name);
|
|
|
|
HRESULT _GetResourceBindingDesc(UINT ResourceIndex,
|
|
D3D12_SHADER_INPUT_BIND_DESC *pDesc,
|
|
PublicAPI api = PublicAPI::D3D12);
|
|
|
|
ID3D12ShaderReflectionVariable *_GetVariableByName(LPCSTR Name);
|
|
|
|
HRESULT _GetResourceBindingDescByName(LPCSTR Name,
|
|
D3D12_SHADER_INPUT_BIND_DESC *pDesc,
|
|
PublicAPI api = PublicAPI::D3D12);
|
|
};
|
|
|
|
class DxilShaderReflection : public DxilModuleReflection,
|
|
public ID3D12ShaderReflection {
|
|
private:
|
|
DXC_MICROCOM_TM_REF_FIELDS()
|
|
std::vector<D3D12_SIGNATURE_PARAMETER_DESC> m_InputSignature;
|
|
std::vector<D3D12_SIGNATURE_PARAMETER_DESC> m_OutputSignature;
|
|
std::vector<D3D12_SIGNATURE_PARAMETER_DESC> m_PatchConstantSignature;
|
|
std::vector<std::unique_ptr<char[]>> m_UpperCaseNames;
|
|
D3D12_SHADER_DESC m_Desc = {};
|
|
|
|
void SetCBufferUsage();
|
|
void CreateReflectionObjectsForSignature(
|
|
const DxilSignature &Sig,
|
|
std::vector<D3D12_SIGNATURE_PARAMETER_DESC> &Descs);
|
|
LPCSTR CreateUpperCase(LPCSTR pValue);
|
|
void MarkUsedSignatureElements();
|
|
void InitDesc();
|
|
|
|
public:
|
|
PublicAPI m_PublicAPI;
|
|
void SetPublicAPI(PublicAPI value) { m_PublicAPI = value; }
|
|
static PublicAPI IIDToAPI(REFIID iid) {
|
|
PublicAPI api = PublicAPI::Invalid;
|
|
if (IsEqualIID(__uuidof(ID3D12ShaderReflection), iid))
|
|
api = PublicAPI::D3D12;
|
|
else if (IsEqualIID(IID_ID3D11ShaderReflection_43, iid))
|
|
api = PublicAPI::D3D11_43;
|
|
else if (IsEqualIID(IID_ID3D11ShaderReflection_47, iid))
|
|
api = PublicAPI::D3D11_47;
|
|
return api;
|
|
}
|
|
DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
|
|
DXC_MICROCOM_TM_CTOR(DxilShaderReflection)
|
|
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid,
|
|
void **ppvObject) noexcept override {
|
|
HRESULT hr = E_NOINTERFACE;
|
|
|
|
// There is non-standard handling of QueryInterface:
|
|
// - although everything uses the same vtable as ID3D12ShaderReflection,
|
|
// there are differences in behavior depending on the API version, and
|
|
// there are 3 of these - it's not just d3d11 vs d3d12.
|
|
// - when the object is created the API version is fixed
|
|
// - from that point on, this object can only be QI'd for the matching API
|
|
// version.
|
|
PublicAPI api = IIDToAPI(iid);
|
|
if (api == m_PublicAPI) {
|
|
*ppvObject = static_cast<ID3D12ShaderReflection *>(this);
|
|
this->AddRef();
|
|
hr = S_OK;
|
|
} else if (IsEqualIID(__uuidof(IUnknown), iid)) {
|
|
*ppvObject = static_cast<IUnknown *>(this);
|
|
this->AddRef();
|
|
hr = S_OK;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT Load(const DxilProgramHeader *pProgramHeader,
|
|
const DxilPartHeader *pRDATPart);
|
|
|
|
// ID3D12ShaderReflection
|
|
STDMETHODIMP GetDesc(D3D12_SHADER_DESC *pDesc) noexcept override;
|
|
|
|
STDMETHODIMP_(ID3D12ShaderReflectionConstantBuffer *)
|
|
GetConstantBufferByIndex(UINT Index) noexcept override;
|
|
STDMETHODIMP_(ID3D12ShaderReflectionConstantBuffer *)
|
|
GetConstantBufferByName(LPCSTR Name) noexcept override;
|
|
|
|
STDMETHODIMP
|
|
GetResourceBindingDesc(UINT ResourceIndex,
|
|
D3D12_SHADER_INPUT_BIND_DESC *pDesc) noexcept override;
|
|
|
|
STDMETHODIMP GetInputParameterDesc(
|
|
UINT ParameterIndex,
|
|
D3D12_SIGNATURE_PARAMETER_DESC *pDesc) noexcept override;
|
|
STDMETHODIMP GetOutputParameterDesc(
|
|
UINT ParameterIndex,
|
|
D3D12_SIGNATURE_PARAMETER_DESC *pDesc) noexcept override;
|
|
STDMETHODIMP GetPatchConstantParameterDesc(
|
|
UINT ParameterIndex,
|
|
D3D12_SIGNATURE_PARAMETER_DESC *pDesc) noexcept override;
|
|
|
|
STDMETHODIMP_(ID3D12ShaderReflectionVariable *)
|
|
GetVariableByName(LPCSTR Name) noexcept override;
|
|
|
|
STDMETHODIMP GetResourceBindingDescByName(
|
|
LPCSTR Name, D3D12_SHADER_INPUT_BIND_DESC *pDesc) noexcept override;
|
|
|
|
STDMETHODIMP_(UINT) GetMovInstructionCount(THIS) noexcept override;
|
|
STDMETHODIMP_(UINT) GetMovcInstructionCount(THIS) noexcept override;
|
|
STDMETHODIMP_(UINT) GetConversionInstructionCount(THIS) noexcept override;
|
|
STDMETHODIMP_(UINT) GetBitwiseInstructionCount(THIS) noexcept override;
|
|
|
|
STDMETHODIMP_(D3D_PRIMITIVE) GetGSInputPrimitive(THIS) noexcept override;
|
|
STDMETHODIMP_(BOOL) IsSampleFrequencyShader(THIS) noexcept override;
|
|
|
|
STDMETHODIMP_(UINT) GetNumInterfaceSlots(THIS) noexcept override;
|
|
STDMETHODIMP
|
|
GetMinFeatureLevel(D3D_FEATURE_LEVEL *pLevel) noexcept override;
|
|
|
|
STDMETHODIMP_(UINT)
|
|
GetThreadGroupSize(UINT *pSizeX, UINT *pSizeY,
|
|
UINT *pSizeZ) noexcept override;
|
|
|
|
STDMETHODIMP_(UINT64) GetRequiresFlags(THIS) noexcept override;
|
|
};
|
|
|
|
class CFunctionReflection;
|
|
class DxilLibraryReflection : public DxilModuleReflection,
|
|
public ID3D12LibraryReflection {
|
|
private:
|
|
DXC_MICROCOM_TM_REF_FIELDS()
|
|
|
|
// Storage, and function by name:
|
|
typedef DenseMap<StringRef, std::unique_ptr<CFunctionReflection>> FunctionMap;
|
|
typedef DenseMap<const Function *, CFunctionReflection *> FunctionsByPtr;
|
|
FunctionMap m_FunctionMap;
|
|
FunctionsByPtr m_FunctionsByPtr;
|
|
// Enable indexing into functions in deterministic order:
|
|
std::vector<CFunctionReflection *> m_FunctionVector;
|
|
|
|
void AddResourceDependencies();
|
|
void SetCBufferUsage();
|
|
|
|
public:
|
|
DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
|
|
DXC_MICROCOM_TM_CTOR(DxilLibraryReflection)
|
|
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid,
|
|
void **ppvObject) noexcept override {
|
|
return DoBasicQueryInterface<ID3D12LibraryReflection>(this, iid, ppvObject);
|
|
}
|
|
|
|
HRESULT Load(const DxilProgramHeader *pProgramHeader,
|
|
const DxilPartHeader *pRDATPart);
|
|
|
|
// ID3D12LibraryReflection
|
|
STDMETHOD(GetDesc)(D3D12_LIBRARY_DESC *pDesc) override;
|
|
|
|
STDMETHOD_(ID3D12FunctionReflection *, GetFunctionByIndex)
|
|
(INT FunctionIndex) override;
|
|
};
|
|
|
|
namespace hlsl {
|
|
|
|
HRESULT CreateDxilShaderReflection(const DxilProgramHeader *pProgramHeader,
|
|
const DxilPartHeader *pRDATPart, REFIID iid,
|
|
void **ppvObject) {
|
|
if (!ppvObject)
|
|
return E_INVALIDARG;
|
|
PublicAPI api = DxilShaderReflection::IIDToAPI(iid);
|
|
if (api == PublicAPI::Invalid) {
|
|
if (IsEqualIID(__uuidof(IUnknown), iid))
|
|
api = PublicAPI::D3D12;
|
|
else
|
|
return E_NOINTERFACE;
|
|
}
|
|
CComPtr<DxilShaderReflection> pReflection =
|
|
DxilShaderReflection::Alloc(DxcGetThreadMallocNoRef());
|
|
IFROOM(pReflection.p);
|
|
pReflection->SetPublicAPI(api);
|
|
// pRDATPart to be used for transition.
|
|
IFR(pReflection->Load(pProgramHeader, pRDATPart));
|
|
IFR(pReflection.p->QueryInterface(iid, ppvObject));
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CreateDxilLibraryReflection(const DxilProgramHeader *pProgramHeader,
|
|
const DxilPartHeader *pRDATPart, REFIID iid,
|
|
void **ppvObject) {
|
|
if (!ppvObject)
|
|
return E_INVALIDARG;
|
|
if (!IsEqualIID(__uuidof(ID3D12LibraryReflection), iid) &&
|
|
!IsEqualIID(__uuidof(IUnknown), iid))
|
|
return E_NOINTERFACE;
|
|
CComPtr<DxilLibraryReflection> pReflection =
|
|
DxilLibraryReflection::Alloc(DxcGetThreadMallocNoRef());
|
|
IFROOM(pReflection.p);
|
|
// pRDATPart used for resource usage per-function.
|
|
IFR(pReflection->Load(pProgramHeader, pRDATPart));
|
|
IFR(pReflection.p->QueryInterface(iid, ppvObject));
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CreateDxilShaderOrLibraryReflectionFromProgramHeader(
|
|
const DxilProgramHeader *pProgramHeader, const DxilPartHeader *pRDATPart,
|
|
REFIID iid, void **ppvObject) {
|
|
// Detect whether library, or if unrecognized program version.
|
|
DXIL::ShaderKind SK = GetVersionShaderType(pProgramHeader->ProgramVersion);
|
|
if (!(SK < DXIL::ShaderKind::Invalid))
|
|
return E_INVALIDARG;
|
|
bool bIsLibrary = DXIL::ShaderKind::Library == SK;
|
|
|
|
if (bIsLibrary) {
|
|
IFR(hlsl::CreateDxilLibraryReflection(pProgramHeader, pRDATPart, iid,
|
|
ppvObject));
|
|
} else {
|
|
IFR(hlsl::CreateDxilShaderReflection(pProgramHeader, pRDATPart, iid,
|
|
ppvObject));
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
bool IsValidReflectionModulePart(DxilFourCC fourCC) {
|
|
return fourCC == DFCC_DXIL || fourCC == DFCC_ShaderDebugInfoDXIL ||
|
|
fourCC == DFCC_ShaderStatistics;
|
|
}
|
|
|
|
HRESULT CreateDxilShaderOrLibraryReflectionFromModulePart(
|
|
const DxilPartHeader *pModulePart, const DxilPartHeader *pRDATPart,
|
|
REFIID iid, void **ppvObject) {
|
|
if (!pModulePart)
|
|
return E_INVALIDARG;
|
|
|
|
if (!IsValidReflectionModulePart((DxilFourCC)pModulePart->PartFourCC))
|
|
return E_INVALIDARG;
|
|
|
|
const DxilProgramHeader *pProgramHeader =
|
|
reinterpret_cast<const DxilProgramHeader *>(GetDxilPartData(pModulePart));
|
|
if (!IsValidDxilProgramHeader(pProgramHeader, pModulePart->PartSize))
|
|
return E_INVALIDARG;
|
|
|
|
// If bitcode is too small, it's probably been stripped, and we cannot create
|
|
// reflection with it.
|
|
if (pModulePart->PartSize - pProgramHeader->BitcodeHeader.BitcodeOffset < 4)
|
|
return DXC_E_MISSING_PART;
|
|
|
|
return CreateDxilShaderOrLibraryReflectionFromProgramHeader(
|
|
pProgramHeader, pRDATPart, iid, ppvObject);
|
|
}
|
|
|
|
} // namespace hlsl
|
|
|
|
HRESULT DxilContainerReflection::Load(IDxcBlob *pContainer) {
|
|
|
|
if (pContainer == nullptr) {
|
|
m_container.Release();
|
|
m_pHeader = nullptr;
|
|
m_headerLen = 0;
|
|
return S_OK;
|
|
}
|
|
|
|
CComPtr<IDxcBlob> pPDBContainer;
|
|
try {
|
|
DxcThreadMalloc DxcMalloc(m_pMalloc);
|
|
CComPtr<IStream> pStream;
|
|
IFR(hlsl::CreateReadOnlyBlobStream(pContainer, &pStream));
|
|
if (SUCCEEDED(hlsl::pdb::LoadDataFromStream(m_pMalloc, pStream,
|
|
&pPDBContainer))) {
|
|
pContainer = pPDBContainer;
|
|
}
|
|
}
|
|
CATCH_CPP_RETURN_HRESULT();
|
|
|
|
uint32_t bufLen = pContainer->GetBufferSize();
|
|
const DxilContainerHeader *pHeader =
|
|
IsDxilContainerLike(pContainer->GetBufferPointer(), bufLen);
|
|
if (pHeader == nullptr) {
|
|
return E_INVALIDARG;
|
|
}
|
|
if (!IsValidDxilContainer(pHeader, bufLen)) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
m_container = pContainer;
|
|
m_headerLen = bufLen;
|
|
m_pHeader = pHeader;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT DxilContainerReflection::GetPartCount(UINT32 *pResult) {
|
|
if (pResult == nullptr)
|
|
return E_POINTER;
|
|
if (!IsLoaded())
|
|
return E_NOT_VALID_STATE;
|
|
*pResult = m_pHeader->PartCount;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT DxilContainerReflection::GetPartKind(UINT32 idx, UINT32 *pResult) {
|
|
if (pResult == nullptr)
|
|
return E_POINTER;
|
|
if (!IsLoaded())
|
|
return E_NOT_VALID_STATE;
|
|
if (idx >= m_pHeader->PartCount)
|
|
return E_BOUNDS;
|
|
const DxilPartHeader *pPart = GetDxilContainerPart(m_pHeader, idx);
|
|
*pResult = pPart->PartFourCC;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT DxilContainerReflection::GetPartContent(UINT32 idx,
|
|
IDxcBlob **ppResult) {
|
|
if (ppResult == nullptr)
|
|
return E_POINTER;
|
|
*ppResult = nullptr;
|
|
if (!IsLoaded())
|
|
return E_NOT_VALID_STATE;
|
|
if (idx >= m_pHeader->PartCount)
|
|
return E_BOUNDS;
|
|
const DxilPartHeader *pPart = GetDxilContainerPart(m_pHeader, idx);
|
|
const char *pData = GetDxilPartData(pPart);
|
|
uint32_t offset =
|
|
(uint32_t)(pData -
|
|
(char *)m_container
|
|
->GetBufferPointer()); // Offset from the beginning.
|
|
uint32_t length = pPart->PartSize;
|
|
DxcThreadMalloc TM(m_pMalloc);
|
|
return DxcCreateBlobFromBlob(m_container, offset, length, ppResult);
|
|
}
|
|
|
|
HRESULT DxilContainerReflection::FindFirstPartKind(UINT32 kind,
|
|
UINT32 *pResult) {
|
|
if (pResult == nullptr)
|
|
return E_POINTER;
|
|
*pResult = 0;
|
|
if (!IsLoaded())
|
|
return E_NOT_VALID_STATE;
|
|
DxilPartIterator it =
|
|
std::find_if(begin(m_pHeader), end(m_pHeader), DxilPartIsType(kind));
|
|
if (it == end(m_pHeader))
|
|
return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
|
|
*pResult = it.index;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT DxilContainerReflection::GetPartReflection(UINT32 idx, REFIID iid,
|
|
void **ppvObject) {
|
|
if (ppvObject == nullptr)
|
|
return E_POINTER;
|
|
*ppvObject = nullptr;
|
|
if (!IsLoaded())
|
|
return E_NOT_VALID_STATE;
|
|
if (idx >= m_pHeader->PartCount)
|
|
return E_BOUNDS;
|
|
const DxilPartHeader *pPart = GetDxilContainerPart(m_pHeader, idx);
|
|
if (!hlsl::IsValidReflectionModulePart((hlsl::DxilFourCC)pPart->PartFourCC))
|
|
return E_NOTIMPL;
|
|
|
|
// Use DFCC_ShaderStatistics for reflection instead of DXIL part, until switch
|
|
// to using RDAT for reflection instead of module.
|
|
const DxilPartHeader *pRDATPart = nullptr;
|
|
for (idx = 0; idx < m_pHeader->PartCount; ++idx) {
|
|
const DxilPartHeader *pPartTest = GetDxilContainerPart(m_pHeader, idx);
|
|
if (pPartTest->PartFourCC == DFCC_RuntimeData) {
|
|
pRDATPart = pPartTest;
|
|
}
|
|
if (pPart->PartFourCC != DFCC_ShaderStatistics) {
|
|
if (pPartTest->PartFourCC == DFCC_ShaderStatistics) {
|
|
const DxilProgramHeader *pProgramHeaderTest =
|
|
reinterpret_cast<const DxilProgramHeader *>(
|
|
GetDxilPartData(pPartTest));
|
|
if (IsValidDxilProgramHeader(pProgramHeaderTest, pPartTest->PartSize)) {
|
|
pPart = pPartTest;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
DxcThreadMalloc TM(m_pMalloc);
|
|
HRESULT hr = S_OK;
|
|
|
|
IFC(hlsl::CreateDxilShaderOrLibraryReflectionFromModulePart(pPart, pRDATPart,
|
|
iid, ppvObject));
|
|
|
|
Cleanup:
|
|
return hr;
|
|
}
|
|
|
|
void hlsl::CreateDxcContainerReflection(IDxcContainerReflection **ppResult) {
|
|
CComPtr<DxilContainerReflection> pReflection =
|
|
DxilContainerReflection::Alloc(DxcGetThreadMallocNoRef());
|
|
*ppResult = pReflection.Detach();
|
|
if (*ppResult == nullptr)
|
|
throw std::bad_alloc();
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// DxilShaderReflection implementation - helper objects. //
|
|
|
|
class CShaderReflectionType;
|
|
class CShaderReflectionVariable;
|
|
class CShaderReflectionConstantBuffer;
|
|
class CShaderReflection;
|
|
struct D3D11_INTERNALSHADER_RESOURCE_DEF;
|
|
class CShaderReflectionType final : public ID3D12ShaderReflectionType {
|
|
friend class CShaderReflectionConstantBuffer;
|
|
|
|
protected:
|
|
D3D12_SHADER_TYPE_DESC m_Desc;
|
|
UINT m_SizeInCBuffer;
|
|
std::string m_Name;
|
|
std::vector<StringRef> m_MemberNames;
|
|
std::vector<CShaderReflectionType *> m_MemberTypes;
|
|
CShaderReflectionType *m_pSubType;
|
|
CShaderReflectionType *m_pBaseClass;
|
|
std::vector<CShaderReflectionType *> m_Interfaces;
|
|
ULONG_PTR m_Identity;
|
|
|
|
public:
|
|
// Internal
|
|
HRESULT InitializeEmpty();
|
|
HRESULT
|
|
Initialize(DxilModule &M, llvm::Type *type,
|
|
DxilFieldAnnotation &typeAnnotation, unsigned int baseOffset,
|
|
std::vector<std::unique_ptr<CShaderReflectionType>> &allTypes,
|
|
bool isCBuffer);
|
|
|
|
// ID3D12ShaderReflectionType
|
|
STDMETHOD(GetDesc)(D3D12_SHADER_TYPE_DESC *pDesc);
|
|
|
|
STDMETHOD_(ID3D12ShaderReflectionType *, GetMemberTypeByIndex)(UINT Index);
|
|
STDMETHOD_(ID3D12ShaderReflectionType *, GetMemberTypeByName)(LPCSTR Name);
|
|
STDMETHOD_(LPCSTR, GetMemberTypeName)(UINT Index);
|
|
|
|
STDMETHOD(IsEqual)(ID3D12ShaderReflectionType *pType);
|
|
STDMETHOD_(ID3D12ShaderReflectionType *, GetSubType)();
|
|
STDMETHOD_(ID3D12ShaderReflectionType *, GetBaseClass)();
|
|
STDMETHOD_(UINT, GetNumInterfaces)();
|
|
STDMETHOD_(ID3D12ShaderReflectionType *, GetInterfaceByIndex)(UINT uIndex);
|
|
STDMETHOD(IsOfType)(ID3D12ShaderReflectionType *pType);
|
|
STDMETHOD(ImplementsInterface)(ID3D12ShaderReflectionType *pBase);
|
|
|
|
bool CheckEqual(CShaderReflectionType *pOther) {
|
|
return m_Identity == pOther->m_Identity;
|
|
}
|
|
|
|
UINT GetCBufferSize() { return m_SizeInCBuffer; }
|
|
};
|
|
|
|
class CShaderReflectionVariable final : public ID3D12ShaderReflectionVariable {
|
|
protected:
|
|
D3D12_SHADER_VARIABLE_DESC m_Desc;
|
|
CShaderReflectionType *m_pType;
|
|
CShaderReflectionConstantBuffer *m_pBuffer;
|
|
BYTE *m_pDefaultValue;
|
|
|
|
public:
|
|
void Initialize(CShaderReflectionConstantBuffer *pBuffer,
|
|
D3D12_SHADER_VARIABLE_DESC *pDesc,
|
|
CShaderReflectionType *pType, BYTE *pDefaultValue);
|
|
|
|
LPCSTR GetName() { return m_Desc.Name; }
|
|
|
|
// ID3D12ShaderReflectionVariable
|
|
STDMETHOD(GetDesc)(D3D12_SHADER_VARIABLE_DESC *pDesc);
|
|
|
|
STDMETHOD_(ID3D12ShaderReflectionType *, GetType)();
|
|
STDMETHOD_(ID3D12ShaderReflectionConstantBuffer *, GetBuffer)();
|
|
|
|
STDMETHOD_(UINT, GetInterfaceSlot)(UINT uArrayIndex);
|
|
};
|
|
|
|
class CShaderReflectionConstantBuffer final
|
|
: public ID3D12ShaderReflectionConstantBuffer {
|
|
protected:
|
|
D3D12_SHADER_BUFFER_DESC m_Desc;
|
|
std::vector<CShaderReflectionVariable> m_Variables;
|
|
// For StructuredBuffer arrays, Name will have [0] appended for each dimension
|
|
// to match fxc behavior.
|
|
std::string m_ReflectionName;
|
|
|
|
public:
|
|
CShaderReflectionConstantBuffer() = default;
|
|
CShaderReflectionConstantBuffer(CShaderReflectionConstantBuffer &&other) {
|
|
m_Desc = other.m_Desc;
|
|
std::swap(m_Variables, other.m_Variables);
|
|
}
|
|
|
|
void Initialize(DxilModule &M, DxilCBuffer &CB,
|
|
std::vector<std::unique_ptr<CShaderReflectionType>> &allTypes,
|
|
bool bUsageInMetadata);
|
|
void InitializeStructuredBuffer(
|
|
DxilModule &M, DxilResource &R,
|
|
std::vector<std::unique_ptr<CShaderReflectionType>> &allTypes);
|
|
void InitializeTBuffer(
|
|
DxilModule &M, DxilResource &R,
|
|
std::vector<std::unique_ptr<CShaderReflectionType>> &allTypes,
|
|
bool bUsageInMetadata);
|
|
LPCSTR GetName() { return m_Desc.Name; }
|
|
|
|
// ID3D12ShaderReflectionConstantBuffer
|
|
STDMETHOD(GetDesc)(D3D12_SHADER_BUFFER_DESC *pDesc);
|
|
|
|
STDMETHOD_(ID3D12ShaderReflectionVariable *, GetVariableByIndex)(UINT Index);
|
|
STDMETHOD_(ID3D12ShaderReflectionVariable *, GetVariableByName)(LPCSTR Name);
|
|
};
|
|
|
|
// Invalid type sentinel definitions
|
|
class CInvalidSRType;
|
|
class CInvalidSRVariable;
|
|
class CInvalidSRConstantBuffer;
|
|
class CInvalidSRLibraryFunction;
|
|
class CInvalidSRFunctionParameter;
|
|
|
|
class CInvalidSRType final : public ID3D12ShaderReflectionType {
|
|
STDMETHOD(GetDesc)(D3D12_SHADER_TYPE_DESC *pDesc) { return E_FAIL; }
|
|
|
|
STDMETHOD_(ID3D12ShaderReflectionType *, GetMemberTypeByIndex)(UINT Index);
|
|
STDMETHOD_(ID3D12ShaderReflectionType *, GetMemberTypeByName)(LPCSTR Name);
|
|
STDMETHOD_(LPCSTR, GetMemberTypeName)(UINT Index) { return "$Invalid"; }
|
|
|
|
STDMETHOD(IsEqual)(ID3D12ShaderReflectionType *pType) { return E_FAIL; }
|
|
STDMETHOD_(ID3D12ShaderReflectionType *, GetSubType)();
|
|
STDMETHOD_(ID3D12ShaderReflectionType *, GetBaseClass)();
|
|
STDMETHOD_(UINT, GetNumInterfaces)() { return 0; }
|
|
STDMETHOD_(ID3D12ShaderReflectionType *, GetInterfaceByIndex)(UINT uIndex);
|
|
STDMETHOD(IsOfType)(ID3D12ShaderReflectionType *pType) { return E_FAIL; }
|
|
STDMETHOD(ImplementsInterface)(ID3D12ShaderReflectionType *pBase) {
|
|
return E_FAIL;
|
|
}
|
|
};
|
|
static CInvalidSRType g_InvalidSRType;
|
|
|
|
ID3D12ShaderReflectionType *CInvalidSRType::GetMemberTypeByIndex(UINT) {
|
|
return &g_InvalidSRType;
|
|
}
|
|
ID3D12ShaderReflectionType *CInvalidSRType::GetMemberTypeByName(LPCSTR) {
|
|
return &g_InvalidSRType;
|
|
}
|
|
ID3D12ShaderReflectionType *CInvalidSRType::GetSubType() {
|
|
return &g_InvalidSRType;
|
|
}
|
|
ID3D12ShaderReflectionType *CInvalidSRType::GetBaseClass() {
|
|
return &g_InvalidSRType;
|
|
}
|
|
ID3D12ShaderReflectionType *CInvalidSRType::GetInterfaceByIndex(UINT) {
|
|
return &g_InvalidSRType;
|
|
}
|
|
|
|
class CInvalidSRVariable final : public ID3D12ShaderReflectionVariable {
|
|
STDMETHOD(GetDesc)(D3D12_SHADER_VARIABLE_DESC *pDesc) { return E_FAIL; }
|
|
|
|
STDMETHOD_(ID3D12ShaderReflectionType *, GetType)() {
|
|
return &g_InvalidSRType;
|
|
}
|
|
STDMETHOD_(ID3D12ShaderReflectionConstantBuffer *, GetBuffer)();
|
|
|
|
STDMETHOD_(UINT, GetInterfaceSlot)(UINT uIndex) { return UINT_MAX; }
|
|
};
|
|
static CInvalidSRVariable g_InvalidSRVariable;
|
|
|
|
class CInvalidSRConstantBuffer final
|
|
: public ID3D12ShaderReflectionConstantBuffer {
|
|
STDMETHOD(GetDesc)(D3D12_SHADER_BUFFER_DESC *pDesc) { return E_FAIL; }
|
|
|
|
STDMETHOD_(ID3D12ShaderReflectionVariable *, GetVariableByIndex)(UINT Index) {
|
|
return &g_InvalidSRVariable;
|
|
}
|
|
STDMETHOD_(ID3D12ShaderReflectionVariable *, GetVariableByName)(LPCSTR Name) {
|
|
return &g_InvalidSRVariable;
|
|
}
|
|
};
|
|
static CInvalidSRConstantBuffer g_InvalidSRConstantBuffer;
|
|
|
|
class CInvalidFunctionParameter final
|
|
: public ID3D12FunctionParameterReflection {
|
|
STDMETHOD(GetDesc)(D3D12_PARAMETER_DESC *pDesc) { return E_FAIL; }
|
|
};
|
|
CInvalidFunctionParameter g_InvalidFunctionParameter;
|
|
|
|
class CInvalidFunction final : public ID3D12FunctionReflection {
|
|
STDMETHOD(GetDesc)(D3D12_FUNCTION_DESC *pDesc) { return E_FAIL; }
|
|
|
|
STDMETHOD_(ID3D12ShaderReflectionConstantBuffer *, GetConstantBufferByIndex)
|
|
(UINT BufferIndex) { return &g_InvalidSRConstantBuffer; }
|
|
STDMETHOD_(ID3D12ShaderReflectionConstantBuffer *, GetConstantBufferByName)
|
|
(LPCSTR Name) { return &g_InvalidSRConstantBuffer; }
|
|
|
|
STDMETHOD(GetResourceBindingDesc)
|
|
(UINT ResourceIndex, D3D12_SHADER_INPUT_BIND_DESC *pDesc) { return E_FAIL; }
|
|
|
|
STDMETHOD_(ID3D12ShaderReflectionVariable *, GetVariableByName)(LPCSTR Name) {
|
|
return nullptr;
|
|
}
|
|
|
|
STDMETHOD(GetResourceBindingDescByName)
|
|
(LPCSTR Name, D3D12_SHADER_INPUT_BIND_DESC *pDesc) { return E_FAIL; }
|
|
|
|
// Use D3D_RETURN_PARAMETER_INDEX to get description of the return value.
|
|
STDMETHOD_(ID3D12FunctionParameterReflection *, GetFunctionParameter)
|
|
(INT ParameterIndex) { return &g_InvalidFunctionParameter; }
|
|
};
|
|
CInvalidFunction g_InvalidFunction;
|
|
|
|
void CShaderReflectionVariable::Initialize(
|
|
CShaderReflectionConstantBuffer *pBuffer, D3D12_SHADER_VARIABLE_DESC *pDesc,
|
|
CShaderReflectionType *pType, BYTE *pDefaultValue) {
|
|
m_pBuffer = pBuffer;
|
|
memcpy(&m_Desc, pDesc, sizeof(m_Desc));
|
|
m_pType = pType;
|
|
m_pDefaultValue = pDefaultValue;
|
|
}
|
|
|
|
HRESULT CShaderReflectionVariable::GetDesc(D3D12_SHADER_VARIABLE_DESC *pDesc) {
|
|
if (!pDesc)
|
|
return E_POINTER;
|
|
memcpy(pDesc, &m_Desc, sizeof(m_Desc));
|
|
return S_OK;
|
|
}
|
|
|
|
ID3D12ShaderReflectionType *CShaderReflectionVariable::GetType() {
|
|
return m_pType;
|
|
}
|
|
|
|
ID3D12ShaderReflectionConstantBuffer *CShaderReflectionVariable::GetBuffer() {
|
|
return m_pBuffer;
|
|
}
|
|
|
|
UINT CShaderReflectionVariable::GetInterfaceSlot(UINT uArrayIndex) {
|
|
return UINT_MAX;
|
|
}
|
|
|
|
ID3D12ShaderReflectionConstantBuffer *CInvalidSRVariable::GetBuffer() {
|
|
return &g_InvalidSRConstantBuffer;
|
|
}
|
|
|
|
STDMETHODIMP CShaderReflectionType::GetDesc(D3D12_SHADER_TYPE_DESC *pDesc) {
|
|
if (!pDesc)
|
|
return E_POINTER;
|
|
memcpy(pDesc, &m_Desc, sizeof(m_Desc));
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP_(ID3D12ShaderReflectionType *)
|
|
CShaderReflectionType::GetMemberTypeByIndex(UINT Index) {
|
|
if (Index >= m_MemberTypes.size()) {
|
|
return &g_InvalidSRType;
|
|
}
|
|
return m_MemberTypes[Index];
|
|
}
|
|
|
|
STDMETHODIMP_(LPCSTR) CShaderReflectionType::GetMemberTypeName(UINT Index) {
|
|
if (Index >= m_MemberTypes.size()) {
|
|
return nullptr;
|
|
}
|
|
return (LPCSTR)m_MemberNames[Index].bytes_begin();
|
|
}
|
|
|
|
STDMETHODIMP_(ID3D12ShaderReflectionType *)
|
|
CShaderReflectionType::GetMemberTypeByName(LPCSTR Name) {
|
|
UINT memberCount = m_Desc.Members;
|
|
for (UINT mm = 0; mm < memberCount; ++mm) {
|
|
if (m_MemberNames[mm] == Name) {
|
|
return m_MemberTypes[mm];
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
STDMETHODIMP CShaderReflectionType::IsEqual(ID3D12ShaderReflectionType *pType) {
|
|
// TODO: implement this check, if users actually depend on it
|
|
return S_FALSE;
|
|
}
|
|
|
|
STDMETHODIMP_(ID3D12ShaderReflectionType *)
|
|
CShaderReflectionType::GetSubType() {
|
|
// TODO: implement `class`-related features, if requested
|
|
return nullptr;
|
|
}
|
|
|
|
STDMETHODIMP_(ID3D12ShaderReflectionType *)
|
|
CShaderReflectionType::GetBaseClass() {
|
|
// TODO: implement `class`-related features, if requested
|
|
return nullptr;
|
|
}
|
|
|
|
STDMETHODIMP_(UINT) CShaderReflectionType::GetNumInterfaces() {
|
|
// HLSL interfaces have been deprecated
|
|
return 0;
|
|
}
|
|
|
|
STDMETHODIMP_(ID3D12ShaderReflectionType *)
|
|
CShaderReflectionType::GetInterfaceByIndex(UINT uIndex) {
|
|
// HLSL interfaces have been deprecated
|
|
return nullptr;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CShaderReflectionType::IsOfType(ID3D12ShaderReflectionType *pType) {
|
|
// TODO: implement `class`-related features, if requested
|
|
return S_FALSE;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CShaderReflectionType::ImplementsInterface(ID3D12ShaderReflectionType *pBase) {
|
|
// HLSL interfaces have been deprecated
|
|
return S_FALSE;
|
|
}
|
|
|
|
// Helper routine for types that don't have an obvious mapping
|
|
// to the existing shader reflection interface.
|
|
static bool
|
|
ProcessUnhandledObjectType(llvm::StructType *structType,
|
|
D3D_SHADER_VARIABLE_TYPE *outObjectType) {
|
|
// Don't actually make this a hard error, but instead report the problem using
|
|
// a suitable debug message.
|
|
#ifndef NDEBUG
|
|
OutputDebugFormatA(
|
|
"DxilContainerReflection.cpp: error: unhandled object type '%s'.\n",
|
|
structType->getName().str().c_str());
|
|
#endif
|
|
*outObjectType = D3D_SVT_VOID;
|
|
return true;
|
|
}
|
|
|
|
// Helper routine to try to detect if a type represents an HLSL "object" type
|
|
// (a texture, sampler, buffer, etc.), and to extract the coresponding shader
|
|
// reflection type.
|
|
static bool TryToDetectObjectType(llvm::StructType *structType,
|
|
D3D_SHADER_VARIABLE_TYPE *outObjectType) {
|
|
// Note: This logic is largely duplicated from `dxilutil::IsHLSLObjectType`
|
|
// with the addition of returning the appropriate reflection type tag.
|
|
//
|
|
// That logic looks error-prone, since it relies on string tests against
|
|
// type names, including cases that just test against a prefix.
|
|
// This code doesn't try to be any more robust.
|
|
|
|
StringRef name = structType->getName();
|
|
|
|
if (name.startswith("dx.types.wave_t")) {
|
|
return ProcessUnhandledObjectType(structType, outObjectType);
|
|
}
|
|
|
|
// Strip off some prefixes we are likely to see.
|
|
name = name.ltrim("class.");
|
|
name = name.ltrim("struct.");
|
|
|
|
// Slice types occur as intermediates (they aren not objects)
|
|
if (name.endswith("_slice_type")) {
|
|
return false;
|
|
}
|
|
|
|
// We might check for an exact name match, or a prefix match
|
|
#define EXACT_MATCH(NAME, TAG) \
|
|
else if (name == #NAME) do { \
|
|
*outObjectType = TAG; \
|
|
return true; \
|
|
} \
|
|
while (0)
|
|
#define PREFIX_MATCH(NAME, TAG) \
|
|
else if (name.startswith(#NAME)) do { \
|
|
*outObjectType = TAG; \
|
|
return true; \
|
|
} \
|
|
while (0)
|
|
|
|
if (0) {
|
|
}
|
|
EXACT_MATCH(SamplerState, D3D_SVT_SAMPLER);
|
|
EXACT_MATCH(SamplerComparisonState, D3D_SVT_SAMPLER);
|
|
|
|
// Note: GS output stream types are supported in the reflection interface.
|
|
else if (name.startswith("TriangleStream")) {
|
|
return ProcessUnhandledObjectType(structType, outObjectType);
|
|
}
|
|
else if (name.startswith("PointStream")) {
|
|
return ProcessUnhandledObjectType(structType, outObjectType);
|
|
}
|
|
else if (name.startswith("LineStream")) {
|
|
return ProcessUnhandledObjectType(structType, outObjectType);
|
|
}
|
|
|
|
PREFIX_MATCH(AppendStructuredBuffer, D3D_SVT_APPEND_STRUCTURED_BUFFER);
|
|
PREFIX_MATCH(ConsumeStructuredBuffer, D3D_SVT_CONSUME_STRUCTURED_BUFFER);
|
|
PREFIX_MATCH(ConstantBuffer, D3D_SVT_CBUFFER);
|
|
|
|
// Note: the `HLModule` code does this trick to avoid checking more names
|
|
// than it has to, but it doesn't seem 100% correct to do this.
|
|
// TODO: consider just listing the `RasterizerOrdered` cases explicitly,
|
|
// just as we do for the `RW` cases already.
|
|
name = name.ltrim("RasterizerOrdered");
|
|
|
|
if (0) {
|
|
}
|
|
EXACT_MATCH(ByteAddressBuffer, D3D_SVT_BYTEADDRESS_BUFFER);
|
|
EXACT_MATCH(RWByteAddressBuffer, D3D_SVT_RWBYTEADDRESS_BUFFER);
|
|
PREFIX_MATCH(Buffer, D3D_SVT_BUFFER);
|
|
PREFIX_MATCH(RWBuffer, D3D_SVT_RWBUFFER);
|
|
PREFIX_MATCH(StructuredBuffer, D3D_SVT_STRUCTURED_BUFFER);
|
|
PREFIX_MATCH(RWStructuredBuffer, D3D_SVT_RWSTRUCTURED_BUFFER);
|
|
PREFIX_MATCH(Texture1D, D3D_SVT_TEXTURE1D);
|
|
PREFIX_MATCH(RWTexture1D, D3D_SVT_RWTEXTURE1D);
|
|
PREFIX_MATCH(Texture1DArray, D3D_SVT_TEXTURE1DARRAY);
|
|
PREFIX_MATCH(RWTexture1DArray, D3D_SVT_RWTEXTURE1DARRAY);
|
|
PREFIX_MATCH(Texture2D, D3D_SVT_TEXTURE2D);
|
|
PREFIX_MATCH(RWTexture2D, D3D_SVT_RWTEXTURE2D);
|
|
PREFIX_MATCH(Texture2DArray, D3D_SVT_TEXTURE2DARRAY);
|
|
PREFIX_MATCH(RWTexture2DArray, D3D_SVT_RWTEXTURE2DARRAY);
|
|
PREFIX_MATCH(Texture3D, D3D_SVT_TEXTURE3D);
|
|
PREFIX_MATCH(RWTexture3D, D3D_SVT_RWTEXTURE3D);
|
|
PREFIX_MATCH(TextureCube, D3D_SVT_TEXTURECUBE);
|
|
PREFIX_MATCH(TextureCubeArray, D3D_SVT_TEXTURECUBEARRAY);
|
|
PREFIX_MATCH(Texture2DMS, D3D_SVT_TEXTURE2DMS);
|
|
PREFIX_MATCH(Texture2DMSArray, D3D_SVT_TEXTURE2DMSARRAY);
|
|
|
|
#undef EXACT_MATCH
|
|
#undef PREFIX_MATCH
|
|
|
|
// Default: not an object type
|
|
return false;
|
|
}
|
|
|
|
// Helper to determine if an LLVM type represents an HLSL
|
|
// object type (uses the `TryToDetectObjectType()` function
|
|
// defined previously).
|
|
static bool IsObjectType(llvm::Type *inType) {
|
|
llvm::Type *type = inType;
|
|
while (type->isArrayTy()) {
|
|
type = type->getArrayElementType();
|
|
}
|
|
|
|
llvm::StructType *structType = dyn_cast<StructType>(type);
|
|
if (!structType)
|
|
return false;
|
|
|
|
D3D_SHADER_VARIABLE_TYPE ignored;
|
|
return TryToDetectObjectType(structType, &ignored);
|
|
}
|
|
|
|
HRESULT CShaderReflectionType::InitializeEmpty() {
|
|
ZeroMemory(&m_Desc, sizeof(m_Desc));
|
|
return S_OK;
|
|
}
|
|
|
|
// Returns true if type is array and/or vec with matching number of elements.
|
|
static bool MatchVectorOrMatrixType(llvm::Type *type, unsigned count,
|
|
int maxDepth) {
|
|
if (type->isArrayTy()) {
|
|
unsigned arraySize = (unsigned)type->getArrayNumElements();
|
|
if (maxDepth < 1 || count < arraySize || (count % arraySize) != 0)
|
|
return false;
|
|
return MatchVectorOrMatrixType(type->getArrayElementType(),
|
|
count / arraySize, maxDepth - 1);
|
|
} else if (type->isVectorTy()) {
|
|
if (maxDepth < 1)
|
|
return false;
|
|
return type->getVectorNumElements() == count;
|
|
}
|
|
return count == 1;
|
|
}
|
|
|
|
// Main logic for translating an LLVM type and associated
|
|
// annotations into a D3D shader reflection type.
|
|
HRESULT CShaderReflectionType::Initialize(
|
|
DxilModule &M, llvm::Type *inType, DxilFieldAnnotation &typeAnnotation,
|
|
unsigned int baseOffset,
|
|
std::vector<std::unique_ptr<CShaderReflectionType>> &allTypes,
|
|
bool isCBuffer) {
|
|
DXASSERT_NOMSG(inType);
|
|
|
|
// Set a bunch of fields to default values, to avoid duplication.
|
|
m_Desc.Class = D3D_SVC_SCALAR;
|
|
m_Desc.Rows = 0;
|
|
m_Desc.Columns = 0;
|
|
m_Desc.Elements = 0;
|
|
m_Desc.Members = 0;
|
|
m_SizeInCBuffer = 0;
|
|
|
|
// Used for calculating size later
|
|
unsigned cbRows = 1;
|
|
unsigned cbCols = 1;
|
|
unsigned cbCompSize = 4; // or 8 for 64-bit types.
|
|
unsigned cbRowStride = 16; // or 32 if 64-bit and cols > 2.
|
|
|
|
if (isCBuffer) {
|
|
// Extract offset relative to parent.
|
|
// Note: the `baseOffset` is used in the case where the type in
|
|
// question is a field in a constant buffer, since then both the
|
|
// field and the variable store the same offset information, and
|
|
// we need to zero out the value in the type to avoid the user
|
|
// of the reflection interface seeing 2x the correct value.
|
|
m_Desc.Offset = typeAnnotation.GetCBufferOffset() - baseOffset;
|
|
} else {
|
|
m_Desc.Offset = baseOffset;
|
|
}
|
|
|
|
// Arrays don't seem to be represented directly in the reflection
|
|
// data, but only as the `Elements` field being non-zero.
|
|
// We "unwrap" any array type here, and then proceed to look
|
|
// at the element type.
|
|
llvm::Type *type = inType;
|
|
|
|
// Arrays can be a bit difficult, since some types are translated to arrays.
|
|
// Additionally, matrices have multiple potential forms, so we must pay
|
|
// attention to the field annotation to determine when we have reached the
|
|
// element type that may be a matrix or a vector.
|
|
|
|
// There are several possible matrix encodings:
|
|
// High level: struct { [rows x <cols x float>] }
|
|
// High level struct stripped: [rows x <cols x float>]
|
|
// High level struct stripped, one row: <cols x float>
|
|
// Vector as array: [rows x [cols x float]]
|
|
// Vector as array, one row: [cols x float]
|
|
// Flattened vector: <(rows*cols) x float>
|
|
// Flattened vector as array: [(rows*cols) x float]
|
|
// And vector may use llvm vector, or be translated to array:
|
|
// <cols x float> <-> [cols x float]
|
|
// Use type annotation to determine if we have a vector or matrix first,
|
|
// so we can stop multiplying in array dims at the right time.
|
|
|
|
if (typeAnnotation.HasMatrixAnnotation()) {
|
|
// We can extract the details from the annotation.
|
|
DxilMatrixAnnotation const &matrixAnnotation =
|
|
typeAnnotation.GetMatrixAnnotation();
|
|
|
|
switch (matrixAnnotation.Orientation) {
|
|
default:
|
|
#ifndef NDEBUG
|
|
OutputDebugStringA(
|
|
"DxilContainerReflection.cpp: error: unknown matrix orientation\n");
|
|
#endif
|
|
// Note: column-major layout is the default
|
|
LLVM_FALLTHROUGH; // HLSL Change
|
|
case hlsl::MatrixOrientation::Undefined:
|
|
case hlsl::MatrixOrientation::ColumnMajor:
|
|
m_Desc.Class = D3D_SVC_MATRIX_COLUMNS;
|
|
break;
|
|
|
|
case hlsl::MatrixOrientation::RowMajor:
|
|
m_Desc.Class = D3D_SVC_MATRIX_ROWS;
|
|
break;
|
|
}
|
|
|
|
m_Desc.Rows = matrixAnnotation.Rows;
|
|
m_Desc.Columns = matrixAnnotation.Cols;
|
|
|
|
cbRows = m_Desc.Rows;
|
|
cbCols = m_Desc.Columns;
|
|
if (m_Desc.Class == D3D_SVC_MATRIX_COLUMNS) {
|
|
std::swap(cbRows, cbCols);
|
|
}
|
|
} else if (unsigned cols = typeAnnotation.GetVectorSize()) {
|
|
// Older format lacks this size, but the type will be a vector,
|
|
// so that will be handled later by original code path.
|
|
m_Desc.Class = D3D_SVC_VECTOR;
|
|
m_Desc.Rows = 1;
|
|
m_Desc.Columns = cols;
|
|
|
|
cbRows = m_Desc.Rows;
|
|
cbCols = m_Desc.Columns;
|
|
}
|
|
|
|
while (type->isArrayTy()) {
|
|
// Already determined that this is a vector or matrix, so break if the
|
|
// number of remaining array and/or vector elements matches.
|
|
if (m_Desc.Class != D3D_SVC_SCALAR) {
|
|
// max depth is 1 for vector, and 2 for matrix, unless rows in storage
|
|
// orientation is 1.
|
|
if (MatchVectorOrMatrixType(
|
|
type, cbRows * cbCols,
|
|
(m_Desc.Class == D3D_SVC_VECTOR || cbRows == 1) ? 1 : 2))
|
|
break;
|
|
}
|
|
|
|
// Non-array types should have `Elements` be zero, so as soon as we
|
|
// find that we have our first real array (not a matrix), we initialize
|
|
// `Elements`
|
|
if (!m_Desc.Elements)
|
|
m_Desc.Elements = 1;
|
|
|
|
// It isn't clear what is the desired behavior for multi-dimensional arrays,
|
|
// but for now we do the expedient thing of multiplying out all their
|
|
// dimensions.
|
|
m_Desc.Elements *= type->getArrayNumElements();
|
|
type = type->getArrayElementType();
|
|
}
|
|
|
|
// Look at the annotation to try to determine the basic type of value.
|
|
//
|
|
// Note that DXIL supports some types that don't currently have equivalents
|
|
// in the reflection interface, so we try to muddle through here.
|
|
bool bMinPrec = M.GetUseMinPrecision();
|
|
D3D_SHADER_VARIABLE_TYPE componentType = D3D_SVT_VOID;
|
|
switch (typeAnnotation.GetCompType().GetKind()) {
|
|
case hlsl::DXIL::ComponentType::Invalid:
|
|
break;
|
|
|
|
case hlsl::DXIL::ComponentType::I1:
|
|
componentType = D3D_SVT_BOOL;
|
|
m_Name = "bool";
|
|
break;
|
|
|
|
case hlsl::DXIL::ComponentType::I16:
|
|
if (bMinPrec) {
|
|
componentType = D3D_SVT_MIN16INT;
|
|
m_Name = "min16int";
|
|
} else {
|
|
componentType = D3D_SVT_INT16;
|
|
m_Name = "int16_t";
|
|
cbCompSize = 2;
|
|
}
|
|
break;
|
|
|
|
case hlsl::DXIL::ComponentType::U16:
|
|
if (bMinPrec) {
|
|
componentType = D3D_SVT_MIN16UINT;
|
|
m_Name = "min16uint";
|
|
} else {
|
|
componentType = D3D_SVT_UINT16;
|
|
m_Name = "uint16_t";
|
|
cbCompSize = 2;
|
|
}
|
|
break;
|
|
|
|
case hlsl::DXIL::ComponentType::I64:
|
|
componentType = D3D_SVT_INT64;
|
|
m_Name = "int64_t";
|
|
cbCompSize = 8;
|
|
break;
|
|
case hlsl::DXIL::ComponentType::I32:
|
|
componentType = D3D_SVT_INT;
|
|
m_Name = "int";
|
|
break;
|
|
|
|
case hlsl::DXIL::ComponentType::U64:
|
|
componentType = D3D_SVT_UINT64;
|
|
m_Name = "uint64_t";
|
|
cbCompSize = 8;
|
|
break;
|
|
case hlsl::DXIL::ComponentType::U32:
|
|
componentType = D3D_SVT_UINT;
|
|
m_Name = "uint";
|
|
break;
|
|
|
|
case hlsl::DXIL::ComponentType::F16:
|
|
case hlsl::DXIL::ComponentType::SNormF16:
|
|
case hlsl::DXIL::ComponentType::UNormF16:
|
|
if (bMinPrec) {
|
|
componentType = D3D_SVT_MIN16FLOAT;
|
|
m_Name = "min16float";
|
|
} else {
|
|
componentType = D3D_SVT_FLOAT16;
|
|
m_Name = "float16_t";
|
|
cbCompSize = 2;
|
|
}
|
|
break;
|
|
|
|
case hlsl::DXIL::ComponentType::F32:
|
|
case hlsl::DXIL::ComponentType::SNormF32:
|
|
case hlsl::DXIL::ComponentType::UNormF32:
|
|
componentType = D3D_SVT_FLOAT;
|
|
m_Name = "float";
|
|
break;
|
|
|
|
case hlsl::DXIL::ComponentType::F64:
|
|
case hlsl::DXIL::ComponentType::SNormF64:
|
|
case hlsl::DXIL::ComponentType::UNormF64:
|
|
cbCompSize = 8;
|
|
componentType = D3D_SVT_DOUBLE;
|
|
m_Name = "double";
|
|
break;
|
|
|
|
default:
|
|
#ifndef NDEBUG
|
|
OutputDebugStringA(
|
|
"DxilContainerReflection.cpp: error: unknown component type\n");
|
|
#endif
|
|
break;
|
|
}
|
|
m_Desc.Type = componentType;
|
|
|
|
if (m_Desc.Class != D3D_SVC_SCALAR) {
|
|
// matrix or explicit vector already handled, except for name.
|
|
if (m_Desc.Class == D3D_SVC_VECTOR) {
|
|
m_Name += std::to_string(m_Desc.Columns);
|
|
} else {
|
|
m_Name +=
|
|
std::to_string(m_Desc.Rows) + "x" + std::to_string(m_Desc.Columns);
|
|
}
|
|
} else if (FixedVectorType *VT = dyn_cast<FixedVectorType>(type)) {
|
|
// We assume that LLVM vectors either represent matrices (handled above)
|
|
// or HLSL vectors.
|
|
//
|
|
// Note: the reflection interface encodes an N-vector as if it had 1 row
|
|
// and N columns.
|
|
m_Desc.Class = D3D_SVC_VECTOR;
|
|
m_Desc.Rows = 1;
|
|
m_Desc.Columns = VT->getNumElements();
|
|
|
|
m_Name += std::to_string(VT->getNumElements());
|
|
|
|
cbRows = m_Desc.Rows;
|
|
cbCols = m_Desc.Columns;
|
|
} else if (type->isStructTy()) {
|
|
// A struct type might be an ordinary user-defined `struct`,
|
|
// or one of the builtin in HLSL "object" types.
|
|
StructType *structType = cast<StructType>(type);
|
|
const StructLayout *structLayout =
|
|
isCBuffer ? nullptr
|
|
: M.GetModule()->getDataLayout().getStructLayout(structType);
|
|
|
|
// We use our function to try to detect an object type
|
|
// based on its name.
|
|
if (TryToDetectObjectType(structType, &m_Desc.Type)) {
|
|
m_Desc.Class = D3D_SVC_OBJECT;
|
|
} else {
|
|
// Otherwise we have a struct and need to recurse on its fields.
|
|
m_Desc.Class = D3D_SVC_STRUCT;
|
|
m_Desc.Rows = 1;
|
|
|
|
// Try to "clean" the type name for use in reflection data
|
|
llvm::StringRef name = structType->getName();
|
|
name =
|
|
name.ltrim("dx.alignment.legacy."); // legacy prefix for legacy types
|
|
name = name.ltrim(kHostLayoutTypePrefix);
|
|
name = name.ltrim("struct.");
|
|
m_Name = name;
|
|
|
|
// Fields may have annotations, and we need to look at these
|
|
// in order to decode their types properly.
|
|
DxilTypeSystem &typeSys = M.GetTypeSystem();
|
|
DxilStructAnnotation *structAnnotation =
|
|
typeSys.GetStructAnnotation(structType);
|
|
|
|
// There is no annotation for empty structs
|
|
unsigned int fieldCount = 0;
|
|
if (structAnnotation && !structAnnotation->IsEmptyBesidesResources())
|
|
fieldCount = type->getStructNumElements();
|
|
|
|
// The DXBC reflection info computes `Columns` for a
|
|
// `struct` type from the fields (see below)
|
|
UINT columnCounter = 0;
|
|
|
|
CShaderReflectionType *fieldReflectionType = nullptr;
|
|
|
|
for (unsigned int ff = 0; ff < fieldCount; ++ff) {
|
|
DxilFieldAnnotation &fieldAnnotation =
|
|
structAnnotation->GetFieldAnnotation(ff);
|
|
llvm::Type *fieldType = structType->getStructElementType(ff);
|
|
|
|
// Skip fields with object types, since these are not part of constant
|
|
// buffers, and are not allowed in other buffer types.
|
|
if (IsObjectType(fieldType)) {
|
|
continue;
|
|
}
|
|
|
|
fieldReflectionType = new CShaderReflectionType();
|
|
allTypes.push_back(
|
|
std::unique_ptr<CShaderReflectionType>(fieldReflectionType));
|
|
|
|
unsigned int elementOffset =
|
|
structLayout ? (unsigned int)structLayout->getElementOffset(ff) : 0;
|
|
|
|
fieldReflectionType->Initialize(M, fieldType, fieldAnnotation,
|
|
elementOffset, allTypes, isCBuffer);
|
|
|
|
// Treat bit fields as member inside the integer.
|
|
if (fieldAnnotation.HasBitFields())
|
|
fieldReflectionType->m_Desc.Members =
|
|
fieldAnnotation.GetBitFields().size();
|
|
|
|
m_MemberTypes.push_back(fieldReflectionType);
|
|
m_MemberNames.push_back(fieldAnnotation.GetFieldName().c_str());
|
|
|
|
// Skip structures fields with no real contents, otherwise we expand
|
|
// the size of this struct by 1 when we treat a zero column size as 1.
|
|
if (isa<StructType>(fieldType) &&
|
|
fieldReflectionType->m_Desc.Columns == 0) {
|
|
continue;
|
|
}
|
|
|
|
// Effectively, we want to add one to `Columns` for every scalar
|
|
// nested recursively inside this `struct` type (ignoring objects,
|
|
// which we filtered above). We should be able to compute this as the
|
|
// product of the `Columns`, `Rows` and `Elements` of each field, with
|
|
// the caveat that some of these may be zero, but shoud be treated as
|
|
// one.
|
|
columnCounter +=
|
|
(fieldReflectionType->m_Desc.Columns
|
|
? fieldReflectionType->m_Desc.Columns
|
|
: 1) *
|
|
(fieldReflectionType->m_Desc.Rows ? fieldReflectionType->m_Desc.Rows
|
|
: 1) *
|
|
(fieldReflectionType->m_Desc.Elements
|
|
? fieldReflectionType->m_Desc.Elements
|
|
: 1);
|
|
|
|
if (fieldAnnotation.HasBitFields()) {
|
|
unsigned bitOffset = 0;
|
|
CShaderReflectionType *bitFieldReflectionType = nullptr;
|
|
for (auto &bitfieldAnnotation : fieldAnnotation.GetBitFields()) {
|
|
bitFieldReflectionType = new CShaderReflectionType();
|
|
allTypes.push_back(
|
|
std::unique_ptr<CShaderReflectionType>(bitFieldReflectionType));
|
|
|
|
bitFieldReflectionType->Initialize(M, fieldType, fieldAnnotation,
|
|
elementOffset, allTypes,
|
|
isCBuffer);
|
|
bitFieldReflectionType->m_Desc.Class = D3D_SVC_BIT_FIELD;
|
|
|
|
// Save bit size to columns.
|
|
bitFieldReflectionType->m_Desc.Columns =
|
|
bitfieldAnnotation.GetBitFieldWidth();
|
|
// Save bit offset to Offset.
|
|
bitFieldReflectionType->m_Desc.Offset = bitOffset;
|
|
bitOffset += bitfieldAnnotation.GetBitFieldWidth();
|
|
|
|
fieldReflectionType->m_MemberTypes.push_back(
|
|
bitFieldReflectionType);
|
|
fieldReflectionType->m_MemberNames.push_back(
|
|
bitfieldAnnotation.GetFieldName().c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
m_Desc.Columns = columnCounter;
|
|
|
|
if (fieldReflectionType) {
|
|
// Set our size based on the last fields offset + size:
|
|
m_SizeInCBuffer = fieldReflectionType->m_Desc.Offset +
|
|
fieldReflectionType->m_SizeInCBuffer;
|
|
if (m_Desc.Elements > 1) {
|
|
unsigned alignedSize = ((m_SizeInCBuffer + 15) & ~0xF);
|
|
m_SizeInCBuffer += (m_Desc.Elements - 1) * alignedSize;
|
|
}
|
|
}
|
|
|
|
// Because we might have skipped fields during enumeration,
|
|
// the `Members` count in the description might not be the same
|
|
// as the field count of the original LLVM type.
|
|
m_Desc.Members = m_MemberTypes.size();
|
|
}
|
|
} else if (type->isPointerTy()) {
|
|
#ifndef NDEBUG
|
|
OutputDebugStringA(
|
|
"DxilContainerReflection.cpp: error: cannot reflect pointer type\n");
|
|
#endif
|
|
} else if (type->isVoidTy()) {
|
|
// Name for `void` wasn't handle in the component-type `switch` above
|
|
m_Name = "void";
|
|
m_Desc.Class = D3D_SVC_SCALAR;
|
|
m_Desc.Rows = 1;
|
|
m_Desc.Columns = 1;
|
|
} else {
|
|
// Assume we have a scalar at this point.
|
|
m_Desc.Class = D3D_SVC_SCALAR;
|
|
m_Desc.Rows = 1;
|
|
m_Desc.Columns = 1;
|
|
|
|
// Special-case naming
|
|
switch (m_Desc.Type) {
|
|
default:
|
|
break;
|
|
|
|
case D3D_SVT_UINT:
|
|
// Scalar `uint` gets reflected as `dword`, while vectors/matrices use
|
|
// `uint`...
|
|
m_Name = "dword";
|
|
break;
|
|
}
|
|
|
|
cbRows = 1;
|
|
cbCols = 1;
|
|
}
|
|
// TODO: are there other cases to be handled?
|
|
|
|
// Compute our cbuffer size for member reflection
|
|
switch (m_Desc.Class) {
|
|
case D3D_SVC_SCALAR:
|
|
case D3D_SVC_MATRIX_COLUMNS:
|
|
case D3D_SVC_MATRIX_ROWS:
|
|
case D3D_SVC_VECTOR:
|
|
if (m_Desc.Elements > 1)
|
|
cbRows = cbRows * m_Desc.Elements;
|
|
if (cbCompSize > 4 && cbCols > 2)
|
|
cbRowStride = 32;
|
|
m_SizeInCBuffer = cbRowStride * (cbRows - 1) + cbCompSize * cbCols;
|
|
break;
|
|
}
|
|
|
|
m_Desc.Name = m_Name.c_str();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
void CShaderReflectionConstantBuffer::Initialize(
|
|
DxilModule &M, DxilCBuffer &CB,
|
|
std::vector<std::unique_ptr<CShaderReflectionType>> &allTypes,
|
|
bool bUsageInMetadata) {
|
|
ZeroMemory(&m_Desc, sizeof(m_Desc));
|
|
m_ReflectionName = CB.GetGlobalName();
|
|
m_Desc.Name = m_ReflectionName.c_str();
|
|
m_Desc.Size = CB.GetSize();
|
|
m_Desc.Size =
|
|
(m_Desc.Size + 0x0f) & ~(0x0f); // Round up to 16 bytes for reflection.
|
|
m_Desc.Type = D3D_CT_CBUFFER;
|
|
m_Desc.uFlags = 0;
|
|
// For ConstantBuffer<> buf[2], the array size is in Resource binding count
|
|
// part.
|
|
Type *Ty =
|
|
dxilutil::StripArrayTypes(CB.GetHLSLType()->getPointerElementType());
|
|
|
|
DxilTypeSystem &typeSys = M.GetTypeSystem();
|
|
StructType *ST = cast<StructType>(Ty);
|
|
DxilStructAnnotation *annotation =
|
|
typeSys.GetStructAnnotation(cast<StructType>(ST));
|
|
// Dxil from dxbc doesn't have annotation.
|
|
if (!annotation)
|
|
return;
|
|
|
|
m_Desc.Variables = ST->getNumContainedTypes();
|
|
|
|
if (CB.GetRangeSize() > 1) {
|
|
DXASSERT(m_Desc.Variables == 1, "otherwise, assumption is wrong");
|
|
}
|
|
|
|
// If only one member, it's used if it's here.
|
|
bool bAllUsed = ST->getNumContainedTypes() < 2;
|
|
bAllUsed |= !bUsageInMetadata; // Will update in SetCBufferUsage.
|
|
|
|
for (unsigned i = 0; i < ST->getNumContainedTypes(); ++i) {
|
|
DxilFieldAnnotation &fieldAnnotation = annotation->GetFieldAnnotation(i);
|
|
|
|
D3D12_SHADER_VARIABLE_DESC VarDesc;
|
|
ZeroMemory(&VarDesc, sizeof(VarDesc));
|
|
VarDesc.uFlags =
|
|
(bAllUsed || fieldAnnotation.IsCBVarUsed()) ? D3D_SVF_USED : 0;
|
|
CShaderReflectionVariable Var;
|
|
// Create reflection type.
|
|
CShaderReflectionType *pVarType = new CShaderReflectionType();
|
|
allTypes.push_back(std::unique_ptr<CShaderReflectionType>(pVarType));
|
|
pVarType->Initialize(M, ST->getContainedType(i), fieldAnnotation,
|
|
fieldAnnotation.GetCBufferOffset(), allTypes, true);
|
|
|
|
// Replicate fxc bug, where Elements == 1 for inner struct of CB array,
|
|
// instead of 0.
|
|
if (CB.GetRangeSize() > 1) {
|
|
DXASSERT(pVarType->m_Desc.Elements == 0,
|
|
"otherwise, assumption is wrong");
|
|
pVarType->m_Desc.Elements = 1;
|
|
} else if (CB.GetHLSLType()->getPointerElementType()->isArrayTy() &&
|
|
CB.GetRangeSize() == 1) {
|
|
// Set elements to 1 for size 1 array.
|
|
pVarType->m_Desc.Elements = 1;
|
|
}
|
|
|
|
BYTE *pDefaultValue = nullptr;
|
|
|
|
VarDesc.Name = fieldAnnotation.GetFieldName().c_str();
|
|
VarDesc.StartOffset = fieldAnnotation.GetCBufferOffset();
|
|
VarDesc.Size = pVarType->GetCBufferSize();
|
|
Var.Initialize(this, &VarDesc, pVarType, pDefaultValue);
|
|
m_Variables.push_back(Var);
|
|
}
|
|
}
|
|
|
|
static unsigned CalcResTypeSize(DxilModule &M, DxilResource &R) {
|
|
Type *Ty = R.GetHLSLType()->getPointerElementType();
|
|
if (R.IsStructuredBuffer()) {
|
|
Ty = dxilutil::StripArrayTypes(Ty);
|
|
}
|
|
return M.GetModule()->getDataLayout().getTypeAllocSize(Ty);
|
|
}
|
|
|
|
void CShaderReflectionConstantBuffer::InitializeStructuredBuffer(
|
|
DxilModule &M, DxilResource &R,
|
|
std::vector<std::unique_ptr<CShaderReflectionType>> &allTypes) {
|
|
ZeroMemory(&m_Desc, sizeof(m_Desc));
|
|
m_ReflectionName = R.GetGlobalName();
|
|
m_Desc.Type = D3D11_CT_RESOURCE_BIND_INFO;
|
|
m_Desc.uFlags = 0;
|
|
m_Desc.Variables = 1;
|
|
|
|
D3D12_SHADER_VARIABLE_DESC VarDesc;
|
|
ZeroMemory(&VarDesc, sizeof(VarDesc));
|
|
VarDesc.Name = "$Element";
|
|
VarDesc.Size = CalcResTypeSize(M, R);
|
|
VarDesc.StartTexture = UINT_MAX;
|
|
VarDesc.StartSampler = UINT_MAX;
|
|
VarDesc.uFlags |= D3D_SVF_USED;
|
|
CShaderReflectionVariable Var;
|
|
|
|
// First type is an empty type: returned if no annotation available.
|
|
CShaderReflectionType *pVarType = allTypes[0].get();
|
|
|
|
// Create reflection type, if we have the necessary annotation info
|
|
|
|
// Extract the `struct` that wraps element type of the buffer resource
|
|
Type *Ty = R.GetHLSLType()->getPointerElementType();
|
|
SmallVector<unsigned, 4> arrayDims;
|
|
Ty = dxilutil::StripArrayTypes(Ty, &arrayDims);
|
|
for (unsigned i = 0; i < arrayDims.size(); ++i) {
|
|
m_ReflectionName += "[0]";
|
|
}
|
|
m_Desc.Name = m_ReflectionName.c_str();
|
|
StructType *ST = cast<StructType>(Ty);
|
|
|
|
// Look up struct type annotation on the element type
|
|
DxilTypeSystem &typeSys = M.GetTypeSystem();
|
|
DxilStructAnnotation *annotation =
|
|
typeSys.GetStructAnnotation(cast<StructType>(ST));
|
|
|
|
// Dxil from dxbc doesn't have annotation.
|
|
if (annotation) {
|
|
// Actually create the reflection type.
|
|
pVarType = new CShaderReflectionType();
|
|
allTypes.push_back(std::unique_ptr<CShaderReflectionType>(pVarType));
|
|
|
|
// The user-visible element type is the first field of the wrapepr `struct`
|
|
Type *fieldType = ST->getElementType(0);
|
|
DxilFieldAnnotation &fieldAnnotation = annotation->GetFieldAnnotation(0);
|
|
|
|
pVarType->Initialize(M, fieldType, fieldAnnotation, 0, allTypes, false);
|
|
}
|
|
|
|
BYTE *pDefaultValue = nullptr;
|
|
Var.Initialize(this, &VarDesc, pVarType, pDefaultValue);
|
|
m_Variables.push_back(Var);
|
|
|
|
m_Desc.Size = VarDesc.Size;
|
|
}
|
|
|
|
void CShaderReflectionConstantBuffer::InitializeTBuffer(
|
|
DxilModule &M, DxilResource &R,
|
|
std::vector<std::unique_ptr<CShaderReflectionType>> &allTypes,
|
|
bool bUsageInMetadata) {
|
|
ZeroMemory(&m_Desc, sizeof(m_Desc));
|
|
m_ReflectionName = R.GetGlobalName();
|
|
m_Desc.Type = D3D11_CT_TBUFFER;
|
|
m_Desc.uFlags = 0;
|
|
|
|
Type *Ty = R.GetHLSLType()->getPointerElementType();
|
|
|
|
DxilTypeSystem &typeSys = M.GetTypeSystem();
|
|
StructType *ST = cast<StructType>(Ty);
|
|
DxilStructAnnotation *annotation =
|
|
typeSys.GetStructAnnotation(cast<StructType>(ST));
|
|
// Dxil from dxbc doesn't have annotation.
|
|
if (!annotation)
|
|
return;
|
|
|
|
m_Desc.Name = m_ReflectionName.c_str();
|
|
m_Desc.Variables = ST->getNumContainedTypes();
|
|
|
|
// If only one member, it's used if it's here.
|
|
bool bAllUsed = ST->getNumContainedTypes() < 2;
|
|
bAllUsed |= !bUsageInMetadata; // Will update in SetCBufferUsage.
|
|
|
|
for (unsigned i = 0; i < ST->getNumContainedTypes(); ++i) {
|
|
DxilFieldAnnotation &fieldAnnotation = annotation->GetFieldAnnotation(i);
|
|
|
|
D3D12_SHADER_VARIABLE_DESC VarDesc;
|
|
ZeroMemory(&VarDesc, sizeof(VarDesc));
|
|
VarDesc.uFlags =
|
|
(bAllUsed || fieldAnnotation.IsCBVarUsed()) ? D3D_SVF_USED : 0;
|
|
CShaderReflectionVariable Var;
|
|
// Create reflection type.
|
|
CShaderReflectionType *pVarType = new CShaderReflectionType();
|
|
allTypes.push_back(std::unique_ptr<CShaderReflectionType>(pVarType));
|
|
pVarType->Initialize(M, ST->getContainedType(i), fieldAnnotation,
|
|
fieldAnnotation.GetCBufferOffset(), allTypes, true);
|
|
|
|
BYTE *pDefaultValue = nullptr;
|
|
|
|
VarDesc.Name = fieldAnnotation.GetFieldName().c_str();
|
|
VarDesc.StartOffset = fieldAnnotation.GetCBufferOffset();
|
|
VarDesc.Size = pVarType->GetCBufferSize();
|
|
VarDesc.StartTexture = UINT_MAX;
|
|
VarDesc.StartSampler = UINT_MAX;
|
|
Var.Initialize(this, &VarDesc, pVarType, pDefaultValue);
|
|
m_Variables.push_back(Var);
|
|
|
|
m_Desc.Size = std::max(m_Desc.Size, VarDesc.StartOffset + VarDesc.Size);
|
|
}
|
|
m_Desc.Size =
|
|
(m_Desc.Size + 0x0f) & ~(0x0f); // Round up to 16 bytes for reflection.
|
|
}
|
|
|
|
HRESULT
|
|
CShaderReflectionConstantBuffer::GetDesc(D3D12_SHADER_BUFFER_DESC *pDesc) {
|
|
if (!pDesc)
|
|
return E_POINTER;
|
|
memcpy(pDesc, &m_Desc, sizeof(m_Desc));
|
|
return S_OK;
|
|
}
|
|
|
|
ID3D12ShaderReflectionVariable *
|
|
CShaderReflectionConstantBuffer::GetVariableByIndex(UINT Index) {
|
|
if (Index >= m_Variables.size()) {
|
|
return &g_InvalidSRVariable;
|
|
}
|
|
|
|
return &m_Variables[Index];
|
|
}
|
|
|
|
ID3D12ShaderReflectionVariable *
|
|
CShaderReflectionConstantBuffer::GetVariableByName(LPCSTR Name) {
|
|
UINT index;
|
|
|
|
if (NULL == Name) {
|
|
return &g_InvalidSRVariable;
|
|
}
|
|
|
|
for (index = 0; index < m_Variables.size(); ++index) {
|
|
if (0 == strcmp(m_Variables[index].GetName(), Name)) {
|
|
return &m_Variables[index];
|
|
}
|
|
}
|
|
|
|
return &g_InvalidSRVariable;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// DxilShaderReflection implementation. //
|
|
|
|
static DxilResource *DxilResourceFromBase(DxilResourceBase *RB) {
|
|
DxilResourceBase::Class C = RB->GetClass();
|
|
if (C == DXIL::ResourceClass::UAV || C == DXIL::ResourceClass::SRV)
|
|
return (DxilResource *)RB;
|
|
return nullptr;
|
|
}
|
|
|
|
static D3D_SHADER_INPUT_TYPE ResourceToShaderInputType(DxilResourceBase *RB) {
|
|
DxilResource *R = DxilResourceFromBase(RB);
|
|
bool isUAV = RB->GetClass() == DxilResourceBase::Class::UAV;
|
|
switch (RB->GetKind()) {
|
|
case DxilResource::Kind::CBuffer:
|
|
return D3D_SIT_CBUFFER;
|
|
case DxilResource::Kind::Sampler:
|
|
return D3D_SIT_SAMPLER;
|
|
case DxilResource::Kind::RawBuffer:
|
|
return isUAV ? D3D_SIT_UAV_RWBYTEADDRESS : D3D_SIT_BYTEADDRESS;
|
|
case DxilResource::Kind::StructuredBuffer: {
|
|
if (!isUAV)
|
|
return D3D_SIT_STRUCTURED;
|
|
// TODO: D3D_SIT_UAV_CONSUME_STRUCTURED, D3D_SIT_UAV_APPEND_STRUCTURED?
|
|
if (R->HasCounter())
|
|
return D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER;
|
|
return D3D_SIT_UAV_RWSTRUCTURED;
|
|
}
|
|
case DxilResource::Kind::TBuffer:
|
|
return D3D_SIT_TBUFFER;
|
|
case DxilResource::Kind::TypedBuffer:
|
|
case DxilResource::Kind::Texture1D:
|
|
case DxilResource::Kind::Texture1DArray:
|
|
case DxilResource::Kind::Texture2D:
|
|
case DxilResource::Kind::Texture2DArray:
|
|
case DxilResource::Kind::Texture2DMS:
|
|
case DxilResource::Kind::Texture2DMSArray:
|
|
case DxilResource::Kind::Texture3D:
|
|
case DxilResource::Kind::TextureCube:
|
|
case DxilResource::Kind::TextureCubeArray:
|
|
return isUAV ? D3D_SIT_UAV_RWTYPED : D3D_SIT_TEXTURE;
|
|
case DxilResource::Kind::RTAccelerationStructure:
|
|
return (D3D_SHADER_INPUT_TYPE)(D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER +
|
|
1); // D3D_SIT_RTACCELERATIONSTRUCTURE
|
|
case DxilResource::Kind::FeedbackTexture2D:
|
|
case DxilResource::Kind::FeedbackTexture2DArray:
|
|
return (D3D_SHADER_INPUT_TYPE)(D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER +
|
|
2); // D3D_SIT_UAV_FEEDBACKTEXTURE
|
|
default:
|
|
return (D3D_SHADER_INPUT_TYPE)-1;
|
|
}
|
|
}
|
|
|
|
static D3D_RESOURCE_RETURN_TYPE ResourceToReturnType(DxilResourceBase *RB) {
|
|
DxilResource *R = DxilResourceFromBase(RB);
|
|
if (R != nullptr && !R->IsTBuffer()) {
|
|
CompType CT = R->GetCompType();
|
|
if (CT.GetKind() == CompType::Kind::F64)
|
|
return D3D_RETURN_TYPE_DOUBLE;
|
|
if (CT.IsUNorm())
|
|
return D3D_RETURN_TYPE_UNORM;
|
|
if (CT.IsSNorm())
|
|
return D3D_RETURN_TYPE_SNORM;
|
|
if (CT.IsSIntTy())
|
|
return D3D_RETURN_TYPE_SINT;
|
|
if (CT.IsUIntTy())
|
|
return D3D_RETURN_TYPE_UINT;
|
|
if (CT.IsFloatTy())
|
|
return D3D_RETURN_TYPE_FLOAT;
|
|
|
|
// D3D_RETURN_TYPE_CONTINUED: Return type is a multiple-dword type, such as
|
|
// a double or uint64, and the component is continued from the previous
|
|
// component that was declared. The first component represents the lower
|
|
// bits.
|
|
return D3D_RETURN_TYPE_MIXED;
|
|
}
|
|
|
|
return (D3D_RESOURCE_RETURN_TYPE)0;
|
|
}
|
|
|
|
static D3D_SRV_DIMENSION ResourceToDimension(DxilResourceBase *RB) {
|
|
switch (RB->GetKind()) {
|
|
case DxilResource::Kind::StructuredBuffer:
|
|
case DxilResource::Kind::TypedBuffer:
|
|
return D3D_SRV_DIMENSION_BUFFER;
|
|
case DxilResource::Kind::TBuffer:
|
|
return D3D_SRV_DIMENSION_UNKNOWN; // Fxc returns this
|
|
case DxilResource::Kind::Texture1D:
|
|
return D3D_SRV_DIMENSION_TEXTURE1D;
|
|
case DxilResource::Kind::Texture1DArray:
|
|
return D3D_SRV_DIMENSION_TEXTURE1DARRAY;
|
|
case DxilResource::Kind::Texture2D:
|
|
case DxilResource::Kind::FeedbackTexture2D:
|
|
return D3D_SRV_DIMENSION_TEXTURE2D;
|
|
case DxilResource::Kind::Texture2DArray:
|
|
case DxilResource::Kind::FeedbackTexture2DArray:
|
|
return D3D_SRV_DIMENSION_TEXTURE2DARRAY;
|
|
case DxilResource::Kind::Texture2DMS:
|
|
return D3D_SRV_DIMENSION_TEXTURE2DMS;
|
|
case DxilResource::Kind::Texture2DMSArray:
|
|
return D3D_SRV_DIMENSION_TEXTURE2DMSARRAY;
|
|
case DxilResource::Kind::Texture3D:
|
|
return D3D_SRV_DIMENSION_TEXTURE3D;
|
|
case DxilResource::Kind::TextureCube:
|
|
return D3D_SRV_DIMENSION_TEXTURECUBE;
|
|
case DxilResource::Kind::TextureCubeArray:
|
|
return D3D_SRV_DIMENSION_TEXTURECUBEARRAY;
|
|
case DxilResource::Kind::RawBuffer:
|
|
return D3D11_SRV_DIMENSION_BUFFER; // D3D11_SRV_DIMENSION_BUFFEREX?
|
|
default:
|
|
return D3D_SRV_DIMENSION_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
static UINT ResourceToFlags(DxilResourceBase *RB) {
|
|
if (RB->GetClass() == DXIL::ResourceClass::CBuffer)
|
|
return D3D_SIF_USERPACKED;
|
|
UINT result = 0;
|
|
DxilResource *R = DxilResourceFromBase(RB);
|
|
if (R != nullptr &&
|
|
(R->IsAnyTexture() || R->GetKind() == DXIL::ResourceKind::TypedBuffer)) {
|
|
llvm::Type *RetTy = R->GetRetType();
|
|
if (VectorType *VT = dyn_cast<VectorType>(RetTy)) {
|
|
unsigned vecSize = VT->getNumElements();
|
|
switch (vecSize) {
|
|
case 4:
|
|
result |= D3D_SIF_TEXTURE_COMPONENTS;
|
|
break;
|
|
case 3:
|
|
result |= D3D_SIF_TEXTURE_COMPONENT_1;
|
|
break;
|
|
case 2:
|
|
result |= D3D_SIF_TEXTURE_COMPONENT_0;
|
|
break;
|
|
}
|
|
}
|
|
} else if (R && R->IsTBuffer()) {
|
|
return D3D_SIF_USERPACKED;
|
|
} else if (RB->GetClass() == DXIL::ResourceClass::Sampler) {
|
|
DxilSampler *S = static_cast<DxilSampler *>(RB);
|
|
if (S->GetSamplerKind() == DXIL::SamplerKind::Comparison)
|
|
result |= D3D_SIF_COMPARISON_SAMPLER;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void DxilModuleReflection::CreateReflectionObjectForResource(
|
|
DxilResourceBase *RB) {
|
|
DxilResourceBase::Class C = RB->GetClass();
|
|
DxilResource *R =
|
|
(C == DXIL::ResourceClass::UAV || C == DXIL::ResourceClass::SRV)
|
|
? (DxilResource *)RB
|
|
: nullptr;
|
|
D3D12_SHADER_INPUT_BIND_DESC inputBind;
|
|
ZeroMemory(&inputBind, sizeof(inputBind));
|
|
inputBind.BindCount = RB->GetRangeSize();
|
|
// FXC Bug: For Unbounded range, CBuffers say bind count is UINT_MAX, but all
|
|
// others report 0!
|
|
if (RB->GetRangeSize() == UINT_MAX && C != DXIL::ResourceClass::CBuffer)
|
|
inputBind.BindCount = 0;
|
|
inputBind.BindPoint = RB->GetLowerBound();
|
|
inputBind.Dimension = ResourceToDimension(RB);
|
|
inputBind.Name = RB->GetGlobalName().c_str();
|
|
inputBind.Type = ResourceToShaderInputType(RB);
|
|
if (R == nullptr) {
|
|
inputBind.NumSamples = 0;
|
|
} else {
|
|
inputBind.NumSamples = R->GetSampleCount();
|
|
if (inputBind.NumSamples == 0) {
|
|
if (R->IsStructuredBuffer()) {
|
|
inputBind.NumSamples = CalcResTypeSize(*m_pDxilModule, *R);
|
|
} else if (!R->IsRawBuffer() && !R->IsTBuffer() &&
|
|
R->GetKind() != DXIL::ResourceKind::Texture2DMS &&
|
|
R->GetKind() != DXIL::ResourceKind::Texture2DMSArray) {
|
|
inputBind.NumSamples = 0xFFFFFFFF;
|
|
}
|
|
}
|
|
}
|
|
inputBind.ReturnType = ResourceToReturnType(RB);
|
|
inputBind.Space = RB->GetSpaceID();
|
|
inputBind.uFlags = ResourceToFlags(RB);
|
|
inputBind.uID = RB->GetID();
|
|
m_Resources.push_back(inputBind);
|
|
}
|
|
|
|
// Find the imm offset part from a value.
|
|
// It must exist unless offset is 0.
|
|
static unsigned GetCBOffset(Value *V) {
|
|
if (ConstantInt *Imm = dyn_cast<ConstantInt>(V))
|
|
return Imm->getLimitedValue();
|
|
else if (isa<UnaryInstruction>(V)) {
|
|
return 0;
|
|
} else if (BinaryOperator *BO = dyn_cast<BinaryOperator>(V)) {
|
|
switch (BO->getOpcode()) {
|
|
case Instruction::Add: {
|
|
unsigned left = GetCBOffset(BO->getOperand(0));
|
|
unsigned right = GetCBOffset(BO->getOperand(1));
|
|
return left + right;
|
|
} break;
|
|
case Instruction::Or: {
|
|
unsigned left = GetCBOffset(BO->getOperand(0));
|
|
unsigned right = GetCBOffset(BO->getOperand(1));
|
|
return left | right;
|
|
} break;
|
|
default:
|
|
return 0;
|
|
}
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static unsigned GetOffsetForCBExtractValue(ExtractValueInst *EV,
|
|
bool bMinPrecision) {
|
|
DXASSERT(EV->getNumIndices() == 1,
|
|
"otherwise, unexpected indices/type for extractvalue");
|
|
unsigned typeSize = 4;
|
|
unsigned bits = EV->getType()->getScalarSizeInBits();
|
|
if (bits == 64)
|
|
typeSize = 8;
|
|
else if (bits == 16 && !bMinPrecision)
|
|
typeSize = 2;
|
|
return (EV->getIndices().front() * typeSize);
|
|
}
|
|
|
|
static void CollectInPhiChain(PHINode *cbUser, std::vector<unsigned> &cbufUsage,
|
|
unsigned offset,
|
|
std::unordered_set<Value *> &userSet,
|
|
bool bMinPrecision) {
|
|
if (userSet.count(cbUser) > 0)
|
|
return;
|
|
|
|
userSet.insert(cbUser);
|
|
for (User *cbU : cbUser->users()) {
|
|
if (ExtractValueInst *EV = dyn_cast<ExtractValueInst>(cbU)) {
|
|
cbufUsage.emplace_back(offset +
|
|
GetOffsetForCBExtractValue(EV, bMinPrecision));
|
|
} else {
|
|
PHINode *phi = cast<PHINode>(cbU);
|
|
CollectInPhiChain(phi, cbufUsage, offset, userSet, bMinPrecision);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void CollectCBufUsage(Value *cbHandle, std::vector<unsigned> &cbufUsage,
|
|
bool bMinPrecision) {
|
|
for (User *U : cbHandle->users()) {
|
|
CallInst *CI = cast<CallInst>(U);
|
|
ConstantInt *opcodeV =
|
|
cast<ConstantInt>(CI->getArgOperand(DXIL::OperandIndex::kOpcodeIdx));
|
|
DXIL::OpCode opcode = static_cast<DXIL::OpCode>(opcodeV->getLimitedValue());
|
|
if (opcode == DXIL::OpCode::CBufferLoadLegacy) {
|
|
DxilInst_CBufferLoadLegacy cbload(CI);
|
|
Value *resIndex = cbload.get_regIndex();
|
|
unsigned offset = GetCBOffset(resIndex);
|
|
// 16 bytes align.
|
|
offset <<= 4;
|
|
for (User *cbU : U->users()) {
|
|
if (ExtractValueInst *EV = dyn_cast<ExtractValueInst>(cbU)) {
|
|
cbufUsage.emplace_back(offset +
|
|
GetOffsetForCBExtractValue(EV, bMinPrecision));
|
|
} else {
|
|
PHINode *phi = cast<PHINode>(cbU);
|
|
std::unordered_set<Value *> userSet;
|
|
CollectInPhiChain(phi, cbufUsage, offset, userSet, bMinPrecision);
|
|
}
|
|
}
|
|
} else if (opcode == DXIL::OpCode::CBufferLoad) {
|
|
DxilInst_CBufferLoad cbload(CI);
|
|
Value *byteOffset = cbload.get_byteOffset();
|
|
unsigned offset = GetCBOffset(byteOffset);
|
|
cbufUsage.emplace_back(offset);
|
|
} else if (opcode == DXIL::OpCode::AnnotateHandle) {
|
|
DxilInst_AnnotateHandle annotateHandle(CI);
|
|
Value *annotatedHandle = annotateHandle.get_res();
|
|
CollectCBufUsage(annotatedHandle, cbufUsage, bMinPrecision);
|
|
} else {
|
|
//
|
|
DXASSERT(0, "invalid opcode");
|
|
}
|
|
}
|
|
}
|
|
|
|
static void SetCBufVarUsage(CShaderReflectionConstantBuffer &cb,
|
|
std::vector<unsigned> &usage) {
|
|
D3D12_SHADER_BUFFER_DESC Desc;
|
|
if (FAILED(cb.GetDesc(&Desc)))
|
|
return;
|
|
|
|
unsigned size = Desc.Variables;
|
|
|
|
std::sort(usage.begin(), usage.end());
|
|
for (unsigned i = 0; i < size; i++) {
|
|
ID3D12ShaderReflectionVariable *pVar = cb.GetVariableByIndex(i);
|
|
D3D12_SHADER_VARIABLE_DESC VarDesc;
|
|
if (FAILED(pVar->GetDesc(&VarDesc)))
|
|
continue;
|
|
if (!pVar)
|
|
continue;
|
|
|
|
unsigned begin = VarDesc.StartOffset;
|
|
unsigned end = begin + VarDesc.Size;
|
|
auto beginIt = std::find_if(usage.begin(), usage.end(),
|
|
[&](unsigned v) { return v >= begin; });
|
|
auto endIt = std::find_if(usage.begin(), usage.end(),
|
|
[&](unsigned v) { return v >= end; });
|
|
|
|
bool used = beginIt != endIt;
|
|
// Clear used.
|
|
if (!used) {
|
|
CShaderReflectionType *pVarType =
|
|
(CShaderReflectionType *)pVar->GetType();
|
|
BYTE *pDefaultValue = nullptr;
|
|
|
|
VarDesc.uFlags &= ~D3D_SVF_USED;
|
|
CShaderReflectionVariable *pCVarDesc = (CShaderReflectionVariable *)pVar;
|
|
pCVarDesc->Initialize(&cb, &VarDesc, pVarType, pDefaultValue);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DxilShaderReflection::SetCBufferUsage() {
|
|
hlsl::OP *hlslOP = m_pDxilModule->GetOP();
|
|
LLVMContext &Ctx = m_pDxilModule->GetCtx();
|
|
|
|
// Indexes >= cbuffer size from DxilModule are SRV or UAV structured buffers.
|
|
// We only collect usage for actual cbuffers, so don't go clearing usage on
|
|
// other buffers.
|
|
unsigned cbSize = std::min(m_CBs.size(), m_pDxilModule->GetCBuffers().size());
|
|
std::vector<std::vector<unsigned>> cbufUsage(cbSize);
|
|
|
|
Function *createHandle =
|
|
hlslOP->GetOpFunc(DXIL::OpCode::CreateHandle, Type::getVoidTy(Ctx));
|
|
|
|
if (createHandle->user_empty()) {
|
|
createHandle->eraseFromParent();
|
|
return;
|
|
}
|
|
|
|
// Find all cb handles.
|
|
for (User *U : createHandle->users()) {
|
|
DxilInst_CreateHandle handle(cast<CallInst>(U));
|
|
Value *resClass = handle.get_resourceClass();
|
|
ConstantInt *immResClass = cast<ConstantInt>(resClass);
|
|
if (immResClass->getLimitedValue() ==
|
|
(unsigned)DXIL::ResourceClass::CBuffer) {
|
|
ConstantInt *cbID = cast<ConstantInt>(handle.get_rangeId());
|
|
CollectCBufUsage(U, cbufUsage[cbID->getLimitedValue()],
|
|
m_pDxilModule->GetUseMinPrecision());
|
|
}
|
|
}
|
|
|
|
for (unsigned i = 0; i < cbSize; i++) {
|
|
SetCBufVarUsage(*m_CBs[i], cbufUsage[i]);
|
|
}
|
|
}
|
|
|
|
void DxilModuleReflection::CreateReflectionObjects() {
|
|
DXASSERT_NOMSG(m_pDxilModule != nullptr);
|
|
|
|
{
|
|
// Add empty type for when no type info is available, instead of returning
|
|
// nullptr.
|
|
DXASSERT_NOMSG(m_Types.empty());
|
|
CShaderReflectionType *pEmptyType = new CShaderReflectionType();
|
|
m_Types.push_back(std::unique_ptr<CShaderReflectionType>(pEmptyType));
|
|
pEmptyType->InitializeEmpty();
|
|
}
|
|
|
|
// Create constant buffers, resources and signatures.
|
|
for (auto &&cb : m_pDxilModule->GetCBuffers()) {
|
|
std::unique_ptr<CShaderReflectionConstantBuffer> rcb(
|
|
new CShaderReflectionConstantBuffer());
|
|
rcb->Initialize(*m_pDxilModule, *(cb.get()), m_Types, m_bUsageInMetadata);
|
|
m_CBsByName[rcb->GetName()] = (UINT)m_CBs.size();
|
|
m_CBs.emplace_back(std::move(rcb));
|
|
}
|
|
|
|
// TODO: add tbuffers into m_CBs
|
|
for (auto &&uav : m_pDxilModule->GetUAVs()) {
|
|
if (!DXIL::IsStructuredBuffer(uav->GetKind())) {
|
|
continue;
|
|
}
|
|
std::unique_ptr<CShaderReflectionConstantBuffer> rcb(
|
|
new CShaderReflectionConstantBuffer());
|
|
rcb->InitializeStructuredBuffer(*m_pDxilModule, *(uav.get()), m_Types);
|
|
m_StructuredBufferCBsByName[rcb->GetName()] = (UINT)m_CBs.size();
|
|
m_CBs.emplace_back(std::move(rcb));
|
|
}
|
|
for (auto &&srv : m_pDxilModule->GetSRVs()) {
|
|
if (srv->GetKind() != DxilResource::Kind::StructuredBuffer &&
|
|
srv->GetKind() != DxilResource::Kind::TBuffer) {
|
|
continue;
|
|
}
|
|
std::unique_ptr<CShaderReflectionConstantBuffer> rcb(
|
|
new CShaderReflectionConstantBuffer());
|
|
if (srv->GetKind() == DxilResource::Kind::TBuffer) {
|
|
rcb->InitializeTBuffer(*m_pDxilModule, *(srv.get()), m_Types,
|
|
m_bUsageInMetadata);
|
|
m_CBsByName[rcb->GetName()] = (UINT)m_CBs.size();
|
|
} else {
|
|
rcb->InitializeStructuredBuffer(*m_pDxilModule, *(srv.get()), m_Types);
|
|
m_StructuredBufferCBsByName[rcb->GetName()] = (UINT)m_CBs.size();
|
|
}
|
|
m_CBs.emplace_back(std::move(rcb));
|
|
}
|
|
|
|
// Populate all resources.
|
|
for (auto &&cbRes : m_pDxilModule->GetCBuffers()) {
|
|
CreateReflectionObjectForResource(cbRes.get());
|
|
}
|
|
for (auto &&samplerRes : m_pDxilModule->GetSamplers()) {
|
|
CreateReflectionObjectForResource(samplerRes.get());
|
|
}
|
|
for (auto &&srvRes : m_pDxilModule->GetSRVs()) {
|
|
CreateReflectionObjectForResource(srvRes.get());
|
|
}
|
|
for (auto &&uavRes : m_pDxilModule->GetUAVs()) {
|
|
CreateReflectionObjectForResource(uavRes.get());
|
|
}
|
|
}
|
|
|
|
static D3D_REGISTER_COMPONENT_TYPE
|
|
CompTypeToRegisterComponentType(CompType CT) {
|
|
switch (CT.GetKind()) {
|
|
case DXIL::ComponentType::F16:
|
|
case DXIL::ComponentType::F32:
|
|
return D3D_REGISTER_COMPONENT_FLOAT32;
|
|
case DXIL::ComponentType::I1:
|
|
case DXIL::ComponentType::U16:
|
|
case DXIL::ComponentType::U32:
|
|
return D3D_REGISTER_COMPONENT_UINT32;
|
|
case DXIL::ComponentType::I16:
|
|
case DXIL::ComponentType::I32:
|
|
return D3D_REGISTER_COMPONENT_SINT32;
|
|
default:
|
|
return D3D_REGISTER_COMPONENT_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
static D3D_MIN_PRECISION CompTypeToMinPrecision(CompType CT) {
|
|
switch (CT.GetKind()) {
|
|
case DXIL::ComponentType::F16:
|
|
return D3D_MIN_PRECISION_FLOAT_16;
|
|
case DXIL::ComponentType::I16:
|
|
return D3D_MIN_PRECISION_SINT_16;
|
|
case DXIL::ComponentType::U16:
|
|
return D3D_MIN_PRECISION_UINT_16;
|
|
default:
|
|
return D3D_MIN_PRECISION_DEFAULT;
|
|
}
|
|
}
|
|
|
|
D3D_NAME SemanticToSystemValueType(const Semantic *S,
|
|
DXIL::TessellatorDomain domain) {
|
|
switch (S->GetKind()) {
|
|
case Semantic::Kind::ClipDistance:
|
|
return D3D_NAME_CLIP_DISTANCE;
|
|
case Semantic::Kind::Arbitrary:
|
|
return D3D_NAME_UNDEFINED;
|
|
case Semantic::Kind::VertexID:
|
|
return D3D_NAME_VERTEX_ID;
|
|
case Semantic::Kind::InstanceID:
|
|
return D3D_NAME_INSTANCE_ID;
|
|
case Semantic::Kind::Position:
|
|
return D3D_NAME_POSITION;
|
|
case Semantic::Kind::Coverage:
|
|
return D3D_NAME_COVERAGE;
|
|
case Semantic::Kind::InnerCoverage:
|
|
return D3D_NAME_INNER_COVERAGE;
|
|
case Semantic::Kind::PrimitiveID:
|
|
return D3D_NAME_PRIMITIVE_ID;
|
|
case Semantic::Kind::SampleIndex:
|
|
return D3D_NAME_SAMPLE_INDEX;
|
|
case Semantic::Kind::IsFrontFace:
|
|
return D3D_NAME_IS_FRONT_FACE;
|
|
case Semantic::Kind::RenderTargetArrayIndex:
|
|
return D3D_NAME_RENDER_TARGET_ARRAY_INDEX;
|
|
case Semantic::Kind::ViewPortArrayIndex:
|
|
return D3D_NAME_VIEWPORT_ARRAY_INDEX;
|
|
case Semantic::Kind::CullDistance:
|
|
return D3D_NAME_CULL_DISTANCE;
|
|
case Semantic::Kind::Target:
|
|
return D3D_NAME_TARGET;
|
|
case Semantic::Kind::Depth:
|
|
return D3D_NAME_DEPTH;
|
|
case Semantic::Kind::DepthLessEqual:
|
|
return D3D_NAME_DEPTH_LESS_EQUAL;
|
|
case Semantic::Kind::DepthGreaterEqual:
|
|
return D3D_NAME_DEPTH_GREATER_EQUAL;
|
|
case Semantic::Kind::StencilRef:
|
|
return D3D_NAME_STENCIL_REF;
|
|
case Semantic::Kind::TessFactor: {
|
|
switch (domain) {
|
|
case DXIL::TessellatorDomain::IsoLine:
|
|
return D3D_NAME_FINAL_LINE_DETAIL_TESSFACTOR;
|
|
case DXIL::TessellatorDomain::Tri:
|
|
return D3D_NAME_FINAL_TRI_EDGE_TESSFACTOR;
|
|
case DXIL::TessellatorDomain::Quad:
|
|
return D3D_NAME_FINAL_QUAD_EDGE_TESSFACTOR;
|
|
default:
|
|
return D3D_NAME_UNDEFINED;
|
|
}
|
|
case Semantic::Kind::Barycentrics:
|
|
return (D3D_NAME)DxilProgramSigSemantic::Barycentrics;
|
|
case Semantic::Kind::ShadingRate:
|
|
return (D3D_NAME)DxilProgramSigSemantic::ShadingRate;
|
|
case Semantic::Kind::CullPrimitive:
|
|
return (D3D_NAME)DxilProgramSigSemantic::CullPrimitive;
|
|
}
|
|
case Semantic::Kind::InsideTessFactor:
|
|
switch (domain) {
|
|
case DXIL::TessellatorDomain::Tri:
|
|
return D3D_NAME_FINAL_TRI_INSIDE_TESSFACTOR;
|
|
case DXIL::TessellatorDomain::Quad:
|
|
return D3D_NAME_FINAL_QUAD_INSIDE_TESSFACTOR;
|
|
default:
|
|
return D3D_NAME_UNDEFINED;
|
|
}
|
|
case Semantic::Kind::DispatchThreadID:
|
|
case Semantic::Kind::GroupID:
|
|
case Semantic::Kind::GroupIndex:
|
|
case Semantic::Kind::GroupThreadID:
|
|
case Semantic::Kind::DomainLocation:
|
|
case Semantic::Kind::OutputControlPointID:
|
|
case Semantic::Kind::GSInstanceID:
|
|
case Semantic::Kind::Invalid:
|
|
default:
|
|
return D3D_NAME_UNDEFINED;
|
|
}
|
|
}
|
|
|
|
static uint8_t NegMask(uint8_t V) {
|
|
V ^= 0xF;
|
|
return V & 0xF;
|
|
}
|
|
|
|
void DxilShaderReflection::CreateReflectionObjectsForSignature(
|
|
const DxilSignature &Sig,
|
|
std::vector<D3D12_SIGNATURE_PARAMETER_DESC> &Descs) {
|
|
for (auto &&SigElem : Sig.GetElements()) {
|
|
D3D12_SIGNATURE_PARAMETER_DESC Desc;
|
|
Desc.ComponentType =
|
|
CompTypeToRegisterComponentType(SigElem->GetCompType());
|
|
Desc.Mask = SigElem->GetColsAsMask();
|
|
Desc.MinPrecision = CompTypeToMinPrecision(SigElem->GetCompType());
|
|
if (m_bUsageInMetadata) {
|
|
unsigned UsageMask = SigElem->GetUsageMask();
|
|
if (SigElem->IsAllocated())
|
|
UsageMask <<= SigElem->GetStartCol();
|
|
Desc.ReadWriteMask = Sig.IsInput() ? UsageMask : NegMask(UsageMask);
|
|
} else {
|
|
Desc.ReadWriteMask =
|
|
Sig.IsInput()
|
|
? 0
|
|
: Desc.Mask; // Start with output-never-written/input-never-read.
|
|
}
|
|
Desc.Register = SigElem->GetStartRow();
|
|
Desc.Stream = SigElem->GetOutputStream();
|
|
Desc.SystemValueType = SemanticToSystemValueType(
|
|
SigElem->GetSemantic(), m_pDxilModule->GetTessellatorDomain());
|
|
Desc.SemanticName = SigElem->GetName();
|
|
if (!SigElem->GetSemantic()->IsArbitrary())
|
|
Desc.SemanticName = CreateUpperCase(Desc.SemanticName);
|
|
|
|
const std::vector<unsigned> &indexVec = SigElem->GetSemanticIndexVec();
|
|
for (unsigned semIdx = 0; semIdx < indexVec.size(); ++semIdx) {
|
|
Desc.SemanticIndex = indexVec[semIdx];
|
|
if (Desc.SystemValueType == D3D_NAME_FINAL_LINE_DETAIL_TESSFACTOR &&
|
|
Desc.SemanticIndex == 1)
|
|
Desc.SystemValueType = D3D_NAME_FINAL_LINE_DETAIL_TESSFACTOR;
|
|
Descs.push_back(Desc);
|
|
// When indexVec.size() > 1, subsequent indices need incremented register
|
|
// index
|
|
Desc.Register += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
LPCSTR DxilShaderReflection::CreateUpperCase(LPCSTR pValue) {
|
|
// Restricted only to [a-z] ASCII.
|
|
LPCSTR pCursor = pValue;
|
|
while (*pCursor != '\0') {
|
|
if ('a' <= *pCursor && *pCursor <= 'z') {
|
|
break;
|
|
}
|
|
++pCursor;
|
|
}
|
|
if (*pCursor == '\0')
|
|
return pValue;
|
|
|
|
std::unique_ptr<char[]> pUpperStr =
|
|
llvm::make_unique<char[]>(strlen(pValue) + 1);
|
|
char *pWrite = pUpperStr.get();
|
|
pCursor = pValue;
|
|
for (;;) {
|
|
*pWrite = *pCursor;
|
|
if ('a' <= *pWrite && *pWrite <= 'z') {
|
|
*pWrite += ('A' - 'a');
|
|
}
|
|
if (*pWrite == '\0')
|
|
break;
|
|
++pWrite;
|
|
++pCursor;
|
|
}
|
|
m_UpperCaseNames.push_back(std::move(pUpperStr));
|
|
return m_UpperCaseNames.back().get();
|
|
}
|
|
|
|
HRESULT DxilModuleReflection::LoadRDAT(const DxilPartHeader *pPart) {
|
|
if (pPart) {
|
|
IFRBOOL(m_RDAT.InitFromRDAT(GetDxilPartData(pPart), pPart->PartSize),
|
|
DXC_E_CONTAINER_INVALID);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT DxilModuleReflection::LoadProgramHeader(
|
|
const DxilProgramHeader *pProgramHeader) {
|
|
try {
|
|
const char *pBitcode;
|
|
uint32_t bitcodeLength;
|
|
GetDxilProgramBitcode((const DxilProgramHeader *)pProgramHeader, &pBitcode,
|
|
&bitcodeLength);
|
|
std::unique_ptr<MemoryBuffer> pMemBuffer =
|
|
MemoryBuffer::getMemBufferCopy(StringRef(pBitcode, bitcodeLength));
|
|
bool bBitcodeLoadError = false;
|
|
auto errorHandler = [&bBitcodeLoadError](const DiagnosticInfo &diagInfo) {
|
|
bBitcodeLoadError |= diagInfo.getSeverity() == DS_Error;
|
|
};
|
|
#if 0 // We materialize eagerly, because we'll need to walk instructions to look
|
|
// for usage information.
|
|
ErrorOr<std::unique_ptr<Module>> mod =
|
|
getLazyBitcodeModule(std::move(pMemBuffer), Context, errorHandler);
|
|
#else
|
|
ErrorOr<std::unique_ptr<Module>> mod =
|
|
parseBitcodeFile(pMemBuffer->getMemBufferRef(), Context, errorHandler);
|
|
#endif
|
|
if (!mod || bBitcodeLoadError) {
|
|
return E_INVALIDARG;
|
|
}
|
|
std::swap(m_pModule, mod.get());
|
|
m_pDxilModule = &m_pModule->GetOrCreateDxilModule();
|
|
|
|
unsigned ValMajor, ValMinor;
|
|
m_pDxilModule->GetValidatorVersion(ValMajor, ValMinor);
|
|
m_bUsageInMetadata =
|
|
hlsl::DXIL::CompareVersions(ValMajor, ValMinor, 1, 5) >= 0;
|
|
|
|
CreateReflectionObjects();
|
|
return S_OK;
|
|
}
|
|
CATCH_CPP_RETURN_HRESULT();
|
|
}
|
|
|
|
HRESULT DxilShaderReflection::Load(const DxilProgramHeader *pProgramHeader,
|
|
const DxilPartHeader *pRDATPart) {
|
|
IFR(LoadRDAT(pRDATPart));
|
|
IFR(LoadProgramHeader(pProgramHeader));
|
|
|
|
try {
|
|
// Set cbuf usage.
|
|
if (!m_bUsageInMetadata)
|
|
SetCBufferUsage();
|
|
|
|
// Populate input/output/patch constant signatures.
|
|
CreateReflectionObjectsForSignature(m_pDxilModule->GetInputSignature(),
|
|
m_InputSignature);
|
|
CreateReflectionObjectsForSignature(m_pDxilModule->GetOutputSignature(),
|
|
m_OutputSignature);
|
|
CreateReflectionObjectsForSignature(
|
|
m_pDxilModule->GetPatchConstOrPrimSignature(),
|
|
m_PatchConstantSignature);
|
|
if (!m_bUsageInMetadata)
|
|
MarkUsedSignatureElements();
|
|
|
|
InitDesc();
|
|
|
|
return S_OK;
|
|
}
|
|
CATCH_CPP_RETURN_HRESULT();
|
|
}
|
|
|
|
HRESULT
|
|
DxilShaderReflection::GetDesc(D3D12_SHADER_DESC *pDesc) noexcept {
|
|
if (nullptr == pDesc)
|
|
return E_POINTER;
|
|
memcpy(pDesc, &m_Desc, sizeof(D3D12_SHADER_DESC));
|
|
return S_OK;
|
|
}
|
|
|
|
static bool GetUnsignedVal(Value *V, uint32_t *pValue) {
|
|
ConstantInt *CI = dyn_cast<ConstantInt>(V);
|
|
if (!CI)
|
|
return false;
|
|
uint64_t u = CI->getZExtValue();
|
|
if (u > UINT32_MAX)
|
|
return false;
|
|
*pValue = (uint32_t)u;
|
|
return true;
|
|
}
|
|
|
|
void DxilShaderReflection::MarkUsedSignatureElements() {
|
|
Function *F = m_pDxilModule->GetEntryFunction();
|
|
if (F == nullptr) {
|
|
F = m_pDxilModule->GetPatchConstantFunction();
|
|
}
|
|
DXASSERT(F != nullptr, "else module load should have failed");
|
|
// For every loadInput/storeOutput, update the corresponding ReadWriteMask.
|
|
// F is a pointer to a Function instance
|
|
unsigned elementCount = m_InputSignature.size() + m_OutputSignature.size() +
|
|
m_PatchConstantSignature.size();
|
|
unsigned markedElementCount = 0;
|
|
for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
|
|
DxilInst_LoadInput LI(&*I);
|
|
DxilInst_StoreOutput SO(&*I);
|
|
DxilInst_LoadPatchConstant LPC(&*I);
|
|
DxilInst_StorePatchConstant SPC(&*I);
|
|
DxilInst_StoreVertexOutput SVO(&*I);
|
|
DxilInst_StorePrimitiveOutput SPO(&*I);
|
|
std::vector<D3D12_SIGNATURE_PARAMETER_DESC> *pDescs = nullptr;
|
|
const DxilSignature *pSig;
|
|
uint32_t col, row, sigId;
|
|
if (LI) {
|
|
if (!GetUnsignedVal(LI.get_inputSigId(), &sigId))
|
|
continue;
|
|
if (!GetUnsignedVal(LI.get_colIndex(), &col))
|
|
continue;
|
|
GetUnsignedVal(LI.get_rowIndex(), &row);
|
|
pDescs = &m_InputSignature;
|
|
pSig = &m_pDxilModule->GetInputSignature();
|
|
} else if (SO) {
|
|
if (!GetUnsignedVal(SO.get_outputSigId(), &sigId))
|
|
continue;
|
|
if (!GetUnsignedVal(SO.get_colIndex(), &col))
|
|
continue;
|
|
GetUnsignedVal(SO.get_rowIndex(), &row);
|
|
pDescs = &m_OutputSignature;
|
|
pSig = &m_pDxilModule->GetOutputSignature();
|
|
} else if (SPC) {
|
|
if (!GetUnsignedVal(SPC.get_outputSigID(), &sigId))
|
|
continue;
|
|
if (!GetUnsignedVal(SPC.get_col(), &col))
|
|
continue;
|
|
GetUnsignedVal(SPC.get_row(), &row);
|
|
pDescs = &m_PatchConstantSignature;
|
|
pSig = &m_pDxilModule->GetPatchConstOrPrimSignature();
|
|
} else if (LPC) {
|
|
if (!GetUnsignedVal(LPC.get_inputSigId(), &sigId))
|
|
continue;
|
|
if (!GetUnsignedVal(LPC.get_col(), &col))
|
|
continue;
|
|
GetUnsignedVal(LPC.get_row(), &row);
|
|
pDescs = &m_PatchConstantSignature;
|
|
pSig = &m_pDxilModule->GetPatchConstOrPrimSignature();
|
|
} else if (SVO) {
|
|
if (!GetUnsignedVal(SVO.get_outputSigId(), &sigId))
|
|
continue;
|
|
if (!GetUnsignedVal(SVO.get_colIndex(), &col))
|
|
continue;
|
|
GetUnsignedVal(SVO.get_rowIndex(), &row);
|
|
pSig = &m_pDxilModule->GetOutputSignature();
|
|
} else if (SPO) {
|
|
if (!GetUnsignedVal(SPO.get_outputSigId(), &sigId))
|
|
continue;
|
|
if (!GetUnsignedVal(SPO.get_colIndex(), &col))
|
|
continue;
|
|
GetUnsignedVal(SPO.get_rowIndex(), &row);
|
|
pSig = &m_pDxilModule->GetPatchConstOrPrimSignature();
|
|
} else {
|
|
continue;
|
|
}
|
|
|
|
if (sigId >= pDescs->size())
|
|
continue;
|
|
|
|
D3D12_SIGNATURE_PARAMETER_DESC *pDesc = &(*pDescs)[sigId];
|
|
// Consider being more fine-grained about masks.
|
|
// We report sometimes-read on input as always-read.
|
|
unsigned UsedMask = pSig->IsInput() ? pDesc->Mask : NegMask(pDesc->Mask);
|
|
if (pDesc->ReadWriteMask == UsedMask)
|
|
continue;
|
|
pDesc->ReadWriteMask = UsedMask;
|
|
++markedElementCount;
|
|
if (markedElementCount == elementCount)
|
|
return;
|
|
}
|
|
}
|
|
|
|
void DxilShaderReflection::InitDesc() {
|
|
D3D12_SHADER_DESC *pDesc = &m_Desc;
|
|
|
|
const DxilModule &M = *m_pDxilModule;
|
|
const ShaderModel *pSM = M.GetShaderModel();
|
|
|
|
pDesc->Version =
|
|
EncodeVersion(pSM->GetKind(), pSM->GetMajor(), pSM->GetMinor());
|
|
|
|
Module *pModule = M.GetModule();
|
|
if (NamedMDNode *pIdentMD = pModule->getNamedMetadata("llvm.ident")) {
|
|
if (pIdentMD->getNumOperands()) {
|
|
if (MDNode *pMDList = pIdentMD->getOperand(0)) {
|
|
if (pMDList->getNumOperands()) {
|
|
if (MDString *pMDString =
|
|
dyn_cast_or_null<MDString>(pMDList->getOperand(0))) {
|
|
pDesc->Creator = pMDString->getString().data();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Unset: UINT Flags; // Shader
|
|
// compilation/parse flags
|
|
|
|
pDesc->ConstantBuffers = m_CBs.size();
|
|
pDesc->BoundResources = m_Resources.size();
|
|
pDesc->InputParameters = m_InputSignature.size();
|
|
pDesc->OutputParameters = m_OutputSignature.size();
|
|
pDesc->PatchConstantParameters = m_PatchConstantSignature.size();
|
|
|
|
pDesc->GSOutputTopology =
|
|
(D3D_PRIMITIVE_TOPOLOGY)M.GetStreamPrimitiveTopology();
|
|
pDesc->GSMaxOutputVertexCount = M.GetMaxVertexCount();
|
|
|
|
if (pSM->IsHS())
|
|
pDesc->InputPrimitive =
|
|
(D3D_PRIMITIVE)(D3D_PRIMITIVE_1_CONTROL_POINT_PATCH +
|
|
M.GetInputControlPointCount() - 1);
|
|
else
|
|
pDesc->InputPrimitive = (D3D_PRIMITIVE)M.GetInputPrimitive();
|
|
|
|
pDesc->cGSInstanceCount = M.GetGSInstanceCount();
|
|
|
|
if (pSM->IsHS())
|
|
pDesc->cControlPoints = M.GetOutputControlPointCount();
|
|
else if (pSM->IsDS())
|
|
pDesc->cControlPoints = M.GetInputControlPointCount();
|
|
|
|
pDesc->HSOutputPrimitive =
|
|
(D3D_TESSELLATOR_OUTPUT_PRIMITIVE)M.GetTessellatorOutputPrimitive();
|
|
pDesc->HSPartitioning =
|
|
(D3D_TESSELLATOR_PARTITIONING)M.GetTessellatorPartitioning();
|
|
pDesc->TessellatorDomain = (D3D_TESSELLATOR_DOMAIN)M.GetTessellatorDomain();
|
|
|
|
// Instruction counts only roughly track some fxc counters
|
|
DxilCounters counters = {};
|
|
m_pDxilModule->LoadDxilCounters(counters);
|
|
|
|
// UINT InstructionCount; // Num llvm instructions in all functions
|
|
// UINT TempArrayCount; // Number of bytes used in arrays (alloca + static
|
|
// global)
|
|
// UINT DynamicFlowControlCount; // Number of branches with more than one
|
|
// successor for now
|
|
// UINT ArrayInstructionCount; // number of load/store on arrays for now
|
|
pDesc->InstructionCount = counters.insts;
|
|
pDesc->TempArrayCount = counters.AllArrayBytes();
|
|
pDesc->DynamicFlowControlCount = counters.branches;
|
|
pDesc->ArrayInstructionCount = counters.AllArrayAccesses();
|
|
|
|
// UINT FloatInstructionCount; // Number of floating point arithmetic
|
|
// instructions used
|
|
// UINT IntInstructionCount; // Number of signed integer arithmetic
|
|
// instructions used
|
|
// UINT UintInstructionCount; // Number of unsigned integer arithmetic
|
|
// instructions used
|
|
pDesc->FloatInstructionCount = counters.floats;
|
|
pDesc->IntInstructionCount = counters.ints;
|
|
pDesc->UintInstructionCount = counters.uints;
|
|
|
|
// UINT TextureNormalInstructions; // Number of non-categorized texture
|
|
// instructions
|
|
// UINT TextureLoadInstructions; // Number of texture load
|
|
// instructions
|
|
// UINT TextureCompInstructions; // Number of texture
|
|
// comparison instructions
|
|
// UINT TextureBiasInstructions; // Number of
|
|
// texture bias instructions
|
|
// UINT TextureGradientInstructions; // Number of
|
|
// texture gradient instructions
|
|
pDesc->TextureNormalInstructions = counters.tex_norm;
|
|
pDesc->TextureLoadInstructions = counters.tex_load;
|
|
pDesc->TextureCompInstructions = counters.tex_cmp;
|
|
pDesc->TextureBiasInstructions = counters.tex_bias;
|
|
pDesc->TextureGradientInstructions = counters.tex_grad;
|
|
|
|
// UINT CutInstructionCount; // Number of cut instructions used
|
|
// UINT EmitInstructionCount; // Number of emit instructions used
|
|
pDesc->CutInstructionCount = counters.gs_cut;
|
|
pDesc->EmitInstructionCount = counters.gs_emit;
|
|
|
|
// UINT cBarrierInstructions; // Number of barrier instructions in a
|
|
// compute shader
|
|
// UINT cInterlockedInstructions; // Number of
|
|
// interlocked instructions
|
|
// UINT cTextureStoreInstructions; // Number of
|
|
// texture writes
|
|
pDesc->cBarrierInstructions = counters.barrier;
|
|
pDesc->cInterlockedInstructions = counters.atomic;
|
|
pDesc->cTextureStoreInstructions = counters.tex_store;
|
|
|
|
// Unset: UINT TempRegisterCount; // Don't know how to map this for SSA (not
|
|
// going to do reg allocation here)
|
|
// Unset: UINT DefCount; // Not sure what to map this to
|
|
// Unset: UINT DclCount; // Number of declarations (input + output)
|
|
// TODO: map to used input + output signature rows?
|
|
// Unset: UINT StaticFlowControlCount; // Number of static flow control
|
|
// instructions used This used to map to flow control using special
|
|
// int/bool constant registers in DX9.
|
|
// Unset: UINT MacroInstructionCount; // Number of macro instructions used
|
|
// Macro instructions are a <= DX9 concept.
|
|
}
|
|
|
|
ID3D12ShaderReflectionConstantBuffer *
|
|
DxilShaderReflection::GetConstantBufferByIndex(UINT Index) noexcept {
|
|
return DxilModuleReflection::_GetConstantBufferByIndex(Index);
|
|
}
|
|
ID3D12ShaderReflectionConstantBuffer *
|
|
DxilModuleReflection::_GetConstantBufferByIndex(UINT Index) {
|
|
if (Index >= m_CBs.size()) {
|
|
return &g_InvalidSRConstantBuffer;
|
|
}
|
|
return m_CBs[Index].get();
|
|
}
|
|
|
|
ID3D12ShaderReflectionConstantBuffer *
|
|
DxilShaderReflection::GetConstantBufferByName(LPCSTR Name) noexcept {
|
|
return DxilModuleReflection::_GetConstantBufferByName(Name);
|
|
}
|
|
ID3D12ShaderReflectionConstantBuffer *
|
|
DxilModuleReflection::_GetConstantBufferByName(LPCSTR Name) {
|
|
if (!Name) {
|
|
return &g_InvalidSRConstantBuffer;
|
|
}
|
|
|
|
size_t index = m_CBs.size();
|
|
auto it = m_CBsByName.find(Name);
|
|
if (it != m_CBsByName.end()) {
|
|
index = it->second;
|
|
} else {
|
|
it = m_StructuredBufferCBsByName.find(Name);
|
|
if (it != m_StructuredBufferCBsByName.end()) {
|
|
index = it->second;
|
|
}
|
|
}
|
|
if (index < m_CBs.size()) {
|
|
return m_CBs[index].get();
|
|
}
|
|
|
|
return &g_InvalidSRConstantBuffer;
|
|
}
|
|
|
|
HRESULT DxilShaderReflection::GetResourceBindingDesc(
|
|
UINT ResourceIndex, D3D12_SHADER_INPUT_BIND_DESC *pDesc) noexcept {
|
|
return DxilModuleReflection::_GetResourceBindingDesc(ResourceIndex, pDesc,
|
|
m_PublicAPI);
|
|
}
|
|
HRESULT DxilModuleReflection::_GetResourceBindingDesc(
|
|
UINT ResourceIndex, D3D12_SHADER_INPUT_BIND_DESC *pDesc, PublicAPI api) {
|
|
IFRBOOL(pDesc != nullptr, E_INVALIDARG);
|
|
IFRBOOL(ResourceIndex < m_Resources.size(), E_INVALIDARG);
|
|
if (api != PublicAPI::D3D12) {
|
|
memcpy(pDesc, &m_Resources[ResourceIndex],
|
|
sizeof(D3D11_SHADER_INPUT_BIND_DESC));
|
|
} else {
|
|
*pDesc = m_Resources[ResourceIndex];
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT DxilShaderReflection::GetInputParameterDesc(
|
|
UINT ParameterIndex, D3D12_SIGNATURE_PARAMETER_DESC *pDesc) noexcept {
|
|
IFRBOOL(pDesc != nullptr, E_INVALIDARG);
|
|
IFRBOOL(ParameterIndex < m_InputSignature.size(), E_INVALIDARG);
|
|
if (m_PublicAPI != PublicAPI::D3D11_43)
|
|
*pDesc = m_InputSignature[ParameterIndex];
|
|
else
|
|
memcpy(pDesc, &m_InputSignature[ParameterIndex],
|
|
// D3D11_43 does not have MinPrecison.
|
|
offsetof(D3D12_SIGNATURE_PARAMETER_DESC, Stream) +
|
|
sizeof(D3D12_SIGNATURE_PARAMETER_DESC::Stream));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT DxilShaderReflection::GetOutputParameterDesc(
|
|
UINT ParameterIndex, D3D12_SIGNATURE_PARAMETER_DESC *pDesc) noexcept {
|
|
IFRBOOL(pDesc != nullptr, E_INVALIDARG);
|
|
IFRBOOL(ParameterIndex < m_OutputSignature.size(), E_INVALIDARG);
|
|
if (m_PublicAPI != PublicAPI::D3D11_43)
|
|
*pDesc = m_OutputSignature[ParameterIndex];
|
|
else
|
|
memcpy(pDesc, &m_OutputSignature[ParameterIndex],
|
|
// D3D11_43 does not have MinPrecison.
|
|
offsetof(D3D12_SIGNATURE_PARAMETER_DESC, Stream) +
|
|
sizeof(D3D12_SIGNATURE_PARAMETER_DESC::Stream));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
DxilShaderReflection::GetPatchConstantParameterDesc(
|
|
UINT ParameterIndex, D3D12_SIGNATURE_PARAMETER_DESC *pDesc) noexcept {
|
|
IFRBOOL(pDesc != nullptr, E_INVALIDARG);
|
|
IFRBOOL(ParameterIndex < m_PatchConstantSignature.size(), E_INVALIDARG);
|
|
if (m_PublicAPI != PublicAPI::D3D11_43)
|
|
*pDesc = m_PatchConstantSignature[ParameterIndex];
|
|
else
|
|
memcpy(pDesc, &m_PatchConstantSignature[ParameterIndex],
|
|
// D3D11_43 does not have MinPrecison.
|
|
offsetof(D3D12_SIGNATURE_PARAMETER_DESC, Stream) +
|
|
sizeof(D3D12_SIGNATURE_PARAMETER_DESC::Stream));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
ID3D12ShaderReflectionVariable *
|
|
DxilShaderReflection::GetVariableByName(LPCSTR Name) noexcept {
|
|
return DxilModuleReflection::_GetVariableByName(Name);
|
|
}
|
|
ID3D12ShaderReflectionVariable *
|
|
DxilModuleReflection::_GetVariableByName(LPCSTR Name) {
|
|
if (Name != nullptr) {
|
|
// Iterate through all cbuffers to find the variable.
|
|
for (UINT i = 0; i < m_CBs.size(); i++) {
|
|
ID3D12ShaderReflectionVariable *pVar = m_CBs[i]->GetVariableByName(Name);
|
|
if (pVar != &g_InvalidSRVariable) {
|
|
return pVar;
|
|
}
|
|
}
|
|
}
|
|
|
|
return &g_InvalidSRVariable;
|
|
}
|
|
|
|
HRESULT DxilShaderReflection::GetResourceBindingDescByName(
|
|
LPCSTR Name, D3D12_SHADER_INPUT_BIND_DESC *pDesc) noexcept {
|
|
return DxilModuleReflection::_GetResourceBindingDescByName(Name, pDesc,
|
|
m_PublicAPI);
|
|
}
|
|
HRESULT DxilModuleReflection::_GetResourceBindingDescByName(
|
|
LPCSTR Name, D3D12_SHADER_INPUT_BIND_DESC *pDesc, PublicAPI api) {
|
|
IFRBOOL(Name != nullptr, E_INVALIDARG);
|
|
|
|
for (UINT i = 0; i < m_Resources.size(); i++) {
|
|
if (strcmp(m_Resources[i].Name, Name) == 0) {
|
|
if (api != PublicAPI::D3D12) {
|
|
memcpy(pDesc, &m_Resources[i], sizeof(D3D11_SHADER_INPUT_BIND_DESC));
|
|
} else {
|
|
*pDesc = m_Resources[i];
|
|
}
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
|
|
}
|
|
|
|
UINT DxilShaderReflection::GetMovInstructionCount() noexcept { return 0; }
|
|
UINT DxilShaderReflection::GetMovcInstructionCount() noexcept { return 0; }
|
|
UINT DxilShaderReflection::GetConversionInstructionCount() noexcept {
|
|
return 0;
|
|
}
|
|
UINT DxilShaderReflection::GetBitwiseInstructionCount() noexcept { return 0; }
|
|
|
|
D3D_PRIMITIVE DxilShaderReflection::GetGSInputPrimitive() noexcept {
|
|
if (!m_pDxilModule->GetShaderModel()->IsGS())
|
|
return D3D_PRIMITIVE::D3D10_PRIMITIVE_UNDEFINED;
|
|
return (D3D_PRIMITIVE)m_pDxilModule->GetInputPrimitive();
|
|
}
|
|
|
|
BOOL DxilShaderReflection::IsSampleFrequencyShader() noexcept {
|
|
// TODO: determine correct value
|
|
return FALSE;
|
|
}
|
|
|
|
UINT DxilShaderReflection::GetNumInterfaceSlots() noexcept { return 0; }
|
|
|
|
HRESULT
|
|
DxilShaderReflection::GetMinFeatureLevel(D3D_FEATURE_LEVEL *pLevel) noexcept {
|
|
IFR(AssignToOut(D3D_FEATURE_LEVEL_12_0, pLevel));
|
|
return S_OK;
|
|
}
|
|
|
|
UINT DxilShaderReflection::GetThreadGroupSize(UINT *pSizeX, UINT *pSizeY,
|
|
UINT *pSizeZ) noexcept {
|
|
if (!m_pDxilModule->GetShaderModel()->IsCS() &&
|
|
!m_pDxilModule->GetShaderModel()->IsMS() &&
|
|
!m_pDxilModule->GetShaderModel()->IsAS()) {
|
|
AssignToOutOpt((UINT)0, pSizeX);
|
|
AssignToOutOpt((UINT)0, pSizeY);
|
|
AssignToOutOpt((UINT)0, pSizeZ);
|
|
return 0;
|
|
}
|
|
unsigned x = m_pDxilModule->GetNumThreads(0);
|
|
unsigned y = m_pDxilModule->GetNumThreads(1);
|
|
unsigned z = m_pDxilModule->GetNumThreads(2);
|
|
AssignToOutOpt(x, pSizeX);
|
|
AssignToOutOpt(y, pSizeY);
|
|
AssignToOutOpt(z, pSizeZ);
|
|
return x * y * z;
|
|
}
|
|
|
|
UINT64 DxilShaderReflection::GetRequiresFlags() noexcept {
|
|
UINT64 result = m_pDxilModule->m_ShaderFlags.GetFeatureInfo();
|
|
// FeatureInfo flags are identical, with the exception of a collision between:
|
|
// SHADER_FEATURE_COMPUTE_SHADERS_PLUS_RAW_AND_STRUCTURED_BUFFERS_VIA_SHADER_4_X
|
|
// and D3D_SHADER_REQUIRES_EARLY_DEPTH_STENCIL
|
|
// We keep track of the flag elsewhere, so use that instead.
|
|
result &= ~(UINT64)D3D_SHADER_REQUIRES_EARLY_DEPTH_STENCIL;
|
|
if (m_pDxilModule->m_ShaderFlags.GetForceEarlyDepthStencil())
|
|
result |= D3D_SHADER_REQUIRES_EARLY_DEPTH_STENCIL;
|
|
return result;
|
|
}
|
|
|
|
// ID3D12FunctionReflection
|
|
|
|
class CFunctionReflection final : public ID3D12FunctionReflection {
|
|
protected:
|
|
DxilLibraryReflection *m_pLibraryReflection = nullptr;
|
|
const Function *m_pFunction;
|
|
const DxilFunctionProps *m_pProps; // nullptr if non-shader library function
|
|
// or patch constant function
|
|
std::string m_Name;
|
|
typedef SmallSetVector<UINT32, 8> ResourceUseSet;
|
|
ResourceUseSet m_UsedResources;
|
|
ResourceUseSet m_UsedCBs;
|
|
UINT64 m_FeatureFlags;
|
|
|
|
public:
|
|
void Initialize(DxilLibraryReflection *pLibraryReflection,
|
|
Function *pFunction) {
|
|
DXASSERT_NOMSG(pLibraryReflection);
|
|
DXASSERT_NOMSG(pFunction);
|
|
m_pLibraryReflection = pLibraryReflection;
|
|
m_pFunction = pFunction;
|
|
|
|
const DxilModule &M = *m_pLibraryReflection->m_pDxilModule;
|
|
m_Name = m_pFunction->getName().str();
|
|
m_pProps = nullptr;
|
|
if (M.HasDxilFunctionProps(m_pFunction)) {
|
|
m_pProps = &M.GetDxilFunctionProps(m_pFunction);
|
|
}
|
|
}
|
|
void AddResourceReference(UINT resIndex) { m_UsedResources.insert(resIndex); }
|
|
void AddCBReference(UINT cbIndex) { m_UsedCBs.insert(cbIndex); }
|
|
void SetFeatureFlags(UINT64 flags) { m_FeatureFlags = flags; }
|
|
|
|
// ID3D12FunctionReflection
|
|
STDMETHOD(GetDesc)(D3D12_FUNCTION_DESC *pDesc);
|
|
|
|
// BufferIndex relative to used constant buffers here
|
|
STDMETHOD_(ID3D12ShaderReflectionConstantBuffer *, GetConstantBufferByIndex)
|
|
(UINT BufferIndex);
|
|
STDMETHOD_(ID3D12ShaderReflectionConstantBuffer *, GetConstantBufferByName)
|
|
(LPCSTR Name);
|
|
|
|
STDMETHOD(GetResourceBindingDesc)
|
|
(UINT ResourceIndex, D3D12_SHADER_INPUT_BIND_DESC *pDesc);
|
|
|
|
STDMETHOD_(ID3D12ShaderReflectionVariable *, GetVariableByName)(LPCSTR Name);
|
|
|
|
STDMETHOD(GetResourceBindingDescByName)
|
|
(LPCSTR Name, D3D12_SHADER_INPUT_BIND_DESC *pDesc);
|
|
|
|
// Use D3D_RETURN_PARAMETER_INDEX to get description of the return value.
|
|
STDMETHOD_(ID3D12FunctionParameterReflection *, GetFunctionParameter)
|
|
(INT ParameterIndex) { return &g_InvalidFunctionParameter; }
|
|
};
|
|
|
|
HRESULT CFunctionReflection::GetDesc(D3D12_FUNCTION_DESC *pDesc) {
|
|
DXASSERT_NOMSG(m_pLibraryReflection);
|
|
IFR(ZeroMemoryToOut(pDesc));
|
|
|
|
const ShaderModel *pSM =
|
|
m_pLibraryReflection->m_pDxilModule->GetShaderModel();
|
|
DXIL::ShaderKind kind = DXIL::ShaderKind::Library;
|
|
if (m_pProps) {
|
|
kind = m_pProps->shaderKind;
|
|
}
|
|
pDesc->Version = EncodeVersion(kind, pSM->GetMajor(), pSM->GetMinor());
|
|
|
|
// Unset: LPCSTR Creator; // Creator string
|
|
// Unset: UINT Flags; // Shader compilation/parse flags
|
|
|
|
pDesc->ConstantBuffers = (UINT)m_UsedCBs.size();
|
|
pDesc->BoundResources = (UINT)m_UsedResources.size();
|
|
|
|
// Unset: UINT InstructionCount; // Number of emitted instructions
|
|
// Unset: UINT TempRegisterCount; // Number of temporary registers used
|
|
// Unset: UINT TempArrayCount; // Number of temporary arrays used
|
|
// Unset: UINT DefCount; // Number of constant defines
|
|
// Unset: UINT DclCount; // Number of declarations (input + output)
|
|
// Unset: UINT
|
|
// TextureNormalInstructions; // Number of non-categorized texture
|
|
// instructions
|
|
// Unset: UINT TextureLoadInstructions; // Number of texture load
|
|
// instructions
|
|
// Unset: UINT TextureCompInstructions; // Number of texture comparison
|
|
// instructions
|
|
|
|
// Unset: UINT TextureBiasInstructions;// Number of texture bias instructions
|
|
// Unset: UINT TextureGradientInstructions; // Number of texture gradient
|
|
// instructions
|
|
// Unset: UINT FloatInstructionCount; // Number of floating point arithmetic
|
|
// instructions used
|
|
// Unset: UINT IntInstructionCount; // Number of signed integer arithmetic
|
|
// instructions used
|
|
// Unset: UINT UintInstructionCount; // Number of unsigned integer
|
|
// arithmetic instructions used
|
|
// Unset: UINT StaticFlowControlCount; // Number of static flow control
|
|
// instructions used
|
|
// Unset: UINT DynamicFlowControlCount; // Number of dynamic flow control
|
|
// instructions used
|
|
// Unset: UINT MacroInstructionCount; // Number of macro instructions used
|
|
// Unset: UINT ArrayInstructionCount; // Number of array instructions used
|
|
// Unset: UINT MovInstructionCount; // Number of mov instructions used
|
|
// Unset: UINT MovcInstructionCount; // Number of movc instructions used
|
|
// Unset: UINT ConversionInstructionCount; // Number of type conversion
|
|
// instructions used
|
|
// Unset: UINT BitwiseInstructionCount; // Number of bitwise arithmetic
|
|
// instructions used
|
|
// Unset: D3D_FEATURE_LEVEL MinFeatureLevel; // Min target of the function
|
|
// byte code
|
|
|
|
pDesc->RequiredFeatureFlags =
|
|
m_FeatureFlags & ~(UINT64)D3D_SHADER_REQUIRES_EARLY_DEPTH_STENCIL;
|
|
// Also Mask off function-level derivatives flag.
|
|
pDesc->RequiredFeatureFlags &= ~DXIL::OptFeatureInfo_UsesDerivatives;
|
|
if (kind == DXIL::ShaderKind::Pixel && m_pProps &&
|
|
m_pProps->ShaderProps.PS.EarlyDepthStencil) {
|
|
pDesc->RequiredFeatureFlags |= D3D_SHADER_REQUIRES_EARLY_DEPTH_STENCIL;
|
|
}
|
|
|
|
pDesc->Name = m_Name.c_str();
|
|
|
|
// Unset: INT FunctionParameterCount; // Number of logical parameters in the
|
|
// function signature (not including return)
|
|
// Unset: BOOL HasReturn; // TRUE, if function returns a value, false - it is
|
|
// a subroutine
|
|
// Unset: BOOL Has10Level9VertexShader; // TRUE, if there is a 10L9 VS blob
|
|
// Unset: BOOL Has10Level9PixelShader; // TRUE, if there is a 10L9 PS blob
|
|
return S_OK;
|
|
}
|
|
|
|
// BufferIndex is relative to used constant buffers here
|
|
ID3D12ShaderReflectionConstantBuffer *
|
|
CFunctionReflection::GetConstantBufferByIndex(UINT BufferIndex) {
|
|
DXASSERT_NOMSG(m_pLibraryReflection);
|
|
if (BufferIndex >= m_UsedCBs.size())
|
|
return &g_InvalidSRConstantBuffer;
|
|
return m_pLibraryReflection->_GetConstantBufferByIndex(
|
|
m_UsedCBs[BufferIndex]);
|
|
}
|
|
|
|
ID3D12ShaderReflectionConstantBuffer *
|
|
CFunctionReflection::GetConstantBufferByName(LPCSTR Name) {
|
|
DXASSERT_NOMSG(m_pLibraryReflection);
|
|
return m_pLibraryReflection->_GetConstantBufferByName(Name);
|
|
}
|
|
|
|
HRESULT CFunctionReflection::GetResourceBindingDesc(
|
|
UINT ResourceIndex, D3D12_SHADER_INPUT_BIND_DESC *pDesc) {
|
|
DXASSERT_NOMSG(m_pLibraryReflection);
|
|
if (ResourceIndex >= m_UsedResources.size())
|
|
return E_INVALIDARG;
|
|
return m_pLibraryReflection->_GetResourceBindingDesc(
|
|
m_UsedResources[ResourceIndex], pDesc);
|
|
}
|
|
|
|
ID3D12ShaderReflectionVariable *
|
|
CFunctionReflection::GetVariableByName(LPCSTR Name) {
|
|
DXASSERT_NOMSG(m_pLibraryReflection);
|
|
return m_pLibraryReflection->_GetVariableByName(Name);
|
|
}
|
|
|
|
HRESULT CFunctionReflection::GetResourceBindingDescByName(
|
|
LPCSTR Name, D3D12_SHADER_INPUT_BIND_DESC *pDesc) {
|
|
DXASSERT_NOMSG(m_pLibraryReflection);
|
|
return m_pLibraryReflection->_GetResourceBindingDescByName(Name, pDesc);
|
|
}
|
|
|
|
// DxilLibraryReflection
|
|
|
|
void DxilLibraryReflection::AddResourceDependencies() {
|
|
auto functionTable = m_RDAT.GetFunctionTable();
|
|
m_FunctionVector.clear();
|
|
m_FunctionVector.reserve(functionTable.Count());
|
|
std::map<StringRef, CFunctionReflection *> orderedMap;
|
|
|
|
auto resourceTable = m_RDAT.GetResourceTable();
|
|
unsigned SamplersStart = 0;
|
|
unsigned SRVsStart = 0;
|
|
unsigned UAVsStart = 0;
|
|
DXIL::ResourceClass prevClass = DXIL::ResourceClass::CBuffer;
|
|
for (unsigned i = 0; i < resourceTable.Count(); i++) {
|
|
auto resource = resourceTable[i];
|
|
if (prevClass != resource.getClass()) {
|
|
prevClass = resource.getClass();
|
|
switch (prevClass) {
|
|
case DXIL::ResourceClass::Sampler:
|
|
SamplersStart = i;
|
|
LLVM_FALLTHROUGH;
|
|
case DXIL::ResourceClass::SRV:
|
|
SRVsStart = i;
|
|
LLVM_FALLTHROUGH;
|
|
case DXIL::ResourceClass::UAV:
|
|
UAVsStart = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
IFTBOOL(resourceTable.Count() == m_Resources.size(),
|
|
DXC_E_INCORRECT_DXIL_METADATA);
|
|
|
|
for (unsigned iFunc = 0; iFunc < functionTable.Count(); ++iFunc) {
|
|
auto FR = functionTable[iFunc];
|
|
auto &func = m_FunctionMap[FR.getName()];
|
|
DXASSERT(!func.get(), "otherwise duplicate named functions");
|
|
Function *F = m_pModule->getFunction(FR.getName());
|
|
func.reset(new CFunctionReflection());
|
|
func->Initialize(this, F);
|
|
m_FunctionsByPtr[F] = func.get();
|
|
orderedMap[FR.getName()] = func.get();
|
|
|
|
func->SetFeatureFlags(FR.GetFeatureFlags());
|
|
|
|
for (unsigned iRes = 0; iRes < FR.getResources().Count(); ++iRes) {
|
|
auto RR = FR.getResources()[iRes];
|
|
unsigned id = RR.getID();
|
|
switch (RR.getClass()) {
|
|
case DXIL::ResourceClass::CBuffer:
|
|
func->AddResourceReference(id);
|
|
func->AddCBReference(id);
|
|
break;
|
|
case DXIL::ResourceClass::Sampler:
|
|
func->AddResourceReference(SamplersStart + id);
|
|
break;
|
|
case DXIL::ResourceClass::SRV:
|
|
func->AddResourceReference(SRVsStart + id);
|
|
if (DXIL::IsStructuredBuffer(RR.getKind())) {
|
|
auto it = m_StructuredBufferCBsByName.find(RR.getName());
|
|
if (it != m_StructuredBufferCBsByName.end())
|
|
func->AddCBReference(it->second);
|
|
} else if (RR.getKind() == DXIL::ResourceKind::TBuffer) {
|
|
auto it = m_CBsByName.find(RR.getName());
|
|
if (it != m_CBsByName.end())
|
|
func->AddCBReference(it->second);
|
|
}
|
|
break;
|
|
case DXIL::ResourceClass::UAV:
|
|
func->AddResourceReference(UAVsStart + id);
|
|
if (DXIL::IsStructuredBuffer(RR.getKind())) {
|
|
auto it = m_StructuredBufferCBsByName.find(RR.getName());
|
|
if (it != m_StructuredBufferCBsByName.end())
|
|
func->AddCBReference(it->second);
|
|
}
|
|
break;
|
|
default:
|
|
DXASSERT(false, "Unrecognized ResourceClass in RDAT");
|
|
}
|
|
}
|
|
}
|
|
|
|
for (auto &it : orderedMap) {
|
|
m_FunctionVector.push_back(it.second);
|
|
}
|
|
}
|
|
|
|
static void CollectCBufUsageForLib(Value *V, std::vector<unsigned> &cbufUsage,
|
|
bool bMinPrecision) {
|
|
for (auto user : V->users()) {
|
|
Value *V = user;
|
|
if (auto *CI = dyn_cast<CallInst>(V)) {
|
|
if (hlsl::OP::IsDxilOpFuncCallInst(
|
|
CI, hlsl::OP::OpCode::CreateHandleForLib)) {
|
|
CollectCBufUsage(CI, cbufUsage, bMinPrecision);
|
|
}
|
|
} else if (isa<GEPOperator>(V) || isa<LoadInst>(V)) {
|
|
CollectCBufUsageForLib(user, cbufUsage, bMinPrecision);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DxilLibraryReflection::SetCBufferUsage() {
|
|
unsigned cbSize = std::min(m_CBs.size(), m_pDxilModule->GetCBuffers().size());
|
|
|
|
for (unsigned i = 0; i < cbSize; i++) {
|
|
std::vector<unsigned> cbufUsage;
|
|
CollectCBufUsageForLib(m_pDxilModule->GetCBuffer(i).GetGlobalSymbol(),
|
|
cbufUsage, m_pDxilModule->GetUseMinPrecision());
|
|
SetCBufVarUsage(*m_CBs[i], cbufUsage);
|
|
}
|
|
}
|
|
|
|
// ID3D12LibraryReflection
|
|
|
|
HRESULT DxilLibraryReflection::Load(const DxilProgramHeader *pProgramHeader,
|
|
const DxilPartHeader *pRDATPart) {
|
|
IFR(LoadRDAT(pRDATPart));
|
|
IFR(LoadProgramHeader(pProgramHeader));
|
|
|
|
try {
|
|
AddResourceDependencies();
|
|
if (!m_bUsageInMetadata)
|
|
SetCBufferUsage();
|
|
return S_OK;
|
|
}
|
|
CATCH_CPP_RETURN_HRESULT();
|
|
}
|
|
|
|
HRESULT DxilLibraryReflection::GetDesc(D3D12_LIBRARY_DESC *pDesc) {
|
|
IFR(ZeroMemoryToOut(pDesc));
|
|
// Unset: LPCSTR Creator; // The name of the originator of the
|
|
// library. Unset: UINT Flags; // Compilation flags. UINT
|
|
// FunctionCount; // Number of functions exported from the library.
|
|
pDesc->FunctionCount = (UINT)m_FunctionVector.size();
|
|
return S_OK;
|
|
}
|
|
|
|
ID3D12FunctionReflection *
|
|
DxilLibraryReflection::GetFunctionByIndex(INT FunctionIndex) {
|
|
if ((UINT)FunctionIndex >= m_FunctionVector.size())
|
|
return &g_InvalidFunction;
|
|
return m_FunctionVector[FunctionIndex];
|
|
}
|