Parcourir la source

add creation of ID3D12StateObject

Kolja Strohm il y a 1 mois
Parent
commit
0a20990ef2
2 fichiers modifiés avec 733 ajouts et 15 suppressions
  1. 673 5
      DX12Shader.cpp
  2. 60 10
      DX12Shader.h

+ 673 - 5
DX12Shader.cpp

@@ -4,12 +4,10 @@
 
 using namespace Framework;
 
-Framework::DX12ShaderSignature::DX12ShaderSignature(ID3D12Device5* zDevice,
-    PFN_D3D12_SERIALIZE_ROOT_SIGNATURE pfnD3D12SerializeRootSignature)
+Framework::DX12ShaderSignature::DX12ShaderSignature()
     : ReferenceCounter(),
       signature(0),
-      zDevice(zDevice),
-      pfnD3D12SerializeRootSignature(pfnD3D12SerializeRootSignature)
+      changed(1)
 {}
 
 Framework::DX12ShaderSignature::~DX12ShaderSignature()
@@ -30,10 +28,17 @@ void Framework::DX12ShaderSignature::addRegisterUsage(
     DX12ShaderRegister registerType, int registerIndex, int spaceIndex)
 {
     registerUsages.add({registerType, registerIndex, spaceIndex});
+    changed = 1;
 }
 
-void Framework::DX12ShaderSignature::createSignature()
+void Framework::DX12ShaderSignature::createSignature(ID3D12Device5* zDevice,
+    PFN_D3D12_SERIALIZE_ROOT_SIGNATURE pfnD3D12SerializeRootSignature)
 {
+    if (!changed)
+    {
+        return;
+    }
+    changed = 0;
     if (signature)
     {
         signature->Release();
@@ -109,3 +114,666 @@ ID3D12RootSignature* Framework::DX12ShaderSignature::zSignature() const
 {
     return signature;
 }
+
+Framework::DX12ShaderFunction::DX12ShaderFunction(
+    const Text& functionName, DX12ShaderSignature* signature)
+    : ReferenceCounter(),
+      functionName(functionName),
+      signature(signature),
+      exportDesc(new D3D12_EXPORT_DESC())
+{
+    wchar_t* wc = new wchar_t[functionName.getLength() + 1];
+    mbtowc(wc, functionName.getText(), functionName.getLength() + 1);
+    wc[functionName.getLength()] = 0;
+    exportDesc->Name = wc;
+    exportDesc->ExportToRename = 0;
+    exportDesc->Flags = D3D12_EXPORT_FLAG_NONE;
+}
+
+Framework::DX12ShaderFunction::~DX12ShaderFunction()
+{
+    signature->release();
+    delete[] exportDesc->Name;
+    delete exportDesc;
+}
+
+const Text& Framework::DX12ShaderFunction::getFunctionName() const
+{
+    return functionName;
+}
+
+DX12ShaderSignature* Framework::DX12ShaderFunction::zSignature() const
+{
+    return signature;
+}
+
+D3D12_EXPORT_DESC* Framework::DX12ShaderFunction::zExportDesc() const
+{
+    return exportDesc;
+}
+
+Framework::DX12Shader::DX12Shader(const char* shaderBytes, int shaderBytesSize)
+    : ReferenceCounter(),
+      shaderBytes(shaderBytes),
+      shaderBytesSize(shaderBytesSize),
+      libraryDesc(new D3D12_DXIL_LIBRARY_DESC())
+{
+    libraryDesc->DXILLibrary.pShaderBytecode = shaderBytes;
+    libraryDesc->DXILLibrary.BytecodeLength = shaderBytesSize;
+    libraryDesc->NumExports = 0;
+    libraryDesc->pExports = 0;
+}
+
+Framework::DX12Shader::~DX12Shader()
+{
+    delete[] libraryDesc->pExports;
+    delete libraryDesc;
+}
+
+void Framework::DX12Shader::addFunction(DX12ShaderFunction* function)
+{
+    functions.add(function);
+}
+
+int Framework::DX12Shader::getShaderBytesSize() const
+{
+    return shaderBytesSize;
+}
+
+const char* Framework::DX12Shader::getShaderBytes() const
+{
+    return shaderBytes;
+}
+
+const RCArray<DX12ShaderFunction>& Framework::DX12Shader::getFunctions() const
+{
+    return functions;
+}
+
+D3D12_DXIL_LIBRARY_DESC* Framework::DX12Shader::zLibraryDesc() const
+{
+    if (libraryDesc->NumExports != functions.getEntryCount())
+    {
+        delete[] libraryDesc->pExports;
+        libraryDesc->NumExports = functions.getEntryCount();
+        D3D12_EXPORT_DESC* pExports
+            = new D3D12_EXPORT_DESC[functions.getEntryCount()];
+        int index = 0;
+        for (const auto& function : functions)
+        {
+            memcpy(pExports + index,
+                function->zExportDesc(),
+                sizeof(D3D12_EXPORT_DESC));
+            index++;
+        }
+        libraryDesc->pExports = pExports;
+    }
+    return libraryDesc;
+}
+
+Framework::DX12ShaderHitGroup::DX12ShaderHitGroup(const Text name)
+    : ReferenceCounter(),
+      name(name),
+      closestHitShaderFunction(0),
+      anyHitShaderFunction(0),
+      intersectionShaderFunction(0),
+      payloadSize(0),
+      attributeSize(0),
+      hitGroupDesc(new D3D12_HIT_GROUP_DESC())
+{
+    wchar_t* wc = new wchar_t[name.getLength() + 1];
+    mbtowc(wc, name.getText(), name.getLength() + 1);
+    wc[name.getLength()] = 0;
+    hitGroupDesc->HitGroupExport = wc;
+    hitGroupDesc->IntersectionShaderImport = 0;
+    hitGroupDesc->AnyHitShaderImport = 0;
+    hitGroupDesc->ClosestHitShaderImport = 0;
+}
+
+Framework::DX12ShaderHitGroup::~DX12ShaderHitGroup()
+{
+    delete[] hitGroupDesc->HitGroupExport;
+    delete hitGroupDesc;
+    if (closestHitShaderFunction)
+    {
+        closestHitShaderFunction->release();
+    }
+    if (anyHitShaderFunction)
+    {
+        anyHitShaderFunction->release();
+    }
+    if (intersectionShaderFunction)
+    {
+        intersectionShaderFunction->release();
+    }
+}
+
+void Framework::DX12ShaderHitGroup::setClosestHitShaderFunction(
+    DX12ShaderFunction* closestHitShaderFunction)
+{
+    if (anyHitShaderFunction
+        && anyHitShaderFunction->zSignature()
+               != closestHitShaderFunction->zSignature())
+    {
+        Logging::error()
+            << "Any-hit shader function and closest-hit shader "
+               "function must have the same root signature when they are "
+               "combined in the same hit group. HitGroup Name: '"
+            << name << "' Any Hit Shader Function: '"
+            << anyHitShaderFunction->getFunctionName().getText()
+            << "' Closest Hit Shader Function: '"
+            << closestHitShaderFunction->getFunctionName().getText() << "'";
+        throw std::runtime_error("Incompatible root signatures in hit group");
+    }
+    if (intersectionShaderFunction
+        && intersectionShaderFunction->zSignature()
+               != closestHitShaderFunction->zSignature())
+    {
+        Logging::error()
+            << "Intersection shader function and closest-hit shader "
+               "function must have the same root signature when they are "
+               "combined in the same hit group. HitGroup Name: '"
+            << name << "' Intersection Shader Function: '"
+            << intersectionShaderFunction->getFunctionName().getText()
+            << "' Closest Hit Shader Function: '"
+            << closestHitShaderFunction->getFunctionName().getText() << "'";
+        throw std::runtime_error("Incompatible root signatures in hit group");
+    }
+
+    if (this->closestHitShaderFunction)
+    {
+        this->closestHitShaderFunction->release();
+    }
+    this->closestHitShaderFunction = closestHitShaderFunction;
+    hitGroupDesc->ClosestHitShaderImport = 0;
+    if (closestHitShaderFunction)
+    {
+        hitGroupDesc->ClosestHitShaderImport
+            = closestHitShaderFunction->zExportDesc()->Name;
+    }
+}
+
+void Framework::DX12ShaderHitGroup::setAnyHitShaderFunction(
+    DX12ShaderFunction* anyHitShaderFunction)
+{
+    if (closestHitShaderFunction
+        && closestHitShaderFunction->zSignature()
+               != anyHitShaderFunction->zSignature())
+    {
+        Logging::error()
+            << "Any-hit shader function and closest-hit shader "
+               "function must have the same root signature when they are "
+               "combined in the same hit group. HitGroup Name: '"
+            << name << "' Any Hit Shader Function: '"
+            << anyHitShaderFunction->getFunctionName().getText()
+            << "' Closest Hit Shader Function: '"
+            << closestHitShaderFunction->getFunctionName().getText() << "'";
+        throw std::runtime_error("Incompatible root signatures in hit group");
+    }
+    if (intersectionShaderFunction
+        && intersectionShaderFunction->zSignature()
+               != anyHitShaderFunction->zSignature())
+    {
+        Logging::error()
+            << "Intersection shader function and any-hit shader "
+               "function must have the same root signature when they are "
+               "combined in the same hit group. HitGroup Name: '"
+            << name << "' Intersection Shader Function: '"
+            << intersectionShaderFunction->getFunctionName().getText()
+            << "' Any Hit Shader Function: '"
+            << anyHitShaderFunction->getFunctionName().getText() << "'";
+        throw std::runtime_error("Incompatible root signatures in hit group");
+    }
+
+    if (this->anyHitShaderFunction)
+    {
+        this->anyHitShaderFunction->release();
+    }
+    this->anyHitShaderFunction = anyHitShaderFunction;
+    hitGroupDesc->AnyHitShaderImport = 0;
+    if (anyHitShaderFunction)
+    {
+        hitGroupDesc->AnyHitShaderImport
+            = anyHitShaderFunction->zExportDesc()->Name;
+    }
+}
+
+void Framework::DX12ShaderHitGroup::setIntersectionShaderFunction(
+    DX12ShaderFunction* intersectionShaderFunction)
+{
+    if (closestHitShaderFunction
+        && closestHitShaderFunction->zSignature()
+               != intersectionShaderFunction->zSignature())
+    {
+        Logging::error()
+            << "Intersection shader function and closest-hit shader "
+               "function must have the same root signature when they are "
+               "combined in the same hit group. HitGroup Name: '"
+            << name << "' Intersection Shader Function: '"
+            << intersectionShaderFunction->getFunctionName().getText()
+            << "' Closest Hit Shader Function: '"
+            << closestHitShaderFunction->getFunctionName().getText() << "'";
+        throw std::runtime_error("Incompatible root signatures in hit group");
+    }
+    if (anyHitShaderFunction
+        && anyHitShaderFunction->zSignature()
+               != intersectionShaderFunction->zSignature())
+    {
+        Logging::error()
+            << "Intersection shader function and any-hit shader "
+               "function must have the same root signature when they are "
+               "combined in the same hit group. HitGroup Name: '"
+            << name << "' Intersection Shader Function: '"
+            << intersectionShaderFunction->getFunctionName().getText()
+            << "' Any Hit Shader Function: '"
+            << anyHitShaderFunction->getFunctionName().getText() << "'";
+        throw std::runtime_error("Incompatible root signatures in hit group");
+    }
+
+    if (this->intersectionShaderFunction)
+    {
+        this->intersectionShaderFunction->release();
+    }
+    this->intersectionShaderFunction = intersectionShaderFunction;
+    hitGroupDesc->IntersectionShaderImport = 0;
+    if (intersectionShaderFunction)
+    {
+        hitGroupDesc->IntersectionShaderImport
+            = intersectionShaderFunction->zExportDesc()->Name;
+    }
+}
+
+void Framework::DX12ShaderHitGroup::setPayloadSize(int payloadSize)
+{
+    this->payloadSize = payloadSize;
+}
+
+void Framework::DX12ShaderHitGroup::setAttributeSize(int attributeSize)
+{
+    this->attributeSize = attributeSize;
+}
+
+const Text& Framework::DX12ShaderHitGroup::getName() const
+{
+    return name;
+}
+
+DX12ShaderFunction*
+Framework::DX12ShaderHitGroup::zClosestHitShaderFunction() const
+{
+    return closestHitShaderFunction;
+}
+
+DX12ShaderFunction* Framework::DX12ShaderHitGroup::zAnyHitShaderFunction() const
+{
+    return anyHitShaderFunction;
+}
+
+DX12ShaderFunction*
+Framework::DX12ShaderHitGroup::zIntersectionShaderFunction() const
+{
+    return intersectionShaderFunction;
+}
+
+int Framework::DX12ShaderHitGroup::getPayloadSize() const
+{
+    return payloadSize;
+}
+
+int Framework::DX12ShaderHitGroup::getAttributeSize() const
+{
+    return attributeSize;
+}
+
+D3D12_HIT_GROUP_DESC* Framework::DX12ShaderHitGroup::zHitGroupDesc() const
+{
+    if (hitGroupDesc->IntersectionShaderImport)
+    {
+        hitGroupDesc->Type = D3D12_HIT_GROUP_TYPE_PROCEDURAL_PRIMITIVE;
+    }
+    else
+    {
+        hitGroupDesc->Type = D3D12_HIT_GROUP_TYPE_TRIANGLES;
+    }
+    return hitGroupDesc;
+}
+
+Framework::DX12Pipeline::DX12Pipeline()
+    : ReferenceCounter(),
+      emptyGlobalRootSignature(0),
+      emptyLocalRootSignature(0),
+      pipelineState(0),
+      maxRecursionDepth(0)
+{}
+
+Framework::DX12Pipeline::~DX12Pipeline()
+{
+    if (emptyGlobalRootSignature)
+    {
+        emptyGlobalRootSignature->Release();
+    }
+    if (emptyLocalRootSignature)
+    {
+        emptyLocalRootSignature->Release();
+    }
+    if (pipelineState)
+    {
+        pipelineState->Release();
+    }
+}
+
+void Framework::DX12Pipeline::addShader(DX12Shader* shader)
+{
+    shaders.add(shader);
+}
+
+void Framework::DX12Pipeline::addHitGroup(DX12ShaderHitGroup* hitGroup)
+{
+    hitGroups.add(hitGroup);
+}
+
+void Framework::DX12Pipeline::setMaxRecursionDepth(int maxRecursionDepth)
+{
+    this->maxRecursionDepth = maxRecursionDepth;
+}
+
+void Framework::DX12Pipeline::createPipelineState(ID3D12Device5* zDevice,
+    PFN_D3D12_SERIALIZE_ROOT_SIGNATURE pfnD3D12SerializeRootSignature)
+{
+    if (!emptyGlobalRootSignature)
+    {
+        D3D12_ROOT_SIGNATURE_DESC rootDesc = {};
+        rootDesc.NumParameters = 0;
+        rootDesc.pParameters = 0;
+        rootDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE;
+        ID3DBlob* pSigBlob = 0;
+        ID3DBlob* pErrorBlob = 0;
+        HRESULT hr = pfnD3D12SerializeRootSignature(
+            &rootDesc, D3D_ROOT_SIGNATURE_VERSION_1_0, &pSigBlob, &pErrorBlob);
+        if (pSigBlob)
+        {
+            zDevice->CreateRootSignature(0,
+                pSigBlob->GetBufferPointer(),
+                pSigBlob->GetBufferSize(),
+                __uuidof(ID3D12RootSignature),
+                (void**)&emptyGlobalRootSignature);
+            pSigBlob->Release();
+        }
+        if (pErrorBlob)
+        {
+            std::string errorMessage(
+                static_cast<const char*>(pErrorBlob->GetBufferPointer()),
+                pErrorBlob->GetBufferSize());
+            Logging::error()
+                << "Failed to serialize empty root signature: " << errorMessage;
+            pErrorBlob->Release();
+        }
+    }
+    if (!emptyLocalRootSignature)
+    {
+        D3D12_ROOT_SIGNATURE_DESC rootDesc = {};
+        rootDesc.NumParameters = 0;
+        rootDesc.pParameters = 0;
+        rootDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_LOCAL_ROOT_SIGNATURE;
+        ID3DBlob* pSigBlob = 0;
+        ID3DBlob* pErrorBlob = 0;
+        HRESULT hr = pfnD3D12SerializeRootSignature(
+            &rootDesc, D3D_ROOT_SIGNATURE_VERSION_1_0, &pSigBlob, &pErrorBlob);
+        if (pSigBlob)
+        {
+            zDevice->CreateRootSignature(0,
+                pSigBlob->GetBufferPointer(),
+                pSigBlob->GetBufferSize(),
+                __uuidof(ID3D12RootSignature),
+                (void**)&emptyGlobalRootSignature);
+            pSigBlob->Release();
+        }
+        if (pErrorBlob)
+        {
+            std::string errorMessage(
+                static_cast<const char*>(pErrorBlob->GetBufferPointer()),
+                pErrorBlob->GetBufferSize());
+            Logging::error()
+                << "Failed to serialize empty root signature: " << errorMessage;
+            pErrorBlob->Release();
+        }
+    }
+    unsigned int subobjectCount
+        = shaders.getEntryCount() + hitGroups.getEntryCount() + 5;
+    Array<DX12ShaderSignature*> distinctSignatures;
+    for (const DX12Shader* shader : shaders)
+    {
+        for (const DX12ShaderFunction* function : shader->getFunctions())
+        {
+            DX12ShaderSignature* signature = function->zSignature();
+            if (distinctSignatures.getValueIndex(signature) < 0)
+            {
+                distinctSignatures.add(signature);
+            }
+        }
+    }
+    subobjectCount += distinctSignatures.getEntryCount()
+                    * 2; // Local root signatures for each distinct signature
+    D3D12_STATE_SUBOBJECT* subobjects
+        = new D3D12_STATE_SUBOBJECT[subobjectCount];
+    int index = 0;
+    for (const DX12Shader* shader : shaders)
+    {
+        subobjects[index].Type = D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY;
+        subobjects[index].pDesc = shader->zLibraryDesc();
+        index++;
+    }
+    int maxPayloadSize = 0;
+    int maxAttributeSize = 0;
+    for (const DX12ShaderHitGroup* hitGroup : hitGroups)
+    {
+        subobjects[index].Type = D3D12_STATE_SUBOBJECT_TYPE_HIT_GROUP;
+        subobjects[index].pDesc = hitGroup->zHitGroupDesc();
+        if (hitGroup->getPayloadSize() > maxPayloadSize)
+        {
+            maxPayloadSize = hitGroup->getPayloadSize();
+        }
+        if (hitGroup->getAttributeSize() > maxAttributeSize)
+        {
+            maxAttributeSize = hitGroup->getAttributeSize();
+        }
+        index++;
+    }
+    D3D12_RAYTRACING_SHADER_CONFIG shaderDesc = {};
+    shaderDesc.MaxPayloadSizeInBytes = maxPayloadSize;
+    shaderDesc.MaxAttributeSizeInBytes = maxAttributeSize;
+
+    subobjects[index].Type
+        = D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG;
+    subobjects[index].pDesc = &shaderDesc;
+    index++;
+    // create export list for hole pipeline with all hitgroups and all functions
+    // that are not part of a hit group
+    Array<const DX12ShaderFunction*> functionsWithoutHitGroups;
+    for (const DX12Shader* shader : shaders)
+    {
+        for (const DX12ShaderFunction* function : shader->getFunctions())
+        {
+            bool found = 0;
+            for (const DX12ShaderHitGroup* hitGroup : hitGroups)
+            {
+                if (hitGroup->zClosestHitShaderFunction() == function
+                    || hitGroup->zAnyHitShaderFunction() == function
+                    || hitGroup->zIntersectionShaderFunction() == function)
+                {
+                    found = 1;
+                    break;
+                }
+            }
+            if (!found)
+            {
+                functionsWithoutHitGroups.add(function);
+            }
+        }
+    }
+    wchar_t** functionAndHitGroupNames
+        = new wchar_t*[functionsWithoutHitGroups.getEntryCount()
+                       + hitGroups.getEntryCount()];
+    int nameIndex = 0;
+    for (const DX12ShaderFunction* function : functionsWithoutHitGroups)
+    {
+        functionAndHitGroupNames[nameIndex]
+            = const_cast<wchar_t*>(function->zExportDesc()->Name);
+        nameIndex++;
+    }
+    for (const DX12ShaderHitGroup* hitGroup : hitGroups)
+    {
+        functionAndHitGroupNames[nameIndex]
+            = const_cast<wchar_t*>(hitGroup->zHitGroupDesc()->HitGroupExport);
+        nameIndex++;
+    }
+    D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION shaderPayloadAssociation = {};
+    shaderPayloadAssociation.NumExports
+        = functionsWithoutHitGroups.getEntryCount() + hitGroups.getEntryCount();
+    shaderPayloadAssociation.pExports = functionAndHitGroupNames;
+    shaderPayloadAssociation.pSubobjectToAssociate
+        = &subobjects[index - 1]; // shader config
+    subobjects[index].Type
+        = D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION;
+    subobjects[index].pDesc = &shaderPayloadAssociation;
+    index++;
+    D3D12_LOCAL_ROOT_SIGNATURE* localRootSignatures
+        = new D3D12_LOCAL_ROOT_SIGNATURE[distinctSignatures.getEntryCount()];
+    int rootSignatureIndex = 0;
+    const wchar_t*** rootSignatureExports
+        = new const wchar_t**[distinctSignatures.getEntryCount()];
+    D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION* localRootAssociations
+        = new D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION[distinctSignatures
+                .getEntryCount()];
+    for (DX12ShaderSignature* signature : distinctSignatures)
+    {
+        signature->createSignature(zDevice, pfnD3D12SerializeRootSignature);
+        subobjects[index].Type
+            = D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE;
+        localRootSignatures[rootSignatureIndex].pLocalRootSignature
+            = signature->zSignature();
+        subobjects[index].pDesc = &localRootSignatures[rootSignatureIndex];
+        index++;
+
+        Array<const DX12ShaderFunction*> functionsWithThisSignature;
+        for (const DX12Shader* shader : shaders)
+        {
+            for (const DX12ShaderFunction* function : shader->getFunctions())
+            {
+                if (function->zSignature() == signature)
+                {
+                    bool found = 0;
+                    for (DX12ShaderHitGroup* hitGroup : hitGroups)
+                    {
+                        if (hitGroup->zClosestHitShaderFunction() == function
+                            || hitGroup->zAnyHitShaderFunction() == function
+                            || hitGroup->zIntersectionShaderFunction()
+                                   == function)
+                        {
+                            found = 1;
+                            break;
+                        }
+                    }
+                    if (!found)
+                    {
+                        functionsWithThisSignature.add(function);
+                    }
+                }
+            }
+        }
+        Array<const DX12ShaderHitGroup*> hitGroupsWithThisSignature;
+        for (const DX12ShaderHitGroup* hitGroup : hitGroups)
+        {
+            if (hitGroup->zClosestHitShaderFunction()
+                && hitGroup->zClosestHitShaderFunction()->zSignature()
+                       == signature)
+            {
+                hitGroupsWithThisSignature.add(hitGroup);
+            }
+            else if (hitGroup->zAnyHitShaderFunction()
+                     && hitGroup->zAnyHitShaderFunction()->zSignature()
+                            == signature)
+            {
+                hitGroupsWithThisSignature.add(hitGroup);
+            }
+            else if (hitGroup->zIntersectionShaderFunction()
+                     && hitGroup->zIntersectionShaderFunction()->zSignature()
+                            == signature)
+            {
+                hitGroupsWithThisSignature.add(hitGroup);
+            }
+        }
+        rootSignatureExports[rootSignatureIndex]
+            = new const wchar_t*[functionsWithThisSignature.getEntryCount()
+                                 + hitGroupsWithThisSignature.getEntryCount()];
+        int nameIndex = 0;
+        for (const DX12ShaderFunction* function : functionsWithThisSignature)
+        {
+            rootSignatureExports[rootSignatureIndex][nameIndex]
+                = function->zExportDesc()->Name;
+            nameIndex++;
+        }
+        for (const DX12ShaderHitGroup* hitGroup : hitGroupsWithThisSignature)
+        {
+            rootSignatureExports[rootSignatureIndex][nameIndex]
+                = hitGroup->zHitGroupDesc()->HitGroupExport;
+            nameIndex++;
+        }
+        localRootAssociations[rootSignatureIndex].NumExports
+            = functionsWithThisSignature.getEntryCount()
+            + hitGroupsWithThisSignature.getEntryCount();
+        localRootAssociations[rootSignatureIndex].pExports
+            = rootSignatureExports[rootSignatureIndex];
+        localRootAssociations[rootSignatureIndex].pSubobjectToAssociate
+            = &subobjects[index - 1]; // local root signature
+        subobjects[index].Type
+            = D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION;
+        subobjects[index].pDesc = &localRootAssociations[rootSignatureIndex];
+        index++;
+
+        rootSignatureIndex++;
+    }
+
+    subobjects[index].Type = D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE;
+    subobjects[index].pDesc = &emptyGlobalRootSignature;
+    index++;
+
+    subobjects[index].Type = D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE;
+    subobjects[index].pDesc = &emptyLocalRootSignature;
+    index++;
+
+    D3D12_RAYTRACING_PIPELINE_CONFIG pipelineConfig = {};
+    pipelineConfig.MaxTraceRecursionDepth = maxRecursionDepth;
+    subobjects[index].Type
+        = D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG;
+    subobjects[index].pDesc = &pipelineConfig;
+    index++;
+
+    D3D12_STATE_OBJECT_DESC pipelineDesc = {};
+    pipelineDesc.Type = D3D12_STATE_OBJECT_TYPE_RAYTRACING_PIPELINE;
+    pipelineDesc.NumSubobjects = subobjectCount;
+    pipelineDesc.pSubobjects = subobjects;
+    HRESULT hr = zDevice->CreateStateObject(
+        &pipelineDesc, __uuidof(ID3D12StateObject), (void**)&pipelineState);
+    if (FAILED(hr))
+    {
+        Logging::error()
+            << "Failed to create raytracing pipeline state object: " << std::hex
+            << hr;
+        throw std::logic_error("Could not create the raytracing state object");
+    }
+
+    delete[] functionAndHitGroupNames;
+    delete[] localRootSignatures;
+    for (int i = 0; i < distinctSignatures.getEntryCount(); i++)
+    {
+        delete[] rootSignatureExports[i];
+    }
+    delete[] rootSignatureExports;
+    delete[] localRootAssociations;
+}
+
+ID3D12StateObject* Framework::DX12Pipeline::zPipelineState() const
+{
+    return pipelineState;
+}

+ 60 - 10
DX12Shader.h

@@ -30,13 +30,11 @@ namespace Framework
     {
     private:
         ID3D12RootSignature* signature;
-        ID3D12Device5* zDevice;
         Array<DX12ShaderRegisterUsage> registerUsages;
-        PFN_D3D12_SERIALIZE_ROOT_SIGNATURE pfnD3D12SerializeRootSignature;
+        bool changed;
 
     public:
-        DX12ShaderSignature(ID3D12Device5* zDevice,
-            PFN_D3D12_SERIALIZE_ROOT_SIGNATURE pfnD3D12SerializeRootSignature);
+        DX12ShaderSignature();
         ~DX12ShaderSignature();
         /**
          * needs to be called for each datastructure with : register(...)
@@ -61,7 +59,8 @@ namespace Framework
         /**
          * Creates the root signature.
          */
-        void createSignature();
+        void createSignature(ID3D12Device5* zDevice,
+            PFN_D3D12_SERIALIZE_ROOT_SIGNATURE pfnD3D12SerializeRootSignature);
         ID3D12RootSignature* zSignature() const;
     };
 
@@ -70,6 +69,15 @@ namespace Framework
     private:
         Text functionName;
         DX12ShaderSignature* signature;
+        D3D12_EXPORT_DESC* exportDesc;
+
+    public:
+        DX12ShaderFunction(
+            const Text& functionName, DX12ShaderSignature* signature);
+        ~DX12ShaderFunction();
+        const Text& getFunctionName() const;
+        DX12ShaderSignature* zSignature() const;
+        D3D12_EXPORT_DESC* zExportDesc() const;
     };
 
     class DX12Shader : public ReferenceCounter
@@ -78,24 +86,66 @@ namespace Framework
         RCArray<DX12ShaderFunction> functions;
         const char* shaderBytes;
         int shaderBytesSize;
+        D3D12_DXIL_LIBRARY_DESC* libraryDesc;
+
+    public:
+        DX12Shader(const char* shaderBytes, int shaderBytesSize);
+        ~DX12Shader();
+        void addFunction(DX12ShaderFunction* function);
+        int getShaderBytesSize() const;
+        const char* getShaderBytes() const;
+        const RCArray<DX12ShaderFunction>& getFunctions() const;
+        D3D12_DXIL_LIBRARY_DESC* zLibraryDesc() const;
     };
 
-    class ShaderHitGroup : public ReferenceCounter
+    class DX12ShaderHitGroup : public ReferenceCounter
     {
     private:
         Text name;
-        DX12ShaderFunction* closestHitShaderFunctionName;
-        DX12ShaderFunction* anyHitShaderFunctionName;
-        DX12ShaderFunction* intersectionShaderFunctionName;
+        DX12ShaderFunction* closestHitShaderFunction;
+        DX12ShaderFunction* anyHitShaderFunction;
+        DX12ShaderFunction* intersectionShaderFunction;
         int payloadSize;
         int attributeSize;
+        D3D12_HIT_GROUP_DESC* hitGroupDesc;
+
+    public:
+        DX12ShaderHitGroup(const Text name);
+        ~DX12ShaderHitGroup();
+        void setClosestHitShaderFunction(
+            DX12ShaderFunction* closestHitShaderFunction);
+        void setAnyHitShaderFunction(DX12ShaderFunction* anyHitShaderFunction);
+        void setIntersectionShaderFunction(
+            DX12ShaderFunction* intersectionShaderFunction);
+        void setPayloadSize(int payloadSize);
+        void setAttributeSize(int attributeSize);
+        const Text& getName() const;
+        DX12ShaderFunction* zClosestHitShaderFunction() const;
+        DX12ShaderFunction* zAnyHitShaderFunction() const;
+        DX12ShaderFunction* zIntersectionShaderFunction() const;
+        int getPayloadSize() const;
+        int getAttributeSize() const;
+        D3D12_HIT_GROUP_DESC* zHitGroupDesc() const;
     };
 
     class DX12Pipeline : public ReferenceCounter
     {
     private:
         RCArray<DX12Shader> shaders;
-        RCArray<ShaderHitGroup> hitGroups;
+        RCArray<DX12ShaderHitGroup> hitGroups;
+        ID3D12RootSignature* emptyGlobalRootSignature;
+        ID3D12RootSignature* emptyLocalRootSignature;
+        ID3D12StateObject* pipelineState;
         int maxRecursionDepth;
+
+    public:
+        DX12Pipeline();
+        ~DX12Pipeline();
+        void addShader(DX12Shader* shader);
+        void addHitGroup(DX12ShaderHitGroup* hitGroup);
+        void setMaxRecursionDepth(int maxRecursionDepth);
+        void createPipelineState(ID3D12Device5* zDevice,
+            PFN_D3D12_SERIALIZE_ROOT_SIGNATURE pfnD3D12SerializeRootSignature);
+        ID3D12StateObject* zPipelineState() const;
     }; // namespace Framework
 } // namespace Framework