Parcourir la source

implement shader binding table for directx12 raytracing

Kolja Strohm il y a 4 semaines
Parent
commit
5ad9c07f41
6 fichiers modifiés avec 685 ajouts et 173 suppressions
  1. 2 2
      DX12Buffer.cpp
  2. 2 1
      DX12Buffer.h
  3. 25 68
      DX12GraphicsApi.cpp
  4. 2 1
      DX12GraphicsApi.h
  5. 561 90
      DX12Shader.cpp
  6. 93 11
      DX12Shader.h

+ 2 - 2
DX12Buffer.cpp

@@ -75,7 +75,7 @@ void DX12Buffer::copyToGPU(__int64 byteCount)
 }
 
 void Framework::DX12Buffer::createBufferWithoutData(
-    D3D12_RESOURCE_STATES states)
+    D3D12_RESOURCE_STATES states, D3D12_HEAP_TYPE heapType)
 {
     if (!len) return;
     if (description->Width != len)
@@ -87,7 +87,7 @@ void Framework::DX12Buffer::createBufferWithoutData(
     if (!buffer)
     {
         D3D12_HEAP_PROPERTIES hprop;
-        hprop.Type = D3D12_HEAP_TYPE_DEFAULT;
+        hprop.Type = heapType;
         hprop.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
         hprop.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
         hprop.CreationNodeMask = 0;

+ 2 - 1
DX12Buffer.h

@@ -21,7 +21,8 @@ namespace Framework
         DLLEXPORT virtual ~DX12Buffer();
         //! Copies the data into the buffer if it has changed
         DLLEXPORT virtual void copyToGPU(__int64 byteCount = -1) override;
-        DLLEXPORT void createBufferWithoutData(D3D12_RESOURCE_STATES states);
+        DLLEXPORT void createBufferWithoutData(D3D12_RESOURCE_STATES states,
+            D3D12_HEAP_TYPE heapType = D3D12_HEAP_TYPE_DEFAULT);
         //! Returns the buffer
         DLLEXPORT ID3D12Resource* zBuffer() const;
     };

+ 25 - 68
DX12GraphicsApi.cpp

@@ -35,7 +35,6 @@ DirectX12::DirectX12()
       infoQueue(0),
       directCommandQueue(0),
       swapChain(0),
-      rtvHeap(0),
       backBufferIndex(0),
       tearing(0),
       viewPort(0),
@@ -107,7 +106,6 @@ DirectX12::~DirectX12()
     {
         if (backBuffer[i]) backBuffer[i]->Release();
     }
-    if (rtvHeap) rtvHeap->Release();
     if (swapChain) swapChain->Release();
     if (infoQueue) infoQueue->Release();
     if (device)
@@ -153,9 +151,8 @@ void Framework::DirectX12::renderKamera(
     {
         setPipeline(new DX12Pipeline());
     }
-    // TODO
-    // directCommandQueue->getCommandList()->RSSetViewports(
-    //     1, (D3D12_VIEWPORT*)zKamera->zViewPort());
+    directCommandQueue->zCommandList()->RSSetViewports(
+        1, (D3D12_VIEWPORT*)zKamera->zViewPort());
     Mat4<float> identity = Mat4<float>::identity();
 
     World3D* w = zKamera->zWorld();
@@ -222,9 +219,12 @@ void Framework::DirectX12::renderKamera(
     tlas->endUpdate();
     if (defaultRayGenerationShaderFunction)
     {
-        sbt->setShaderInputs(defaultRayGenerationShaderFunction,
-            {zTarget->zResource()->GetGPUVirtualAddress(),
-                tlas->zResultBuffer()->zBuffer()->GetGPUVirtualAddress()});
+        sbt->setShaderInput(defaultRayGenerationShaderFunction,
+            renderTargetInputOffset,
+            zTarget->zResource()->GetGPUVirtualAddress());
+        sbt->setShaderInput(defaultRayGenerationShaderFunction,
+            tlasInputOffset,
+            tlas->zResultBuffer()->zBuffer()->GetGPUVirtualAddress());
     }
     sbt->setGlobalDescriptorHeap(dynamic_cast<DX12GlobalDescriptorHeap*>(
         globalDescriptorHeap->getThis()));
@@ -234,10 +234,12 @@ void Framework::DirectX12::renderKamera(
 
     D3D12_DISPATCH_RAYS_DESC desc;
     sbt->fillDispatchRaysDesc(&desc);
+    desc.Width = zTarget->zImage()->getWidth();
+    desc.Height = zTarget->zImage()->getHeight();
+    desc.Depth = 1;
     directCommandQueue->zCommandList()->SetPipelineState1(
         pipeline->zPipelineState());
     directCommandQueue->zCommandList()->DispatchRays(&desc);
-    // TODO: call ray tracing
 }
 
 void Framework::DirectX12::initializePipeline()
@@ -249,29 +251,33 @@ void Framework::DirectX12::initializePipeline()
                 sizeof(DX12DefaultRayGenerationShaderBytes));
         // RayGen from RayGen.hlsl
         DX12ShaderSignature* rayGenSignature = new DX12ShaderSignature();
-        rayGenSignature->addRegisterUsageLinkedToShaderBindingTable(
-            DX12_SHADER_REGISTER_U_UNORDERED_ACCESS, 0);
+        renderTargetInputOffset
+            = rayGenSignature->addRegisterUsageLinkedToShaderBindingTable(
+                DX12_SHADER_REGISTER_U_UNORDERED_ACCESS, 0);
         rayGenSignature->addRegisterUsageLinkedToDescriptorHeap(
             0, DX12_SHADER_REGISTER_U_UNORDERED_ACCESS, 1);
-        rayGenSignature->addRegisterUsageLinkedToShaderBindingTable(
-            DX12_SHADER_REGISTER_T_SHADER_RESOURCE, 0);
-        defaultRayGenerationShaderFunction
-            = new DX12ShaderFunction("RayGen", rayGenSignature);
+        tlasInputOffset
+            = rayGenSignature->addRegisterUsageLinkedToShaderBindingTable(
+                DX12_SHADER_REGISTER_T_SHADER_RESOURCE, 0);
+        defaultRayGenerationShaderFunction = new DX12ShaderFunction(
+            "RayGen", rayGenSignature, DX12_SHADER_FUNCTION_TYPE_RAY_GEN);
         rayGenShader->addFunction(defaultRayGenerationShaderFunction);
         pipeline->addShader(rayGenShader);
 
         DX12Shader* missShader = new DX12Shader(
             DX12DefaultMissShaderBytes, sizeof(DX12DefaultMissShaderBytes));
         // Miss from Miss.hlsl
-        missShader->addFunction(
-            new DX12ShaderFunction("Miss", new DX12ShaderSignature()));
+        missShader->addFunction(new DX12ShaderFunction(
+            "Miss", new DX12ShaderSignature(), DX12_SHADER_FUNCTION_TYPE_MISS));
         pipeline->addShader(missShader);
 
         DX12Shader* hitShader = new DX12Shader(
             DX12DefaultMissShaderBytes, sizeof(DX12DefaultMissShaderBytes));
         // ClosestHit from Hit.hlsl
         DX12ShaderFunction* closestHitFunction
-            = new DX12ShaderFunction("ClosestHit", new DX12ShaderSignature());
+            = new DX12ShaderFunction("ClosestHit",
+                new DX12ShaderSignature(),
+                DX12_SHADER_FUNCTION_TYPE_CLOSEST_HIT);
         missShader->addFunction(closestHitFunction);
         pipeline->addShader(hitShader);
 
@@ -294,8 +300,7 @@ void Framework::DirectX12::fillShaderBindingTable(
 {
     if (defaultHitGroup)
     {
-        zShaderBindingTable->setHitGroupShaderInputs(
-            instanceIndex, defaultHitGroup, {});
+        zShaderBindingTable->addHitGroup(defaultHitGroup);
     }
 }
 
@@ -593,29 +598,6 @@ void DirectX12::initialize(
     factory->MakeWindowAssociation(
         fenster->getWindowHandle(), DXGI_MWA_NO_ALT_ENTER);
 
-    D3D12_DESCRIPTOR_HEAP_DESC rtvhdesc = {};
-    rtvhdesc.NumDescriptors = 2; // back buffer count
-    rtvhdesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
-    rtvhdesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
-    res = device->CreateDescriptorHeap(
-        &rtvhdesc, __uuidof(ID3D12DescriptorHeap), (void**)&rtvHeap);
-    if (FAILED(res))
-    {
-        factory->Release();
-        Logging::error() << "ERROR: CreateDescriptorHeap returned " << res
-                         << "\n";
-        WMessageBox(fenster->getWindowHandle(),
-            new Text("Fehler"),
-            new Text("CreateDescriptorHeap ist Fehlgeschlagen."),
-            MB_ICONERROR);
-        return;
-    }
-
-    auto rtvDescriptorSize = device->GetDescriptorHandleIncrementSize(
-        D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
-    D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle(
-        rtvHeap->GetCPUDescriptorHandleForHeapStart());
-
     for (int i = 0; i < 2; i++)
     {
         ID3D12Resource* backBuffer;
@@ -632,11 +614,7 @@ void DirectX12::initialize(
             return;
         }
 
-        device->CreateRenderTargetView(backBuffer, nullptr, rtvHandle);
-
         this->backBuffer[i] = backBuffer;
-
-        rtvHandle.ptr += rtvDescriptorSize;
     }
 
     Image* renderTargetImage = new Image();
@@ -797,27 +775,6 @@ void DirectX12::beginFrame(bool fill2D, bool fill3D, int fillColor)
     // directCommandQueue->getCommandList()->ResourceBarrier(1, &barrier);
 
     if (fill2D) uiTexture->zImage()->setColor(fillColor);
-    if (fill3D)
-    {
-        float color[4];
-        // Setup the color to clear the buffer.
-        color[0] = ((fillColor >> 16) & 0xFF) / 255.f; // R
-        color[1] = ((fillColor >> 8) & 0xFF) / 255.f;  // G
-        color[2] = (fillColor & 0xFF) / 255.f;         // B
-        color[3] = ((fillColor >> 24) & 0xFF) / 255.f; // A
-
-        auto rtvDescriptorSize = device->GetDescriptorHandleIncrementSize(
-            D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
-        D3D12_CPU_DESCRIPTOR_HANDLE rtv
-            = rtvHeap->GetCPUDescriptorHandleForHeapStart();
-        rtv.ptr += rtvDescriptorSize * backBufferIndex;
-
-        // TODO
-        // directCommandQueue->getCommandList()->OMSetRenderTargets(1, &rtv, 0,
-        // 0);
-        //  directCommandQueue->getCommandList()->ClearRenderTargetView(
-        //      rtv, color, 0, 0);
-    }
 
     uiTexture->updateTextur();
 

+ 2 - 1
DX12GraphicsApi.h

@@ -52,7 +52,6 @@ namespace Framework
         ID3D12InfoQueue* infoQueue;
         DX12DirectCommandQueue* directCommandQueue;
         IDXGISwapChain4* swapChain;
-        ID3D12DescriptorHeap* rtvHeap;
         ID3D12Resource* backBuffer[2];
         int backBufferIndex;
         int tearing;
@@ -74,6 +73,8 @@ namespace Framework
         DX12GlobalDescriptorHeap* globalDescriptorHeap;
         DX12ShaderHitGroup* defaultHitGroup;
         DX12ShaderFunction* defaultRayGenerationShaderFunction;
+        int* renderTargetInputOffset;
+        int* tlasInputOffset;
 
     public:
         DLLEXPORT DirectX12();

+ 561 - 90
DX12Shader.cpp

@@ -9,7 +9,8 @@ using namespace Framework;
 Framework::DX12ShaderSignature::DX12ShaderSignature()
     : ReferenceCounter(),
       signature(0),
-      changed(1)
+      changed(1),
+      shaderBindingTableParamCount(0)
 {}
 
 Framework::DX12ShaderSignature::~DX12ShaderSignature()
@@ -18,13 +19,50 @@ Framework::DX12ShaderSignature::~DX12ShaderSignature()
     {
         signature->Release();
     }
+    for (DX12ShaderRegisterUsage* usage : descriptorHeapBindings)
+    {
+        delete usage;
+    }
+    for (DX12ShaderRegisterUsage* usage : bindingTableBindings)
+    {
+        delete usage;
+    }
 }
 
-void Framework::DX12ShaderSignature::addRegisterUsageLinkedToShaderBindingTable(
+int* Framework::DX12ShaderSignature::addRegisterUsageLinkedToShaderBindingTable(
     DX12ShaderRegister registerType, int registerIndex, int spaceIndex)
 {
-    addRegisterUsageLinkedToDescriptorHeap(
-        -1, registerType, registerIndex, spaceIndex);
+    for (DX12ShaderRegisterUsage* usage : descriptorHeapBindings)
+    {
+        if (usage->registerType == registerType
+            && usage->registerIndex == registerIndex
+            && usage->spaceIndex == spaceIndex)
+        {
+            Logging::error()
+                << "Duplicate register usage in root signature: "
+                << registerType << " " << registerIndex << " " << spaceIndex;
+            throw std::invalid_argument(
+                "Duplicate register usage in root signature");
+        }
+    }
+    for (DX12ShaderRegisterUsage* usage : bindingTableBindings)
+    {
+        if (usage->registerType == registerType
+            && usage->registerIndex == registerIndex
+            && usage->spaceIndex == spaceIndex)
+        {
+            Logging::error()
+                << "Duplicate register usage in root signature: "
+                << registerType << " " << registerIndex << " " << spaceIndex;
+            throw std::invalid_argument(
+                "Duplicate register usage in root signature");
+        }
+    }
+    DX12ShaderRegisterUsage* usage = new DX12ShaderRegisterUsage{
+        registerType, registerIndex, spaceIndex, -1, 0};
+    bindingTableBindings.add(usage);
+    changed = 1;
+    return &usage->bindingTableIndex;
 }
 
 void Framework::DX12ShaderSignature::addRegisterUsageLinkedToDescriptorHeap(
@@ -33,28 +71,45 @@ void Framework::DX12ShaderSignature::addRegisterUsageLinkedToDescriptorHeap(
     int registerIndex,
     int spaceIndex)
 {
-    // register usages sould be sorted by registerType -> spaceIndex ->
+    if (descriptorHeapIndex < 0)
+    {
+        Logging::error() << "descriptorHeapIndex can not be below 0";
+        throw std::invalid_argument("descriptorHeapIndex can not be below 0");
+    }
+    for (DX12ShaderRegisterUsage* usage : descriptorHeapBindings)
+    {
+        if (usage->registerType == registerType
+            && usage->registerIndex == registerIndex
+            && usage->spaceIndex == spaceIndex)
+        {
+            Logging::error()
+                << "Duplicate register usage in root signature: "
+                << registerType << " " << registerIndex << " " << spaceIndex;
+            throw std::invalid_argument(
+                "Duplicate register usage in root signature");
+        }
+    }
+    // descriptor heap bindings sould be sorted by registerType -> spaceIndex ->
     // registerIndex
-    ArrayIterator<DX12ShaderRegisterUsage> it = registerUsages.begin();
+    ArrayIterator<DX12ShaderRegisterUsage*> it = descriptorHeapBindings.begin();
     bool found = 0;
     while (it)
     {
-        const DX12ShaderRegisterUsage& usage = it.val();
-        if (usage.registerType > registerType)
+        if (it->registerType > registerType)
         {
             found = 1;
             break;
         }
-        if (usage.registerType == registerType)
+        if (it->registerType == registerType)
         {
-            if (usage.spaceIndex > spaceIndex)
+            if (it->spaceIndex > spaceIndex)
             {
                 found = 1;
                 break;
             }
-            if (usage.spaceIndex == spaceIndex)
+            if (it->spaceIndex == spaceIndex)
             {
-                if (usage.registerIndex >= registerIndex)
+                if (it->registerIndex >= registerIndex)
                 {
                     found = 1;
                     break;
@@ -65,20 +120,21 @@ void Framework::DX12ShaderSignature::addRegisterUsageLinkedToDescriptorHeap(
     }
     if (found)
     {
-        if (it.val().registerIndex == registerIndex)
+        if (it->registerIndex == registerIndex)
         {
             Logging::error()
                 << "Duplicate register usage in root signature: "
                 << registerType << " " << registerIndex << " " << spaceIndex;
-            return;
+            throw std::invalid_argument(
+                "Duplicate register usage in root signature");
         }
-        it.addBefore(
-            {registerType, registerIndex, spaceIndex, descriptorHeapIndex});
+        it.addBefore(new DX12ShaderRegisterUsage{
+            registerType, registerIndex, spaceIndex, descriptorHeapIndex, 0});
     }
     else
     {
-        registerUsages.add(
-            {registerType, registerIndex, spaceIndex, descriptorHeapIndex});
+        descriptorHeapBindings.add(new DX12ShaderRegisterUsage{
+            registerType, registerIndex, spaceIndex, descriptorHeapIndex, 0});
     }
     changed = 1;
 }
@@ -96,87 +152,88 @@ void Framework::DX12ShaderSignature::createSignature(ID3D12Device5* zDevice,
         signature->Release();
         signature = 0;
     }
+    int paramCount = (descriptorHeapBindings.getEntryCount() > 0 ? 1 : 0)
+                   + bindingTableBindings.getEntryCount();
     D3D12_ROOT_PARAMETER* descriptorTable
-        = new D3D12_ROOT_PARAMETER[registerUsages.getEntryCount()];
-    D3D12_DESCRIPTOR_RANGE* descriptorRanges
-        = new D3D12_DESCRIPTOR_RANGE[registerUsages.getEntryCount()];
-    ArrayIterator<DX12ShaderRegisterUsage> it = registerUsages.begin();
+        = new D3D12_ROOT_PARAMETER[paramCount];
     int index = 0;
-    while (it)
+    D3D12_DESCRIPTOR_RANGE* descriptorRanges = 0;
+    if (descriptorHeapBindings.getEntryCount())
     {
-        const auto& usage = it.val();
-        if (usage.descriptorHeapIndex >= 0)
+        descriptorTable[index].ParameterType
+            = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
+        descriptorTable[index].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
+        descriptorRanges = new D3D12_DESCRIPTOR_RANGE[descriptorHeapBindings
+                .getEntryCount()];
+        ArrayIterator<DX12ShaderRegisterUsage*> it
+            = descriptorHeapBindings.begin();
+        while (it)
         {
-            descriptorTable[index].ParameterType
-                = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
-            descriptorTable[index].ShaderVisibility
-                = D3D12_SHADER_VISIBILITY_ALL;
-            descriptorTable[index].DescriptorTable.NumDescriptorRanges
-                = registerUsages.getEntryCount();
-            D3D12_DESCRIPTOR_RANGE* range = &descriptorRanges[index];
-            switch (usage.registerType)
+            it->bindingTableIndex = 0;
+            D3D12_DESCRIPTOR_RANGE& range = descriptorRanges[index];
+            switch (it->registerType)
             {
             case DX12_SHADER_REGISTER_B_CONST_BUFFER:
-                range->RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV;
+                range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV;
                 break;
             case DX12_SHADER_REGISTER_T_SHADER_RESOURCE:
-                range->RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
+                range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
                 break;
             case DX12_SHADER_REGISTER_U_UNORDERED_ACCESS:
-                range->RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
+                range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
                 break;
-            default:
-                Logging::error() << "Unknown register type for root signature: "
-                                 << usage.registerType;
-                range->RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
             }
-            ArrayIterator<DX12ShaderRegisterUsage> next = it.next();
+            ArrayIterator<DX12ShaderRegisterUsage*> next = it.next();
             int size = 1;
-            while (next && next.val().registerType == usage.registerType
-                   && next.val().spaceIndex == usage.spaceIndex
-                   && next.val().registerIndex == usage.registerIndex + size
-                   && next.val().descriptorHeapIndex
-                          == usage.descriptorHeapIndex + size)
+            while (
+                next && next->registerType == it->registerType
+                && next->spaceIndex == it->spaceIndex
+                && next->registerIndex == it->registerIndex + size
+                && next->descriptorHeapIndex == it->descriptorHeapIndex + size)
             {
                 ++size;
                 it = next;
+                it->bindingTableIndex = 0;
                 ++next;
             }
-            range->NumDescriptors = size;
-            range->BaseShaderRegister = usage.registerIndex;
-            range->RegisterSpace = usage.spaceIndex;
-            range->OffsetInDescriptorsFromTableStart
-                = usage.descriptorHeapIndex;
-            descriptorTable[index].DescriptorTable.pDescriptorRanges = range;
+            range.NumDescriptors = size;
+            range.BaseShaderRegister = it->registerIndex;
+            range.RegisterSpace = it->spaceIndex;
+            range.OffsetInDescriptorsFromTableStart = it->descriptorHeapIndex;
+            ++it;
+            ++index;
         }
-        else
+        descriptorTable[index].DescriptorTable.pDescriptorRanges
+            = descriptorRanges;
+        descriptorTable[index].DescriptorTable.NumDescriptorRanges = index;
+        index = 1;
+    }
+    for (DX12ShaderRegisterUsage* usage : bindingTableBindings)
+    {
+        usage->bindingTableIndex = index;
+        switch (usage->registerType)
         {
-            switch (usage.registerType)
-            {
-            case DX12_SHADER_REGISTER_B_CONST_BUFFER:
-                descriptorTable[index].ParameterType
-                    = D3D12_ROOT_PARAMETER_TYPE_CBV;
-                break;
-            case DX12_SHADER_REGISTER_T_SHADER_RESOURCE:
-                descriptorTable[index].ParameterType
-                    = D3D12_ROOT_PARAMETER_TYPE_SRV;
-                break;
-            case DX12_SHADER_REGISTER_U_UNORDERED_ACCESS:
-                descriptorTable[index].ParameterType
-                    = D3D12_ROOT_PARAMETER_TYPE_UAV;
-                break;
-            }
-            descriptorTable[index].ShaderVisibility
-                = D3D12_SHADER_VISIBILITY_ALL;
-            descriptorTable[index].Descriptor.ShaderRegister
-                = usage.registerIndex;
-            descriptorTable[index].Descriptor.RegisterSpace = usage.spaceIndex;
+        case DX12_SHADER_REGISTER_B_CONST_BUFFER:
+            descriptorTable[index].ParameterType
+                = D3D12_ROOT_PARAMETER_TYPE_CBV;
+            break;
+        case DX12_SHADER_REGISTER_T_SHADER_RESOURCE:
+            descriptorTable[index].ParameterType
+                = D3D12_ROOT_PARAMETER_TYPE_SRV;
+            break;
+        case DX12_SHADER_REGISTER_U_UNORDERED_ACCESS:
+            descriptorTable[index].ParameterType
+                = D3D12_ROOT_PARAMETER_TYPE_UAV;
+            break;
         }
-        ++it;
+        descriptorTable[index].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
+        descriptorTable[index].Descriptor.ShaderRegister = usage->registerIndex;
+        descriptorTable[index].Descriptor.RegisterSpace = usage->spaceIndex;
         ++index;
     }
+    shaderBindingTableParamCount = index;
     D3D12_ROOT_SIGNATURE_DESC rootDesc = {};
-    rootDesc.NumParameters = index;
+    rootDesc.NumParameters = shaderBindingTableParamCount;
     rootDesc.pParameters = descriptorTable;
     rootDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_LOCAL_ROOT_SIGNATURE;
     ID3DBlob* pSigBlob = 0;
@@ -202,6 +259,7 @@ void Framework::DX12ShaderSignature::createSignature(ID3D12Device5* zDevice,
         pErrorBlob->Release();
     }
     delete[] descriptorRanges;
+    delete[] descriptorTable;
 }
 
 ID3D12RootSignature* Framework::DX12ShaderSignature::zSignature() const
@@ -209,17 +267,24 @@ ID3D12RootSignature* Framework::DX12ShaderSignature::zSignature() const
     return signature;
 }
 
-const Array<DX12ShaderRegisterUsage>&
-Framework::DX12ShaderSignature::getRegisterUsages() const
+const Array<DX12ShaderRegisterUsage*>&
+Framework::DX12ShaderSignature::getDescriptorHeapBindings() const
 {
-    return registerUsages;
+    return descriptorHeapBindings;
 }
 
-Framework::DX12ShaderFunction::DX12ShaderFunction(
-    const Text& functionName, DX12ShaderSignature* signature)
+int Framework::DX12ShaderSignature::gerShaderBindingTableParamCount() const
+{
+    return shaderBindingTableParamCount;
+}
+
+Framework::DX12ShaderFunction::DX12ShaderFunction(const Text& functionName,
+    DX12ShaderSignature* signature,
+    DX12ShaderFunctionType functionType)
     : ReferenceCounter(),
       functionName(functionName),
       signature(signature),
+      functionType(functionType),
       exportDesc(new D3D12_EXPORT_DESC())
 {
     wchar_t* wc = new wchar_t[functionName.getLength() + 1];
@@ -252,6 +317,11 @@ D3D12_EXPORT_DESC* Framework::DX12ShaderFunction::zExportDesc() const
     return exportDesc;
 }
 
+DX12ShaderFunctionType Framework::DX12ShaderFunction::getFunctionType() const
+{
+    return functionType;
+}
+
 Framework::DX12Shader::DX12Shader(
     const unsigned char* shaderBytes, int shaderBytesSize)
     : ReferenceCounter(),
@@ -540,6 +610,23 @@ D3D12_HIT_GROUP_DESC* Framework::DX12ShaderHitGroup::zHitGroupDesc() const
     return hitGroupDesc;
 }
 
+DX12ShaderSignature* Framework::DX12ShaderHitGroup::zSignature() const
+{
+    if (closestHitShaderFunction)
+    {
+        return closestHitShaderFunction->zSignature();
+    }
+    if (anyHitShaderFunction)
+    {
+        return anyHitShaderFunction->zSignature();
+    }
+    if (intersectionShaderFunction)
+    {
+        return intersectionShaderFunction->zSignature();
+    }
+    return 0;
+}
+
 Framework::DX12Pipeline::DX12Pipeline()
     : ReferenceCounter(),
       emptyGlobalRootSignature(0),
@@ -689,9 +776,9 @@ void Framework::DX12Pipeline::createPipelineState(ID3D12Device5* zDevice,
         = D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG;
     subobjects[index].pDesc = &shaderDesc;
     index++;
+    functionsWithoutHitGroups.clear();
     // 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())
@@ -890,6 +977,22 @@ DX12GlobalDescriptorHeap* Framework::DX12Pipeline::createGlobalDescriptorHeap()
     return new DX12GlobalDescriptorHeap(dynamic_cast<DX12Pipeline*>(getThis()));
 }
 
+const RCArray<DX12Shader>& Framework::DX12Pipeline::getShaders() const
+{
+    return shaders;
+}
+
+const Array<const DX12ShaderFunction*>&
+Framework::DX12Pipeline::getFunctionsWithoutHitGroups() const
+{
+    return functionsWithoutHitGroups;
+}
+
+const RCArray<DX12ShaderHitGroup>& Framework::DX12Pipeline::getHitGroups() const
+{
+    return hitGroups;
+}
+
 Framework::DX12GlobalDescriptorHeap::DX12GlobalDescriptorHeap(
     DX12Pipeline* pipeline)
     : ReferenceCounter(),
@@ -919,18 +1022,19 @@ void Framework::DX12GlobalDescriptorHeap::addInput(
     {
         for (DX12ShaderFunction* function : shader->getFunctions())
         {
-            for (const DX12ShaderRegisterUsage& usage :
-                function->zSignature()->getRegisterUsages())
+            for (const DX12ShaderRegisterUsage* usage :
+                function->zSignature()->getDescriptorHeapBindings())
             {
-                if (usage.descriptorHeapIndex == registerInputs.getEntryCount())
+                if (usage->descriptorHeapIndex
+                    == registerInputs.getEntryCount())
                 {
-                    if (usage.registerType != type)
+                    if (usage->registerType != type)
                     {
                         Logging::error()
                             << "Register type mismatch for register index "
-                            << usage.registerIndex << ", space index "
-                            << usage.spaceIndex << ". Expected register type: "
-                            << usage.registerType
+                            << usage->registerIndex << ", space index "
+                            << usage->spaceIndex << ". Expected register type: "
+                            << usage->registerType
                             << ", given register type: " << type
                             << ". The register type is specified in the "
                                "signature of shader function '"
@@ -1127,5 +1231,372 @@ Framework::DX12GlobalDescriptorHeap::zDescriptorHeap() const
 Framework::DX12ShaderBindingTable::DX12ShaderBindingTable(
     DX12Pipeline* pipeline)
     : ReferenceCounter(),
-      pipeline(pipeline)
-{}
+      pipeline(pipeline),
+      shaderBindingTableBuffer(0),
+      globalDescriptorHeap(0),
+      rayGenRecordSize(0),
+      rayGenCount(0),
+      missRecordSize(0),
+      missCount(0),
+      callableRecordSize(0),
+      callableCount(0),
+      hitGroupRecordSize(0),
+      hitGroupCount(0),
+      tableBuffer(0),
+      tableBufferSize(0),
+      nextHitGroupOffset(0),
+      stateObjectProperties(0)
+{
+    pipeline->zPipelineState()->QueryInterface(
+        __uuidof(ID3D12StateObjectProperties), (void**)&stateObjectProperties);
+}
+
+Framework::DX12ShaderBindingTable::~DX12ShaderBindingTable()
+{
+    stateObjectProperties->Release();
+    if (pipeline)
+    {
+        pipeline->release();
+    }
+    if (shaderBindingTableBuffer)
+    {
+        shaderBindingTableBuffer->release();
+    }
+    if (globalDescriptorHeap)
+    {
+        globalDescriptorHeap->release();
+    }
+    for (const char* buffer : tempBuffers)
+    {
+        delete[] buffer;
+    }
+}
+
+void Framework::DX12ShaderBindingTable::setGlobalDescriptorHeap(
+    DX12GlobalDescriptorHeap* zGlobalDescriptorHeap)
+{
+    if (this->globalDescriptorHeap)
+    {
+        this->globalDescriptorHeap->release();
+    }
+    this->globalDescriptorHeap = zGlobalDescriptorHeap;
+    if (this->globalDescriptorHeap)
+    {
+        this->globalDescriptorHeap->getThis();
+    }
+}
+
+void Framework::DX12ShaderBindingTable::startUpdate()
+{
+    if (shaderBindingTableBuffer)
+    {
+        shaderBindingTableBuffer->zBuffer()->Map(0, 0, (void**)&tableBuffer);
+        tableBufferSize = (int)shaderBindingTableBuffer->getElementCount()
+                        * shaderBindingTableBuffer->getElementLength();
+    }
+    else
+    {
+        tableBuffer = 0;
+        tableBufferSize = 0;
+    }
+    rayGenRecordSize = 0;
+    rayGenCount = 0;
+    missRecordSize = 0;
+    missCount = 0;
+    callableRecordSize = 0;
+    callableCount = 0;
+    for (const DX12ShaderFunction* function :
+        pipeline->getFunctionsWithoutHitGroups())
+    {
+        DX12ShaderSignature* signature = function->zSignature();
+        if (function->getFunctionType() == DX12_SHADER_FUNCTION_TYPE_RAY_GEN)
+        {
+            if (rayGenRecordSize < signature->gerShaderBindingTableParamCount())
+            {
+                rayGenRecordSize = signature->gerShaderBindingTableParamCount();
+            }
+            rayGenCount++;
+        }
+        else if (function->getFunctionType() == DX12_SHADER_FUNCTION_TYPE_MISS)
+        {
+            if (missRecordSize < signature->gerShaderBindingTableParamCount())
+            {
+                missRecordSize = signature->gerShaderBindingTableParamCount();
+            }
+            missCount++;
+        }
+        else if (function->getFunctionType()
+                 == DX12_SHADER_FUNCTION_TYPE_CALLABLE)
+        {
+            if (callableRecordSize
+                < signature->gerShaderBindingTableParamCount())
+            {
+                callableRecordSize
+                    = signature->gerShaderBindingTableParamCount();
+            }
+            callableCount++;
+        }
+    }
+    rayGenRecordSize = ROUND_UP_POWER_OF_2(
+        D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT + rayGenRecordSize * 8,
+        D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT);
+    missRecordSize = ROUND_UP_POWER_OF_2(
+        D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT + missRecordSize * 8,
+        D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT);
+    callableRecordSize = ROUND_UP_POWER_OF_2(
+        D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT + callableRecordSize * 8,
+        D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT);
+    hitGroupCount = 0;
+    hitGroupRecordSize = 0;
+    for (DX12ShaderHitGroup* hitGroup : pipeline->getHitGroups())
+    {
+        DX12ShaderSignature* signature = hitGroup->zSignature();
+        if (hitGroupRecordSize < signature->gerShaderBindingTableParamCount())
+        {
+            hitGroupRecordSize = signature->gerShaderBindingTableParamCount();
+        }
+        hitGroupCount++;
+    }
+    hitGroupRecordSize = ROUND_UP_POWER_OF_2(
+        D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT + hitGroupRecordSize * 8,
+        D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT);
+    nextHitGroupOffset
+        = rayGenRecordSize * rayGenCount + missRecordSize * missCount;
+}
+
+void Framework::DX12ShaderBindingTable::set(int index, void* data, int size)
+{
+    if (tableBufferSize >= index + size)
+    {
+        memcpy(tableBuffer + index, data, size);
+    }
+    else
+    {
+        index -= tableBufferSize;
+        ArrayIterator<char*> it = tempBuffers.begin();
+        while (it && 2048 >= index + size)
+        {
+            index -= 2048;
+            it++;
+        }
+        while (2048 >= index + size)
+        {
+            char* newBuffer = new char[2048];
+            memset(newBuffer, 0, 2048);
+            tempBuffers.add(newBuffer);
+            index -= 2048;
+        }
+        // because the buffer size is allways rounded up to multiples
+        // of 32 and the size written at once is always 8 or 32 it
+        // should never be possible to have a negative index here
+        assert(index >= 0);
+        if (!it)
+        {
+            char* newBuffer = new char[2048];
+            memset(newBuffer, 0, 2048);
+            tempBuffers.add(newBuffer);
+            memcpy(newBuffer + index, data, size);
+        }
+        else
+        {
+            memcpy(it.val() + index, data, size);
+        }
+    }
+}
+
+void Framework::DX12ShaderBindingTable::setShaderInput(
+    DX12ShaderFunction* zFunction, int* offsetPointer, __int64 gpuAddress)
+{
+    int index = 0;
+    for (const DX12ShaderFunction* pf :
+        pipeline->getFunctionsWithoutHitGroups())
+    {
+        if (pf == zFunction)
+        {
+            break;
+        }
+        if (pf->getFunctionType() == zFunction->getFunctionType())
+        {
+            index++;
+        }
+    }
+    int offset = 0;
+    if (zFunction->getFunctionType() == DX12_SHADER_FUNCTION_TYPE_RAY_GEN)
+    {
+        offset = index * rayGenRecordSize;
+    }
+    else if (zFunction->getFunctionType() == DX12_SHADER_FUNCTION_TYPE_MISS)
+    {
+        offset = rayGenRecordSize * rayGenCount + index * missRecordSize;
+    }
+    else if (zFunction->getFunctionType() == DX12_SHADER_FUNCTION_TYPE_CALLABLE)
+    {
+        offset = rayGenRecordSize * rayGenCount + missRecordSize * missCount
+               + index * callableRecordSize;
+    }
+    else
+    {
+        throw std::logic_error("setShaderInput can only be used for ray "
+                               "generation, miss, and callable "
+                               "shader functions");
+    }
+    offset += D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT
+            + sizeof(__int64) * *offsetPointer;
+    set(offset, &gpuAddress, sizeof(__int64));
+}
+
+int Framework::DX12ShaderBindingTable::addHitGroup(
+    DX12ShaderHitGroup* zHitGroup)
+{
+    int index = nextHitGroupOffset;
+    set(index,
+        stateObjectProperties->GetShaderIdentifier(
+            zHitGroup->zHitGroupDesc()->HitGroupExport),
+        D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT);
+    if (zHitGroup->zSignature()->getDescriptorHeapBindings().getEntryCount()
+        > 0)
+    {
+        D3D12_GPU_DESCRIPTOR_HANDLE gpuAddress
+            = globalDescriptorHeap->zDescriptorHeap()
+                  ->GetGPUDescriptorHandleForHeapStart();
+        set(index + D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT,
+            &gpuAddress.ptr,
+            sizeof(__int64));
+    }
+    nextHitGroupOffset += hitGroupRecordSize;
+    return index + D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT;
+}
+
+void Framework::DX12ShaderBindingTable::setHitGroupShaderInput(
+    int hitGroupOffset, int* offsetPointer, __int64 gpuAddress)
+{
+    set(hitGroupOffset + sizeof(__int64) * *offsetPointer,
+        &gpuAddress,
+        sizeof(__int64));
+}
+
+void Framework::DX12ShaderBindingTable::endUpdate(ID3D12Device5* zDevice)
+{
+    int rayTracingIndex = 0;
+    int missIndex = 0;
+    int callableIndex = 0;
+    for (const DX12ShaderFunction* function :
+        pipeline->getFunctionsWithoutHitGroups())
+    {
+        int offset = -1;
+        DX12ShaderSignature* signature = function->zSignature();
+        if (function->getFunctionType() == DX12_SHADER_FUNCTION_TYPE_RAY_GEN)
+        {
+            offset = rayTracingIndex * rayGenRecordSize;
+            rayTracingIndex++;
+        }
+        else if (function->getFunctionType() == DX12_SHADER_FUNCTION_TYPE_MISS)
+        {
+            offset
+                = rayGenRecordSize * rayGenCount + missIndex * missRecordSize;
+            missIndex++;
+        }
+        else if (function->getFunctionType()
+                 == DX12_SHADER_FUNCTION_TYPE_CALLABLE)
+        {
+            offset = rayGenRecordSize * rayGenCount + missRecordSize * missCount
+                   + callableIndex * callableRecordSize;
+            callableIndex++;
+        }
+        if (offset >= 0)
+        {
+            set(offset,
+                stateObjectProperties->GetShaderIdentifier(
+                    function->zExportDesc()->Name),
+                D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT);
+            if (function->zSignature()
+                    ->getDescriptorHeapBindings()
+                    .getEntryCount()
+                > 0)
+            {
+                D3D12_GPU_DESCRIPTOR_HANDLE gpuAddress
+                    = globalDescriptorHeap->zDescriptorHeap()
+                          ->GetGPUDescriptorHandleForHeapStart();
+                set(offset + D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT,
+                    &gpuAddress.ptr,
+                    sizeof(__int64));
+            }
+        }
+    }
+    if (nextHitGroupOffset > tableBufferSize)
+    {
+        DX12Buffer* newBuffer
+            = new DX12Buffer(1, zDevice, D3D12_RESOURCE_FLAG_NONE);
+        newBuffer->setLength(ROUND_UP_POWER_OF_2(nextHitGroupOffset, 256));
+        newBuffer->createBufferWithoutData(
+            D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_HEAP_TYPE_UPLOAD);
+        void* newTableBuffer = 0;
+        newBuffer->zBuffer()->Map(0, 0, (void**)&newTableBuffer);
+        int sizeToCopy = nextHitGroupOffset;
+        int index = 0;
+        if (tableBufferSize > 0)
+        {
+            memcpy(newTableBuffer, tableBuffer, tableBufferSize);
+            sizeToCopy -= tableBufferSize;
+            index = tableBufferSize;
+        }
+        for (char* buffer : tempBuffers)
+        {
+            int bytesToCopy = sizeToCopy < 2048 ? sizeToCopy : 2048;
+            memcpy((char*)newTableBuffer + index, buffer, bytesToCopy);
+            sizeToCopy -= bytesToCopy;
+            index += bytesToCopy;
+            if (sizeToCopy == 0)
+            {
+                break;
+            }
+        }
+        assert(sizeToCopy == 0);
+        newBuffer->zBuffer()->Unmap(0, 0);
+        if (shaderBindingTableBuffer)
+        {
+            shaderBindingTableBuffer->zBuffer()->Unmap(0, 0);
+            shaderBindingTableBuffer->release();
+        }
+        shaderBindingTableBuffer = newBuffer;
+    }
+    else
+    {
+        shaderBindingTableBuffer->zBuffer()->Unmap(0, 0);
+    }
+}
+
+void Framework::DX12ShaderBindingTable::fillDispatchRaysDesc(
+    D3D12_DISPATCH_RAYS_DESC* dispatchRaysDesc)
+{
+    dispatchRaysDesc->RayGenerationShaderRecord.SizeInBytes
+        = rayGenCount * rayGenRecordSize;
+    dispatchRaysDesc->RayGenerationShaderRecord.StartAddress
+        = shaderBindingTableBuffer->zBuffer()->GetGPUVirtualAddress();
+
+    dispatchRaysDesc->MissShaderTable.SizeInBytes = missCount * missRecordSize;
+    dispatchRaysDesc->MissShaderTable.StartAddress
+        = shaderBindingTableBuffer->zBuffer()->GetGPUVirtualAddress()
+        + rayGenCount * rayGenRecordSize;
+    dispatchRaysDesc->MissShaderTable.StrideInBytes = missRecordSize;
+
+    dispatchRaysDesc->HitGroupTable.SizeInBytes
+        = hitGroupCount * hitGroupRecordSize;
+    dispatchRaysDesc->HitGroupTable.StartAddress
+        = shaderBindingTableBuffer->zBuffer()->GetGPUVirtualAddress()
+        + rayGenCount * rayGenRecordSize + missCount * missRecordSize;
+    dispatchRaysDesc->HitGroupTable.StrideInBytes = hitGroupRecordSize;
+
+    dispatchRaysDesc->CallableShaderTable.SizeInBytes
+        = callableCount * callableRecordSize;
+    dispatchRaysDesc->CallableShaderTable.StartAddress
+        = shaderBindingTableBuffer->zBuffer()->GetGPUVirtualAddress()
+        + rayGenCount * rayGenRecordSize + missCount * missRecordSize
+        + hitGroupCount * hitGroupRecordSize;
+    dispatchRaysDesc->CallableShaderTable.StrideInBytes = callableRecordSize;
+}
+
+DX12Pipeline* Framework::DX12ShaderBindingTable::zPipeline() const
+{
+    return pipeline;
+}

+ 93 - 11
DX12Shader.h

@@ -8,6 +8,7 @@ struct ID3D12GraphicsCommandList;
 struct D3D12_INPUT_ELEMENT_DESC;
 struct D3D12_ROOT_PARAMETER1;
 struct D3D12_CONSTANT_BUFFER_VIEW_DESC;
+struct ID3D12StateObjectProperties;
 
 namespace Framework
 {
@@ -28,6 +29,7 @@ namespace Framework
         int registerIndex;
         int spaceIndex;
         int descriptorHeapIndex;
+        int bindingTableIndex;
     };
 
     class DX12ShaderHeap;
@@ -36,8 +38,10 @@ namespace Framework
     {
     private:
         ID3D12RootSignature* signature;
-        Array<DX12ShaderRegisterUsage> registerUsages;
+        Array<DX12ShaderRegisterUsage*> descriptorHeapBindings;
+        Array<DX12ShaderRegisterUsage*> bindingTableBindings;
         bool changed;
+        int shaderBindingTableParamCount;
 
     public:
         DX12ShaderSignature();
@@ -53,8 +57,12 @@ namespace Framework
          * \param registerIndex the register index e.g. 1 for : register(b1)
          * \param spaceIndex the optional space index e.g. 3 for : register(b1,
          * space3)
+         * \return pointer to the offset in the shader binding table where this
+         * parameter needs to be placed. This pointer is only valid after the
+         * call to createSignature() and should be used to fill the shader
+         * binding table with the correct GPU addresses of the resources.
          */
-        void addRegisterUsageLinkedToShaderBindingTable(
+        int* addRegisterUsageLinkedToShaderBindingTable(
             DX12ShaderRegister registerType,
             int registerIndex,
             int spaceIndex = 0);
@@ -63,6 +71,10 @@ namespace Framework
          * either this function or addRegisterUsageLinkedToDescriptorHeap must
          * be called to link the register usage to the shader binding table or
          * descriptor heap.
+         * For optimal performance the registers that are linked to the
+         * descriptor heaps should be consecutive and use consecutive descriptor
+         * heap spaces. Example: register(b3), register(b4), register(b5) linked
+         * to descriptor heap index 2, 3, 4.
          *
          * \param descriptorHeapIndex the index in the descriptor heap witch
          * contains the resource for this register usage
@@ -82,7 +94,19 @@ namespace Framework
         void createSignature(ID3D12Device5* zDevice,
             PFN_D3D12_SERIALIZE_ROOT_SIGNATURE pfnD3D12SerializeRootSignature);
         ID3D12RootSignature* zSignature() const;
-        const Array<DX12ShaderRegisterUsage>& getRegisterUsages() const;
+        const Array<DX12ShaderRegisterUsage*>&
+        getDescriptorHeapBindings() const;
+        int gerShaderBindingTableParamCount() const;
+    };
+
+    enum DX12ShaderFunctionType
+    {
+        DX12_SHADER_FUNCTION_TYPE_RAY_GEN,
+        DX12_SHADER_FUNCTION_TYPE_INTERSECTION,
+        DX12_SHADER_FUNCTION_TYPE_ANY_HIT,
+        DX12_SHADER_FUNCTION_TYPE_CLOSEST_HIT,
+        DX12_SHADER_FUNCTION_TYPE_MISS,
+        DX12_SHADER_FUNCTION_TYPE_CALLABLE,
     };
 
     class DX12ShaderFunction : public ReferenceCounter
@@ -91,14 +115,17 @@ namespace Framework
         Text functionName;
         DX12ShaderSignature* signature;
         D3D12_EXPORT_DESC* exportDesc;
+        DX12ShaderFunctionType functionType;
 
     public:
-        DX12ShaderFunction(
-            const Text& functionName, DX12ShaderSignature* signature);
+        DX12ShaderFunction(const Text& functionName,
+            DX12ShaderSignature* signature,
+            DX12ShaderFunctionType functionType);
         ~DX12ShaderFunction();
         const Text& getFunctionName() const;
         DX12ShaderSignature* zSignature() const;
         D3D12_EXPORT_DESC* zExportDesc() const;
+        DX12ShaderFunctionType getFunctionType() const;
     };
 
     class DX12Shader : public ReferenceCounter
@@ -147,6 +174,7 @@ namespace Framework
         int getPayloadSize() const;
         int getAttributeSize() const;
         D3D12_HIT_GROUP_DESC* zHitGroupDesc() const;
+        DX12ShaderSignature* zSignature() const;
     };
 
     class DX12ShaderBindingTable;
@@ -157,6 +185,7 @@ namespace Framework
     private:
         RCArray<DX12Shader> shaders;
         RCArray<DX12ShaderHitGroup> hitGroups;
+        Array<const DX12ShaderFunction*> functionsWithoutHitGroups;
         ID3D12RootSignature* emptyGlobalRootSignature;
         ID3D12RootSignature* emptyLocalRootSignature;
         ID3D12StateObject* pipelineState;
@@ -174,6 +203,9 @@ namespace Framework
         DX12ShaderBindingTable* createShaderBindingTable();
         DX12GlobalDescriptorHeap* createGlobalDescriptorHeap();
         const RCArray<DX12Shader>& getShaders() const;
+        const Array<const DX12ShaderFunction*>&
+        getFunctionsWithoutHitGroups() const;
+        const RCArray<DX12ShaderHitGroup>& getHitGroups() const;
     }; // namespace Framework
 
     struct DX12ShaderRegisterInput
@@ -217,9 +249,15 @@ namespace Framework
         int rayGenCount;
         int missRecordSize;
         int missCount;
+        int callableRecordSize;
+        int callableCount;
         int hitGroupRecordSize;
         int hitGroupCount;
-        bool changed;
+        char* tableBuffer;
+        int tableBufferSize;
+        Array<char*> tempBuffers;
+        int nextHitGroupOffset;
+        ID3D12StateObjectProperties* stateObjectProperties;
 
     public:
         DX12ShaderBindingTable(DX12Pipeline* pipeline);
@@ -227,11 +265,55 @@ namespace Framework
         void setGlobalDescriptorHeap(
             DX12GlobalDescriptorHeap* zGlobalDescriptorHeap);
         void startUpdate();
-        void setShaderInputs(DX12ShaderFunction* zFunction,
-            std::initializer_list<unsigned __int64> gpuAddresses);
-        void setHitGroupShaderInputs(int instanceIndex,
-            DX12ShaderHitGroup* zHitGroup,
-            std::initializer_list<unsigned __int64> gpuAddresses);
+
+    private:
+        void set(int index, void* data, int size);
+
+    public:
+        /**
+         * sets inputs for shader outside of any hit groups for the current
+         * update of the shader binding table.
+         *
+         * \param zFunction the sample shader function for which the inputs are
+         * set. The function must be part of the pipeline.
+         * \param offsetPointer pointer for the offset in the shader binding
+         * table witch was obtained by adding the register usage to the
+         * segnature of the shader function by calling
+         * DX12ShaderSignature::addRegisterUsageLinkedToShaderBindingTable.
+         * \param gpuAddress the parameter to be placed in the shader binding
+         * table for this input. This is usually the GPU address of a buffer or
+         * texture.
+         */
+        void setShaderInput(DX12ShaderFunction* zFunction,
+            int* offsetPointer,
+            __int64 gpuAddress);
+        /**
+         * adds a hit group to the current update of the shader binding table.
+         * each hit group mus be readded for each update of the shader binding
+         * table.
+         *
+         * \param zHitGroup the hit group to be added. The hit group must be
+         * part of the pipeline.
+         * \return the index of the hit group in the shader binding table. This
+         * index can be used to set the inputs for this hit group by calling
+         * setHitGroupShaderInput.
+         */
+        int addHitGroup(DX12ShaderHitGroup* zHitGroup);
+        /**
+         * sets a specific input for a previously added hitgroup.
+         *
+         * \param hitGroupOffset the hit group offset returned by addHitGroup
+         * for the hit group for which the input is set.
+         * \param offsetPointer pointer for the offset in the shader binding
+         * table witch was obtained by adding the register usage to the
+         * segnature of the shader function by calling
+         * DX12ShaderSignature::addRegisterUsageLinkedToShaderBindingTable.
+         * \param gpuAddress the parameter to be placed in the shader binding
+         * table for this input. This is usually the GPU address of a buffer or
+         * texture.
+         */
+        void setHitGroupShaderInput(
+            int hitGroupOffset, int* offsetPointer, __int64 gpuAddress);
         void endUpdate(ID3D12Device5* zDevice);
         void fillDispatchRaysDesc(D3D12_DISPATCH_RAYS_DESC* dispatchRaysDesc);
         DX12Pipeline* zPipeline() const;