Bläddra i källkod

add support for textures to directx 12 raytracing

Kolja Strohm 3 veckor sedan
förälder
incheckning
2366580e3b
19 ändrade filer med 784 tillägg och 127 borttagningar
  1. 1 0
      .gitignore
  2. 53 5
      DX12BLAS.cpp
  3. 10 1
      DX12BLAS.h
  4. 83 1
      DX12BLASModel.cpp
  5. 10 0
      DX12BLASModel.h
  6. 137 13
      DX12GraphicsApi.cpp
  7. 13 1
      DX12GraphicsApi.h
  8. 23 0
      DX12SamplerState.cpp
  9. 20 0
      DX12SamplerState.h
  10. 254 62
      DX12Shader.cpp
  11. 39 4
      DX12Shader.h
  12. 47 1
      Framework Tests/Camera3D.cpp
  13. 2 0
      Framework.vcxproj
  14. 6 0
      Framework.vcxproj.filters
  15. 29 1
      Hit.hlsl
  16. 40 1
      Model3D.cpp
  17. 9 2
      Model3D.h
  18. 6 30
      TextureList.cpp
  19. 2 5
      TextureList.h

+ 1 - 0
.gitignore

@@ -222,3 +222,4 @@ ModelManifest.xml
 /DX12HitShader.h
 /DX12MissShader.h
 /DX12RayGenShader.h
+/enc_temp_folder

+ 53 - 5
DX12BLAS.cpp

@@ -14,6 +14,9 @@ Framework::DX12BLAS::DX12BLAS(
           zDevice,
           dynamic_cast<DX12CommandQueue*>(zDirectQueue->getThis()),
           D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)),
+      vertexDataBuffer(0),
+      indexBuffer(0),
+      polygonSizeBuffer(0),
       zDevice(zDevice),
       zDirectQueue(zDirectQueue),
       geometryDesc(new D3D12_RAYTRACING_GEOMETRY_DESC())
@@ -23,21 +26,51 @@ Framework::DX12BLAS::~DX12BLAS()
 {
     scratchBuffer->release();
     resultBuffer->release();
+    if (vertexDataBuffer)
+    {
+        vertexDataBuffer->release();
+    }
+    if (indexBuffer)
+    {
+        indexBuffer->release();
+    }
+    if (polygonSizeBuffer)
+    {
+        polygonSizeBuffer->release();
+    }
     delete geometryDesc;
 }
 
-void Framework::DX12BLAS::build(
-    DX12Buffer* vertexBuffer, DX12Buffer* indexBuffer)
+void Framework::DX12BLAS::build(DX12Buffer* zVertexBuffer,
+    DX12Buffer* vertexDataBuffer,
+    DX12Buffer* indexBuffer,
+    DX12Buffer* polygonSizeBuffer)
 {
+    if (this->indexBuffer)
+    {
+        this->indexBuffer->release();
+    }
+    if (this->vertexDataBuffer)
+    {
+        this->vertexDataBuffer->release();
+    }
+    if (this->polygonSizeBuffer)
+    {
+        this->polygonSizeBuffer->release();
+    }
+    this->vertexDataBuffer = vertexDataBuffer;
+    this->indexBuffer = indexBuffer;
+    this->polygonSizeBuffer = polygonSizeBuffer;
+
     memset(geometryDesc, 0, sizeof(D3D12_RAYTRACING_GEOMETRY_DESC));
     geometryDesc->Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES;
     geometryDesc->Flags = D3D12_RAYTRACING_GEOMETRY_FLAG_NONE;
     geometryDesc->Triangles.VertexBuffer.StartAddress
-        = vertexBuffer->zBuffer()->GetGPUVirtualAddress();
+        = zVertexBuffer->zBuffer()->GetGPUVirtualAddress();
     geometryDesc->Triangles.VertexBuffer.StrideInBytes
-        = vertexBuffer->getElementLength();
+        = zVertexBuffer->getElementLength();
     geometryDesc->Triangles.VertexCount
-        = (unsigned)vertexBuffer->getElementCount();
+        = (unsigned)zVertexBuffer->getElementCount();
     geometryDesc->Triangles.VertexFormat = DXGI_FORMAT_R32G32B32_FLOAT;
     geometryDesc->Triangles.IndexBuffer
         = indexBuffer->zBuffer()->GetGPUVirtualAddress();
@@ -94,3 +127,18 @@ Framework::DX12Buffer* Framework::DX12BLAS::zResultBuffer() const
 {
     return resultBuffer;
 }
+
+Framework::DX12Buffer* Framework::DX12BLAS::zVertexDataBuffer() const
+{
+    return vertexDataBuffer;
+}
+
+Framework::DX12Buffer* Framework::DX12BLAS::zIndexBuffer() const
+{
+    return indexBuffer;
+}
+
+Framework::DX12Buffer* Framework::DX12BLAS::zPolygonSizeBuffer() const
+{
+    return polygonSizeBuffer;
+}

+ 10 - 1
DX12BLAS.h

@@ -15,6 +15,9 @@ namespace Framework
     private:
         DX12Buffer* scratchBuffer;
         DX12Buffer* resultBuffer;
+        DX12Buffer* vertexDataBuffer;
+        DX12Buffer* indexBuffer;
+        DX12Buffer* polygonSizeBuffer;
 
         ID3D12Device5* zDevice;
         DX12DirectCommandQueue* zDirectQueue;
@@ -23,8 +26,14 @@ namespace Framework
     public:
         DX12BLAS(ID3D12Device5* zDevice, DX12DirectCommandQueue* zDirectQueue);
         ~DX12BLAS();
-        void build(DX12Buffer* vertexBuffer, DX12Buffer* indexBuffer);
+        void build(DX12Buffer* zVertexBuffer,
+            DX12Buffer* vertexDataBuffer,
+            DX12Buffer* indexBuffer,
+            DX12Buffer* polygonSizeBuffer);
         DX12Buffer* zScratchBuffer() const;
         DX12Buffer* zResultBuffer() const;
+        DX12Buffer* zVertexDataBuffer() const;
+        DX12Buffer* zIndexBuffer() const;
+        DX12Buffer* zPolygonSizeBuffer() const;
     };
 } // namespace Framework

+ 83 - 1
DX12BLASModel.cpp

@@ -11,7 +11,9 @@ Framework::DX12BLASModel::DX12BLASModel(Model3DData* zModelData,
       zDevice(zDevice),
       zDirectQueue(zDirectQueue),
       vertexBuffers(0),
+      vertexDataBuffers(0),
       indexBuffers(0),
+      polygonSizeBuffers(0),
       blasList(0)
 {}
 
@@ -21,10 +23,18 @@ Framework::DX12BLASModel::~DX12BLASModel()
     {
         vertexBuffers->release();
     }
+    if (vertexDataBuffers)
+    {
+        vertexDataBuffers->release();
+    }
     if (indexBuffers)
     {
         indexBuffers->release();
     }
+    if (polygonSizeBuffers)
+    {
+        polygonSizeBuffers->release();
+    }
     if (blasList)
     {
         blasList->release();
@@ -55,6 +65,13 @@ void Framework::DX12BLASModel::calculateBuffers()
     memset(boneIndexBuffers, 0, sizeof(int*) * (maxBoneId + 1));
     int* boneIndexCount = new int[maxBoneId + 1];
     memset(boneIndexCount, 0, sizeof(int) * (maxBoneId + 1));
+    DX2VertexData** boneVertexDatabuffers = new DX2VertexData*[maxBoneId + 1];
+    memset(boneVertexDatabuffers, 0, sizeof(DX2VertexData*) * (maxBoneId + 1));
+    int** bonePolygonSize = new int*[maxBoneId + 1];
+    memset(bonePolygonSize, 0, sizeof(int*) * (maxBoneId + 1));
+    ArrayIterator<Polygon3D*> polygonIterator = zModelData->getPolygons();
+    int polygonSize = polygonIterator->indexAnz;
+    int polygonIndex = 0;
     for (int i = 0; i < indexCount; i += 3)
     { // for each triangle
         int b1 = -1;
@@ -83,10 +100,23 @@ void Framework::DX12BLASModel::calculateBuffers()
                 {
                     boneVertexBuffers[bone] = new Vec3<float>[vertexCount];
                 }
+                if (!boneVertexDatabuffers[bone])
+                {
+                    boneVertexDatabuffers[bone]
+                        = new DX2VertexData[vertexCount];
+                }
                 if (!boneIndexBuffers[bone])
                 {
                     boneIndexBuffers[bone] = new int[indexCount];
                 }
+                if (!bonePolygonSize[bone])
+                {
+                    bonePolygonSize[bone]
+                        = new int[zModelData->getPolygonCount()];
+                    memset(bonePolygonSize[bone],
+                        0,
+                        sizeof(int) * zModelData->getPolygonCount());
+                }
                 for (int j = 0; j < 3; j++)
                 { // add the vertecies and indices of the triangle to the
                   // buffers of the bone
@@ -96,12 +126,27 @@ void Framework::DX12BLASModel::calculateBuffers()
                             = boneVertexCount[bone];
                         boneVertexBuffers[bone][boneVertexCount[bone]]
                             = vertexBuffer[indexBuffer[i + j]].pos;
+                        boneVertexDatabuffers[bone][boneVertexCount[bone]]
+                            .texcoord = vertexBuffer[indexBuffer[i + j]].tPos;
+                        boneVertexDatabuffers[bone][boneVertexCount[bone]]
+                            .normal = vertexBuffer[indexBuffer[i + j]].normal;
                         boneVertexCount[bone]++;
                     }
                     boneIndexBuffers[bone][boneIndexCount[bone]]
                         = boneIndexMapping[bone][indexBuffer[i + j]];
                     boneIndexCount[bone]++;
                 }
+                bonePolygonSize[bone][polygonIndex]++;
+            }
+        }
+        polygonSize -= 3;
+        if (polygonSize <= 0)
+        {
+            polygonIndex++;
+            polygonIterator++;
+            if (polygonIterator)
+            {
+                polygonSize = polygonIterator->indexAnz;
             }
         }
     }
@@ -111,16 +156,26 @@ void Framework::DX12BLASModel::calculateBuffers()
     {
         vertexBuffers = new RCArray<DX12Buffer>();
     }
+    if (!vertexDataBuffers)
+    {
+        vertexDataBuffers = new RCArray<DX12Buffer>();
+    }
     if (!indexBuffers)
     {
         indexBuffers = new RCArray<DX12Buffer>();
     }
+    if (!polygonSizeBuffers)
+    {
+        polygonSizeBuffers = new RCArray<DX12Buffer>();
+    }
     if (!blasList)
     {
         blasList = new RCArray<DX12BLAS>();
     }
     vertexBuffers->clear();
+    vertexDataBuffers->clear();
     indexBuffers->clear();
+    polygonSizeBuffers->clear();
     blasList->clear();
     boneIds.clear();
     for (int i = 0; i <= maxBoneId; i++)
@@ -136,6 +191,16 @@ void Framework::DX12BLASModel::calculateBuffers()
             vertexBuffer->copyToGPU();
             vertexBuffers->add(vertexBuffer);
 
+            DX12Buffer* vertexDataBuffer = new DX12Buffer(sizeof(DX2VertexData),
+                zDevice,
+                dynamic_cast<DX12CommandQueue*>(zDirectQueue->getThis()),
+                0);
+            vertexDataBuffer->setData(boneVertexDatabuffers[i], true);
+            vertexDataBuffer->setLength(
+                boneVertexCount[i] * sizeof(DX2VertexData));
+            vertexDataBuffer->copyToGPU();
+            vertexDataBuffers->add(vertexDataBuffer);
+
             DX12Buffer* indexBuffer = new DX12Buffer(sizeof(int),
                 zDevice,
                 dynamic_cast<DX12CommandQueue*>(zDirectQueue->getThis()),
@@ -145,20 +210,37 @@ void Framework::DX12BLASModel::calculateBuffers()
             indexBuffer->copyToGPU();
             indexBuffers->add(indexBuffer);
 
+            DX12Buffer* polygonSizeBuffer = new DX12Buffer(sizeof(int),
+                zDevice,
+                dynamic_cast<DX12CommandQueue*>(zDirectQueue->getThis()),
+                0);
+            polygonSizeBuffer->setData(bonePolygonSize[i], true);
+            polygonSizeBuffer->setLength(
+                zModelData->getPolygonCount() * sizeof(int));
+            polygonSizeBuffer->copyToGPU();
+            polygonSizeBuffers->add(polygonSizeBuffer);
+
             DX12BLAS* blas = new DX12BLAS(zDevice, zDirectQueue);
-            blas->build(vertexBuffer, indexBuffer);
+            blas->build(vertexBuffer,
+                dynamic_cast<DX12Buffer*>(vertexDataBuffer->getThis()),
+                dynamic_cast<DX12Buffer*>(indexBuffer->getThis()),
+                dynamic_cast<DX12Buffer*>(polygonSizeBuffer->getThis()));
             blasList->add(blas);
             boneIds.add(i);
         }
         delete[] boneIndexMapping[i];
         delete[] boneVertexBuffers[i];
         delete[] boneIndexBuffers[i];
+        delete[] boneVertexDatabuffers[i];
+        delete[] bonePolygonSize[i];
     }
     delete[] boneIndexMapping;
     delete[] boneVertexBuffers;
     delete[] boneVertexCount;
     delete[] boneIndexBuffers;
     delete[] boneIndexCount;
+    delete[] boneVertexDatabuffers;
+    delete[] bonePolygonSize;
     zModelData->unlock();
 }
 

+ 10 - 0
DX12BLASModel.h

@@ -3,19 +3,29 @@
 #include "Array.h"
 #include "DX12BLAS.h"
 #include "DX12Buffer.h"
+#include "Vec2.h"
+#include "Vec3.h"
 
 namespace Framework
 {
     class Model3DData;
     class DX12DirectCommandQueue;
 
+    struct DX2VertexData
+    {
+        Vec2<float> texcoord;
+        Vec3<float> normal;
+    };
+
     class DX12BLASModel : public ReferenceCounter
     {
     private:
         Model3DData* zModelData;
         ID3D12Device5* zDevice;
         RCArray<DX12Buffer>* vertexBuffers;
+        RCArray<DX12Buffer>* vertexDataBuffers;
         RCArray<DX12Buffer>* indexBuffers;
+        RCArray<DX12Buffer>* polygonSizeBuffers;
         DX12DirectCommandQueue* zDirectQueue;
         RCArray<DX12BLAS>* blasList;
         Array<int> boneIds;

+ 137 - 13
DX12GraphicsApi.cpp

@@ -13,6 +13,7 @@
 #include "DX12HitShader.h"
 #include "DX12MissShader.h"
 #include "DX12RayGenShader.h"
+#include "DX12SamplerState.h"
 #include "DX12Shader.h"
 #include "DX12Texture.h"
 #include "DX12TLAS.h"
@@ -52,8 +53,15 @@ DirectX12::DirectX12()
       pfnD3D12SerializeRootSignature(0),
       pipeline(0),
       globalDescriptorHeap(0),
+      textureDescriptorHeap(0),
+      samplerDescriptorHeap(0),
       defaultHitGroup(0),
-      defaultRayGenerationShaderFunction(0)
+      defaultRayGenerationShaderFunction(0),
+      defaultSamplerState(0),
+      sbtTextureIdBufferOffset(0),
+      sbtIndexBufferOffset(0),
+      sbtVertexDataBufferOffset(0),
+      sbtPolygonSizeBufferOffset(0)
 {
     for (int i = 0; i < 2; i++)
         backBuffer[i] = 0;
@@ -90,6 +98,14 @@ DirectX12::~DirectX12()
     {
         globalDescriptorHeap->release();
     }
+    if (textureDescriptorHeap)
+    {
+        textureDescriptorHeap->release();
+    }
+    if (samplerDescriptorHeap)
+    {
+        samplerDescriptorHeap->release();
+    }
     if (pipeline)
     {
         pipeline->release();
@@ -103,6 +119,10 @@ DirectX12::~DirectX12()
     {
         rayGenSettingsBuffer->release();
     }
+    if (defaultSamplerState)
+    {
+        defaultSamplerState->release();
+    }
     texturRegister->release();
     if (uiTexture) uiTexture->release();
     if (defaultKamera) defaultKamera->release();
@@ -200,6 +220,11 @@ void Framework::DirectX12::renderKamera(
     sbt->startUpdate();
     int objectIndex = 0;
     int instanceIndex = 0;
+    // descriptor heaps must be set before filling the shader binding table with
+    // hit groups
+    sbt->setGlobalDescriptorHeap(globalDescriptorHeap);
+    sbt->setTextureDescriptorHeap(textureDescriptorHeap);
+    sbt->setSamplerDescriptorHeap(samplerDescriptorHeap);
     w->render([this, &tlas, &objectIndex, &instanceIndex, &identity, &sbt](
                   Model3D* obj) {
         obj->calculateMatrices(identity, matrixBuffer);
@@ -221,9 +246,9 @@ void Framework::DirectX12::renderKamera(
                 sizeof(float) * 12);
             boneIds++;
             instanceIndex++;
+            fillShaderBindingTable(sbt, obj, objectIndex, blas);
+            objectIndex++;
         }
-        fillShaderBindingTable(sbt, obj, objectIndex);
-        objectIndex++;
     });
     tlas->endUpdate();
     settings.inverseProjection = zKamera->getInverseProjectionMatrix();
@@ -241,10 +266,10 @@ void Framework::DirectX12::renderKamera(
         globalDescriptorHeap->updateTLASInput(
             3, DX12_SHADER_REGISTER_T_SHADER_RESOURCE, tlas);
     }
-    sbt->setGlobalDescriptorHeap(globalDescriptorHeap);
     sbt->endUpdate(device, directCommandQueue);
-    ID3D12DescriptorHeap* heaps[] = {globalDescriptorHeap->zDescriptorHeap()};
-    directCommandQueue->zCommandList()->SetDescriptorHeaps(1, heaps);
+    ID3D12DescriptorHeap* heaps[] = {globalDescriptorHeap->zDescriptorHeap(),
+        samplerDescriptorHeap->zDescriptorHeap()};
+    directCommandQueue->zCommandList()->SetDescriptorHeaps(2, heaps);
 
     D3D12_DISPATCH_RAYS_DESC desc;
     sbt->fillDispatchRaysDesc(&desc);
@@ -288,10 +313,29 @@ void Framework::DirectX12::initializePipeline()
         DX12Shader* hitShader = new DX12Shader(
             DX12DefaultHitShaderBytes, sizeof(DX12DefaultHitShaderBytes));
         // ClosestHit from Hit.hlsl
-        DX12ShaderFunction* closestHitFunction
-            = new DX12ShaderFunction("ClosestHit",
-                new DX12ShaderSignature(),
-                DX12_SHADER_FUNCTION_TYPE_CLOSEST_HIT);
+        DX12ShaderSignature* hitSignature = new DX12ShaderSignature();
+        hitSignature->addRegisterUsageLinkedToDescriptorHeap(
+            0, DX12_SHADER_REGISTER_S_SAMPLER, 0, 0, SAMPLER_DESCRIPTOR_HEAP);
+        hitSignature->addRegisterUsageLinkedToDescriptorHeap(1,
+            DX12_SHADER_REGISTER_T_SHADER_RESOURCE,
+            0,
+            1,
+            TEXTURE_DESCRIPTOR_HEAP,
+            1);
+        sbtTextureIdBufferOffset
+            = hitSignature->addRegisterUsageLinkedToShaderBindingTable(
+                DX12_SHADER_REGISTER_T_SHADER_RESOURCE, 1, 2);
+        sbtIndexBufferOffset
+            = hitSignature->addRegisterUsageLinkedToShaderBindingTable(
+                DX12_SHADER_REGISTER_T_SHADER_RESOURCE, 1, 3);
+        sbtVertexDataBufferOffset
+            = hitSignature->addRegisterUsageLinkedToShaderBindingTable(
+                DX12_SHADER_REGISTER_T_SHADER_RESOURCE, 1, 4);
+        sbtPolygonSizeBufferOffset
+            = hitSignature->addRegisterUsageLinkedToShaderBindingTable(
+                DX12_SHADER_REGISTER_T_SHADER_RESOURCE, 1, 5);
+        DX12ShaderFunction* closestHitFunction = new DX12ShaderFunction(
+            "ClosestHit", hitSignature, DX12_SHADER_FUNCTION_TYPE_CLOSEST_HIT);
         hitShader->addFunction(closestHitFunction);
         pipeline->addShader(hitShader);
 
@@ -320,14 +364,65 @@ void Framework::DirectX12::initializeGlobalDescriptorHeap()
     globalDescriptorHeap->updateDescriptorHeap(device);
 }
 
+void Framework::DirectX12::initializeTextureDescriptorHeap()
+{
+    for (Texture* tex : *texturRegister->zTextures())
+    {
+        textureDescriptorHeap->addTextureInput(
+            DX12_SHADER_REGISTER_T_SHADER_RESOURCE, tex);
+    }
+
+    textureDescriptorHeap->updateDescriptorHeap(device);
+}
+
+void Framework::DirectX12::initializeSamplerDescriptorHeap()
+{
+    if (!defaultSamplerState)
+    {
+        defaultSamplerState = new DX12SamplerState();
+        (*defaultSamplerState)->Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
+        (*defaultSamplerState)->AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
+        (*defaultSamplerState)->AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
+        (*defaultSamplerState)->AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
+        (*defaultSamplerState)->MipLODBias = 0;
+        (*defaultSamplerState)->MaxAnisotropy = 1;
+        (*defaultSamplerState)->ComparisonFunc = D3D12_COMPARISON_FUNC_NONE;
+        (*defaultSamplerState)->BorderColor[0] = 0.f;
+        (*defaultSamplerState)->BorderColor[1] = 0.f;
+        (*defaultSamplerState)->BorderColor[2] = 0.f;
+        (*defaultSamplerState)->BorderColor[3] = 0.f;
+        (*defaultSamplerState)->MinLOD = 0.0f;
+        (*defaultSamplerState)->MaxLOD = D3D12_FLOAT32_MAX;
+    }
+    samplerDescriptorHeap->addSamplerInput(defaultSamplerState);
+
+    samplerDescriptorHeap->updateDescriptorHeap(device);
+}
+
 void Framework::DirectX12::fillShaderBindingTable(
     DX12ShaderBindingTable* zShaderBindingTable,
     Model3D* zModel,
-    int instanceIndex)
+    int instanceIndex,
+    const DX12BLAS* zBLAS)
 {
     if (defaultHitGroup)
     {
-        zShaderBindingTable->addHitGroup(defaultHitGroup);
+        int hitGroupOffset = zShaderBindingTable->addHitGroup(defaultHitGroup);
+        zShaderBindingTable->setHitGroupShaderInput(hitGroupOffset,
+            sbtIndexBufferOffset,
+            zBLAS->zIndexBuffer()->zBuffer()->GetGPUVirtualAddress());
+        zShaderBindingTable->setHitGroupShaderInput(hitGroupOffset,
+            sbtVertexDataBufferOffset,
+            zBLAS->zVertexDataBuffer()->zBuffer()->GetGPUVirtualAddress());
+        zModel->zTexture()->updateTextureIndexBuffer(this);
+        zShaderBindingTable->setHitGroupShaderInput(hitGroupOffset,
+            sbtTextureIdBufferOffset,
+            dynamic_cast<DX12Buffer*>(zModel->zTexture()->zTextureIndexBuffer())
+                ->zBuffer()
+                ->GetGPUVirtualAddress());
+        zShaderBindingTable->setHitGroupShaderInput(hitGroupOffset,
+            sbtPolygonSizeBufferOffset,
+            zBLAS->zPolygonSizeBuffer()->zBuffer()->GetGPUVirtualAddress());
     }
 }
 
@@ -913,6 +1008,12 @@ Texture* DirectX12::createOrGetTexture(
     if (b) ret->setImageZ(b);
     texturRegister->addTexture(dynamic_cast<Texture*>(ret->getThis()), name);
     ret->updateTextur();
+    if (textureDescriptorHeap)
+    {
+        textureDescriptorHeap->addTextureInput(
+            DX12_SHADER_REGISTER_T_SHADER_RESOURCE, ret);
+        textureDescriptorHeap->updateDescriptorHeap(device);
+    }
     // directCommandQueue->execute();
     cs.unlock();
     return ret;
@@ -971,9 +1072,32 @@ void Framework::DirectX12::setPipeline(DX12Pipeline* pipeline)
             {
                 globalDescriptorHeap->release();
             }
-            globalDescriptorHeap = pipeline->createGlobalDescriptorHeap();
+            globalDescriptorHeap
+                = pipeline->createGlobalDescriptorHeap(GLOBAL_DESCRIPTOR_HEAP);
             initializeGlobalDescriptorHeap();
         }
+        if (!textureDescriptorHeap
+            || textureDescriptorHeap->zPipeline() != pipeline)
+        {
+            if (textureDescriptorHeap)
+            {
+                textureDescriptorHeap->release();
+            }
+            textureDescriptorHeap
+                = pipeline->createGlobalDescriptorHeap(TEXTURE_DESCRIPTOR_HEAP);
+            initializeTextureDescriptorHeap();
+        }
+        if (!samplerDescriptorHeap
+            || samplerDescriptorHeap->zPipeline() != pipeline)
+        {
+            if (samplerDescriptorHeap)
+            {
+                samplerDescriptorHeap->release();
+            }
+            samplerDescriptorHeap
+                = pipeline->createGlobalDescriptorHeap(SAMPLER_DESCRIPTOR_HEAP);
+            initializeSamplerDescriptorHeap();
+        }
     }
 }
 

+ 13 - 1
DX12GraphicsApi.h

@@ -44,6 +44,8 @@ namespace Framework
     class DX12ShaderHitGroup;
     class DX12ShaderFunction;
     class Cam3D;
+    class DX12BLAS;
+    class DX12SamplerState;
 
     struct RayGenerationSettings
     {
@@ -88,8 +90,15 @@ namespace Framework
         PFN_D3D12_SERIALIZE_ROOT_SIGNATURE pfnD3D12SerializeRootSignature;
         DX12Pipeline* pipeline;
         DX12GlobalDescriptorHeap* globalDescriptorHeap;
+        DX12GlobalDescriptorHeap* textureDescriptorHeap;
+        DX12GlobalDescriptorHeap* samplerDescriptorHeap;
         DX12ShaderHitGroup* defaultHitGroup;
         DX12ShaderFunction* defaultRayGenerationShaderFunction;
+        DX12SamplerState* defaultSamplerState;
+        int* sbtTextureIdBufferOffset;
+        int* sbtIndexBufferOffset;
+        int* sbtVertexDataBufferOffset;
+        int* sbtPolygonSizeBufferOffset;
 
     public:
         DLLEXPORT DirectX12();
@@ -101,10 +110,13 @@ namespace Framework
             Cam3D* zKamera, DX12Texture* zTarget, bool guiVisible);
         DLLEXPORT virtual void initializePipeline();
         DLLEXPORT virtual void initializeGlobalDescriptorHeap();
+        DLLEXPORT virtual void initializeTextureDescriptorHeap();
+        DLLEXPORT virtual void initializeSamplerDescriptorHeap();
         DLLEXPORT virtual void fillShaderBindingTable(
             DX12ShaderBindingTable* zShaderBindingTable,
             Model3D* zModel,
-            int objectIndex);
+            int objectIndex,
+            const DX12BLAS* zBLAS);
 
     public:
         DLLEXPORT void initialize(NativeWindow* fenster,

+ 23 - 0
DX12SamplerState.cpp

@@ -0,0 +1,23 @@
+#include "DX12SamplerState.h"
+
+#include "d3dx12.h"
+
+Framework::DX12SamplerState::DX12SamplerState()
+    : ReferenceCounter(),
+      samplerDesc(new D3D12_SAMPLER_DESC())
+{}
+
+Framework::DX12SamplerState::~DX12SamplerState()
+{
+    delete samplerDesc;
+}
+
+D3D12_SAMPLER_DESC* Framework::DX12SamplerState::zSamplerDesc() const
+{
+    return samplerDesc;
+}
+
+D3D12_SAMPLER_DESC* Framework::DX12SamplerState::operator->()
+{
+    return samplerDesc;
+}

+ 20 - 0
DX12SamplerState.h

@@ -0,0 +1,20 @@
+#pragma once
+
+#include "ReferenceCounter.h"
+
+struct D3D12_SAMPLER_DESC;
+
+namespace Framework
+{
+    class DX12SamplerState : public ReferenceCounter
+    {
+    private:
+        D3D12_SAMPLER_DESC* samplerDesc;
+
+    public:
+        DLLEXPORT DX12SamplerState();
+        DLLEXPORT ~DX12SamplerState();
+        DLLEXPORT D3D12_SAMPLER_DESC* zSamplerDesc() const;
+        DLLEXPORT D3D12_SAMPLER_DESC* operator->();
+    };
+} // namespace Framework

+ 254 - 62
DX12Shader.cpp

@@ -1,6 +1,7 @@
 #include "DX12Shader.h"
 
 #include "DX12CommandQueue.h"
+#include "DX12SamplerState.h"
 #include "DX12Texture.h"
 #include "DX12TLAS.h"
 #include "Logging.h"
@@ -33,6 +34,13 @@ Framework::DX12ShaderSignature::~DX12ShaderSignature()
 int* Framework::DX12ShaderSignature::addRegisterUsageLinkedToShaderBindingTable(
     DX12ShaderRegister registerType, int registerIndex, int spaceIndex)
 {
+    if (registerType == DX12_SHADER_REGISTER_S_SAMPLER)
+    {
+        Logging::error() << "Sampler register usage can not be linked to "
+                            "shader binding table";
+        throw std::logic_error(
+            "Sampler register usage can not be linked to shader binding table");
+    }
     for (DX12ShaderRegisterUsage* usage : descriptorHeapBindings)
     {
         if (usage->registerType == registerType
@@ -59,8 +67,14 @@ int* Framework::DX12ShaderSignature::addRegisterUsageLinkedToShaderBindingTable(
                 "Duplicate register usage in root signature");
         }
     }
-    DX12ShaderRegisterUsage* usage = new DX12ShaderRegisterUsage{
-        registerType, registerIndex, spaceIndex, -1, 0};
+    DX12ShaderRegisterUsage* usage = new DX12ShaderRegisterUsage{registerType,
+        GLOBAL_DESCRIPTOR_HEAP,
+        registerIndex,
+        spaceIndex,
+        -1,
+        0,
+        0,
+        -1};
     bindingTableBindings.add(usage);
     changed = 1;
     return &usage->bindingTableIndex;
@@ -70,8 +84,21 @@ void Framework::DX12ShaderSignature::addRegisterUsageLinkedToDescriptorHeap(
     int descriptorHeapIndex,
     DX12ShaderRegister registerType,
     int registerIndex,
-    int spaceIndex)
+    int spaceIndex,
+    DX12DescriptorHeapType descriptorHeapType,
+    bool array,
+    int arraySize)
 {
+    if ((registerType == DX12_SHADER_REGISTER_S_SAMPLER)
+        != (descriptorHeapType == SAMPLER_DESCRIPTOR_HEAP))
+    {
+        Logging::error()
+            << "Sampler register usage must be linked to sampler descriptor "
+               "heap and vice versa";
+        throw std::logic_error(
+            "Sampler register usage must be linked to sampler descriptor "
+            "heap and vice versa");
+    }
     if (descriptorHeapIndex < 0)
     {
         Logging::error() << "descriptorHeapIndex can not be below 0";
@@ -90,31 +117,39 @@ void Framework::DX12ShaderSignature::addRegisterUsageLinkedToDescriptorHeap(
                 "Duplicate register usage in root signature");
         }
     }
-    // descriptor heap bindings sould be sorted by registerType -> spaceIndex ->
-    // registerIndex
+    // descriptor heap bindings sould be sorted by descriptorHeapType ->
+    // registerType -> spaceIndex -> registerIndex
     ArrayIterator<DX12ShaderRegisterUsage*> it = descriptorHeapBindings.begin();
     bool found = 0;
     while (it)
     {
-        if (it->registerType > registerType)
+        if (it->descriptorHeapType > descriptorHeapType)
         {
             found = 1;
             break;
         }
-        if (it->registerType == registerType)
+        if (it->descriptorHeapType == descriptorHeapType)
         {
-            if (it->spaceIndex > spaceIndex)
+            if (it->registerType > registerType)
             {
                 found = 1;
                 break;
             }
-            if (it->spaceIndex == spaceIndex)
+            if (it->registerType == registerType)
             {
-                if (it->registerIndex >= registerIndex)
+                if (it->spaceIndex > spaceIndex)
                 {
                     found = 1;
                     break;
                 }
+                if (it->spaceIndex == spaceIndex)
+                {
+                    if (it->registerIndex >= registerIndex)
+                    {
+                        found = 1;
+                        break;
+                    }
+                }
             }
         }
         ++it;
@@ -130,13 +165,25 @@ void Framework::DX12ShaderSignature::addRegisterUsageLinkedToDescriptorHeap(
             throw std::invalid_argument(
                 "Duplicate register usage in root signature");
         }
-        it.addBefore(new DX12ShaderRegisterUsage{
-            registerType, registerIndex, spaceIndex, descriptorHeapIndex, 0});
+        it.addBefore(new DX12ShaderRegisterUsage{registerType,
+            descriptorHeapType,
+            registerIndex,
+            spaceIndex,
+            descriptorHeapIndex,
+            0,
+            array,
+            arraySize});
     }
     else
     {
-        descriptorHeapBindings.add(new DX12ShaderRegisterUsage{
-            registerType, registerIndex, spaceIndex, descriptorHeapIndex, 0});
+        descriptorHeapBindings.add(new DX12ShaderRegisterUsage{registerType,
+            descriptorHeapType,
+            registerIndex,
+            spaceIndex,
+            descriptorHeapIndex,
+            0,
+            array,
+            arraySize});
     }
     changed = 1;
 }
@@ -154,25 +201,42 @@ void Framework::DX12ShaderSignature::createSignature(ID3D12Device5* zDevice,
         signature->Release();
         signature = 0;
     }
-    int paramCount = (descriptorHeapBindings.getEntryCount() > 0 ? 1 : 0)
+    int paramCount = (descriptorHeapBindings.getEntryCount() > 0
+                             ? __DESCRIPTOR_HEAP_TYPE_COUNT__
+                             : 0)
                    + bindingTableBindings.getEntryCount();
     D3D12_ROOT_PARAMETER* descriptorTable
         = new D3D12_ROOT_PARAMETER[paramCount];
     int index = 0;
-    D3D12_DESCRIPTOR_RANGE* descriptorRanges = 0;
-    if (descriptorHeapBindings.getEntryCount())
+    D3D12_DESCRIPTOR_RANGE** descriptorRanges
+        = new D3D12_DESCRIPTOR_RANGE*[__DESCRIPTOR_HEAP_TYPE_COUNT__];
+    int rangeCount = 0;
+    ArrayIterator<DX12ShaderRegisterUsage*> it = descriptorHeapBindings.begin();
+    DX12DescriptorHeapType currentDescriptorHeapType;
+    useGlobalDescriptorHeap = 0;
+    useTextureDescriptorHeap = 0;
+    while (it)
     {
-        descriptorTable[0].ParameterType
+        descriptorTable[index].ParameterType
             = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
-        descriptorTable[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
-        descriptorRanges = new D3D12_DESCRIPTOR_RANGE[descriptorHeapBindings
-                .getEntryCount()];
-        ArrayIterator<DX12ShaderRegisterUsage*> it
-            = descriptorHeapBindings.begin();
-        while (it)
+        descriptorTable[index].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
+        descriptorRanges[index]
+            = new D3D12_DESCRIPTOR_RANGE[descriptorHeapBindings
+                    .getEntryCount()];
+        currentDescriptorHeapType = it->descriptorHeapType;
+        if (currentDescriptorHeapType == GLOBAL_DESCRIPTOR_HEAP)
+        {
+            useGlobalDescriptorHeap = true;
+        }
+        else if (currentDescriptorHeapType == TEXTURE_DESCRIPTOR_HEAP)
+        {
+            useTextureDescriptorHeap = true;
+        }
+        rangeCount = 0;
+        while (it && it->descriptorHeapType == currentDescriptorHeapType)
         {
             it->bindingTableIndex = 0;
-            D3D12_DESCRIPTOR_RANGE& range = descriptorRanges[index];
+            D3D12_DESCRIPTOR_RANGE& range = descriptorRanges[index][rangeCount];
             switch (it->registerType)
             {
             case DX12_SHADER_REGISTER_B_CONST_BUFFER:
@@ -184,30 +248,42 @@ void Framework::DX12ShaderSignature::createSignature(ID3D12Device5* zDevice,
             case DX12_SHADER_REGISTER_U_UNORDERED_ACCESS:
                 range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
                 break;
+            case DX12_SHADER_REGISTER_S_SAMPLER:
+                range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
+                break;
             }
             range.BaseShaderRegister = it->registerIndex;
             range.OffsetInDescriptorsFromTableStart = it->descriptorHeapIndex;
             range.RegisterSpace = it->spaceIndex;
-            ArrayIterator<DX12ShaderRegisterUsage*> next = it.next();
-            int size = 1;
-            while (
-                next && next->registerType == it->registerType
-                && next->spaceIndex == it->spaceIndex
-                && next->registerIndex == it->registerIndex + size
-                && next->descriptorHeapIndex == it->descriptorHeapIndex + size)
+            if (it->array)
             {
-                ++size;
-                it = next;
-                it->bindingTableIndex = 0;
-                ++next;
+                range.NumDescriptors = it->arraySize;
+            }
+            else
+            {
+                ArrayIterator<DX12ShaderRegisterUsage*> next = it.next();
+                int size = 1;
+                while (next && next->registerType == it->registerType
+                       && next->spaceIndex == it->spaceIndex
+                       && next->registerIndex == it->registerIndex + size
+                       && next->descriptorHeapIndex
+                              == it->descriptorHeapIndex + size
+                       && it->descriptorHeapType == currentDescriptorHeapType)
+                {
+                    ++size;
+                    it = next;
+                    it->bindingTableIndex = 0;
+                    ++next;
+                }
+                range.NumDescriptors = size;
             }
-            range.NumDescriptors = size;
             ++it;
-            ++index;
+            ++rangeCount;
         }
-        descriptorTable[0].DescriptorTable.pDescriptorRanges = descriptorRanges;
-        descriptorTable[0].DescriptorTable.NumDescriptorRanges = index;
-        index = 1;
+        descriptorTable[index].DescriptorTable.pDescriptorRanges
+            = descriptorRanges[index];
+        descriptorTable[index].DescriptorTable.NumDescriptorRanges = rangeCount;
+        index++;
     }
     for (DX12ShaderRegisterUsage* usage : bindingTableBindings)
     {
@@ -279,6 +355,21 @@ int Framework::DX12ShaderSignature::gerShaderBindingTableParamCount() const
     return shaderBindingTableParamCount;
 }
 
+bool Framework::DX12ShaderSignature::doesUseGlobalDescriptorHeap() const
+{
+    return useGlobalDescriptorHeap;
+}
+
+bool Framework::DX12ShaderSignature::doesUseTextureDescriptorHeap() const
+{
+    return useTextureDescriptorHeap;
+}
+
+bool Framework::DX12ShaderSignature::doesUseSamplerDescriptorHeap() const
+{
+    return useSamplerDescriptorHeap;
+}
+
 Framework::DX12ShaderFunction::DX12ShaderFunction(const Text& functionName,
     DX12ShaderSignature* signature,
     DX12ShaderFunctionType functionType)
@@ -978,9 +1069,11 @@ DX12ShaderBindingTable* Framework::DX12Pipeline::createShaderBindingTable()
     return new DX12ShaderBindingTable(dynamic_cast<DX12Pipeline*>(getThis()));
 }
 
-DX12GlobalDescriptorHeap* Framework::DX12Pipeline::createGlobalDescriptorHeap()
+DX12GlobalDescriptorHeap* Framework::DX12Pipeline::createGlobalDescriptorHeap(
+    DX12DescriptorHeapType type)
 {
-    return new DX12GlobalDescriptorHeap(dynamic_cast<DX12Pipeline*>(getThis()));
+    return new DX12GlobalDescriptorHeap(
+        dynamic_cast<DX12Pipeline*>(getThis()), type);
 }
 
 const RCArray<DX12Shader>& Framework::DX12Pipeline::getShaders() const
@@ -1000,12 +1093,13 @@ const RCArray<DX12ShaderHitGroup>& Framework::DX12Pipeline::getHitGroups() const
 }
 
 Framework::DX12GlobalDescriptorHeap::DX12GlobalDescriptorHeap(
-    DX12Pipeline* pipeline)
+    DX12Pipeline* pipeline, DX12DescriptorHeapType type)
     : ReferenceCounter(),
       pipeline(pipeline),
       descriptorHeap(0),
       lastDescriptorHeapSize(0),
-      zDevice(0)
+      zDevice(0),
+      type(type)
 {}
 
 Framework::DX12GlobalDescriptorHeap::~DX12GlobalDescriptorHeap()
@@ -1033,8 +1127,8 @@ void Framework::DX12GlobalDescriptorHeap::addInput(
             for (const DX12ShaderRegisterUsage* usage :
                 function->zSignature()->getDescriptorHeapBindings())
             {
-                if (usage->descriptorHeapIndex
-                    == registerInputs.getEntryCount())
+                if (usage->descriptorHeapIndex == registerInputs.getEntryCount()
+                    && usage->descriptorHeapType == this->type)
                 {
                     if (usage->registerType != type)
                     {
@@ -1209,6 +1303,12 @@ void Framework::DX12GlobalDescriptorHeap::updateTLASInput(
     }
 }
 
+void Framework::DX12GlobalDescriptorHeap::addSamplerInput(
+    DX12SamplerState* zSampler)
+{
+    addInput(DX12_SHADER_REGISTER_S_SAMPLER, zSampler);
+}
+
 void Framework::DX12GlobalDescriptorHeap::updateDescriptorHeap(
     ID3D12Device5* zDevice)
 {
@@ -1222,7 +1322,9 @@ void Framework::DX12GlobalDescriptorHeap::updateDescriptorHeap(
         }
         D3D12_DESCRIPTOR_HEAP_DESC desc = {};
         desc.NumDescriptors = registerInputs.getEntryCount();
-        desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
+        desc.Type = type == SAMPLER_DESCRIPTOR_HEAP
+            ? D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER :
+                  D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
         desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
         desc.NodeMask = 0;
 
@@ -1239,6 +1341,8 @@ void Framework::DX12GlobalDescriptorHeap::updateDescriptorHeap(
         DX12Texture* zTexture
             = dynamic_cast<DX12Texture*>(input->inputResource);
         DX12Buffer* zBuffer = dynamic_cast<DX12Buffer*>(input->inputResource);
+        DX12SamplerState* zSampler
+            = dynamic_cast<DX12SamplerState*>(input->inputResource);
         switch (input->registerType)
         {
         case DX12_SHADER_REGISTER_B_CONST_BUFFER:
@@ -1278,7 +1382,7 @@ void Framework::DX12GlobalDescriptorHeap::updateDescriptorHeap(
                 else if (zTexture)
                 {
                     srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
-                    srvDesc.Texture2D.MipLevels = 0;
+                    srvDesc.Texture2D.MipLevels = 1;
                     srvDesc.Texture2D.MostDetailedMip = 0;
                     srvDesc.Texture2D.PlaneSlice = 0;
                     srvDesc.Texture2D.ResourceMinLODClamp = 0.0f;
@@ -1349,6 +1453,21 @@ void Framework::DX12GlobalDescriptorHeap::updateDescriptorHeap(
                     descriptorHeapHandle);
                 break;
             }
+        case DX12_SHADER_REGISTER_S_SAMPLER:
+            if (zSampler)
+            {
+                zDevice->CreateSampler(
+                    zSampler->zSamplerDesc(), descriptorHeapHandle);
+            }
+            else
+            {
+                Logging::error()
+                    << "Expected a sampler resource for register type "
+                    << input->registerType;
+                throw std::logic_error(
+                    "Expected a sampler resource for register type "
+                    + std::to_string(input->registerType));
+            }
         }
         descriptorHeapHandle.ptr += zDevice->GetDescriptorHandleIncrementSize(
             D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
@@ -1372,6 +1491,8 @@ Framework::DX12ShaderBindingTable::DX12ShaderBindingTable(
       pipeline(pipeline),
       shaderBindingTableBuffer(0),
       globalDescriptorHeap(0),
+      textureDescriptorHeap(0),
+      samplerDescriptorHeap(0),
       rayGenRecordSize(0),
       rayGenCount(0),
       missRecordSize(0),
@@ -1404,6 +1525,14 @@ Framework::DX12ShaderBindingTable::~DX12ShaderBindingTable()
     {
         globalDescriptorHeap->release();
     }
+    if (textureDescriptorHeap)
+    {
+        textureDescriptorHeap->release();
+    }
+    if (samplerDescriptorHeap)
+    {
+        samplerDescriptorHeap->release();
+    }
     for (const char* buffer : tempBuffers)
     {
         delete[] buffer;
@@ -1427,6 +1556,40 @@ void Framework::DX12ShaderBindingTable::setGlobalDescriptorHeap(
     }
 }
 
+void Framework::DX12ShaderBindingTable::setTextureDescriptorHeap(
+    DX12GlobalDescriptorHeap* zTextureDescriptorHeap)
+{
+    if (this->textureDescriptorHeap != zTextureDescriptorHeap)
+    {
+        if (this->textureDescriptorHeap)
+        {
+            this->textureDescriptorHeap->release();
+        }
+        this->textureDescriptorHeap = zTextureDescriptorHeap;
+        if (this->textureDescriptorHeap)
+        {
+            this->textureDescriptorHeap->getThis();
+        }
+    }
+}
+
+void Framework::DX12ShaderBindingTable::setSamplerDescriptorHeap(
+    DX12GlobalDescriptorHeap* zSamplerDescriptorHeap)
+{
+    if (this->samplerDescriptorHeap != zSamplerDescriptorHeap)
+    {
+        if (this->samplerDescriptorHeap)
+        {
+            this->samplerDescriptorHeap->release();
+        }
+        this->samplerDescriptorHeap = zSamplerDescriptorHeap;
+        if (this->samplerDescriptorHeap)
+        {
+            this->samplerDescriptorHeap->getThis();
+        }
+    }
+}
+
 void Framework::DX12ShaderBindingTable::startUpdate()
 {
     if (shaderBindingTableBuffer)
@@ -1595,19 +1758,35 @@ int Framework::DX12ShaderBindingTable::addHitGroup(
         stateObjectProperties->GetShaderIdentifier(
             zHitGroup->zHitGroupDesc()->HitGroupExport),
         D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT);
-    if (zHitGroup->zSignature()->getDescriptorHeapBindings().getEntryCount()
-        > 0)
+    index += D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT;
+    if (zHitGroup->zSignature()->doesUseGlobalDescriptorHeap())
     {
         D3D12_GPU_DESCRIPTOR_HANDLE gpuAddress
             = globalDescriptorHeap->zDescriptorHeap()
                   ->GetGPUDescriptorHandleForHeapStart();
-        set(index + D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT,
-            &gpuAddress.ptr,
-            sizeof(__int64));
+        set(index, &gpuAddress.ptr, sizeof(__int64));
+        index += sizeof(__int64);
+    }
+    if (zHitGroup->zSignature()->doesUseTextureDescriptorHeap())
+    {
+        D3D12_GPU_DESCRIPTOR_HANDLE gpuAddress
+            = textureDescriptorHeap->zDescriptorHeap()
+                  ->GetGPUDescriptorHandleForHeapStart();
+        set(index, &gpuAddress.ptr, sizeof(__int64));
+        index += sizeof(__int64);
+    }
+    if (zHitGroup->zSignature()->doesUseSamplerDescriptorHeap())
+    {
+        D3D12_GPU_DESCRIPTOR_HANDLE gpuAddress
+            = samplerDescriptorHeap->zDescriptorHeap()
+                  ->GetGPUDescriptorHandleForHeapStart();
+        set(index, &gpuAddress.ptr, sizeof(__int64));
+        index += sizeof(__int64);
     }
     hitGroupCount++;
     nextHitGroupOffset += hitGroupRecordSize;
-    return index + D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT;
+    return nextHitGroupOffset - hitGroupRecordSize
+         + D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT;
 }
 
 void Framework::DX12ShaderBindingTable::setHitGroupShaderInput(
@@ -1653,17 +1832,30 @@ void Framework::DX12ShaderBindingTable::endUpdate(
                 stateObjectProperties->GetShaderIdentifier(
                     function->zExportDesc()->Name),
                 D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT);
-            if (function->zSignature()
-                    ->getDescriptorHeapBindings()
-                    .getEntryCount()
-                > 0)
+            offset += D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT;
+            if (function->zSignature()->doesUseGlobalDescriptorHeap())
             {
                 D3D12_GPU_DESCRIPTOR_HANDLE gpuAddress
                     = globalDescriptorHeap->zDescriptorHeap()
                           ->GetGPUDescriptorHandleForHeapStart();
-                set(offset + D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT,
-                    &gpuAddress.ptr,
-                    sizeof(__int64));
+                set(offset, &gpuAddress.ptr, sizeof(__int64));
+                offset += sizeof(__int64);
+            }
+            if (function->zSignature()->doesUseTextureDescriptorHeap())
+            {
+                D3D12_GPU_DESCRIPTOR_HANDLE gpuAddress
+                    = textureDescriptorHeap->zDescriptorHeap()
+                          ->GetGPUDescriptorHandleForHeapStart();
+                set(offset, &gpuAddress.ptr, sizeof(__int64));
+                offset += sizeof(__int64);
+            }
+            if (function->zSignature()->doesUseSamplerDescriptorHeap())
+            {
+                D3D12_GPU_DESCRIPTOR_HANDLE gpuAddress
+                    = samplerDescriptorHeap->zDescriptorHeap()
+                          ->GetGPUDescriptorHandleForHeapStart();
+                set(offset, &gpuAddress.ptr, sizeof(__int64));
+                offset += sizeof(__int64);
             }
         }
     }

+ 39 - 4
DX12Shader.h

@@ -14,22 +14,34 @@ namespace Framework
 {
     class Texture;
     class DX12TLAS;
+    class DX12SamplerState;
 
     enum DX12ShaderRegister
     {
         DX12_SHADER_REGISTER_B_CONST_BUFFER = 0,
         DX12_SHADER_REGISTER_T_SHADER_RESOURCE = 1,
         DX12_SHADER_REGISTER_U_UNORDERED_ACCESS = 2,
-        // TODO: Do we need Sampler?
+        DX12_SHADER_REGISTER_S_SAMPLER = 3,
+    };
+
+    enum DX12DescriptorHeapType
+    {
+        GLOBAL_DESCRIPTOR_HEAP = 0,
+        TEXTURE_DESCRIPTOR_HEAP = 1,
+        SAMPLER_DESCRIPTOR_HEAP = 2,
+        __DESCRIPTOR_HEAP_TYPE_COUNT__
     };
 
     struct DX12ShaderRegisterUsage
     {
         DX12ShaderRegister registerType;
+        DX12DescriptorHeapType descriptorHeapType;
         int registerIndex;
         int spaceIndex;
         int descriptorHeapIndex;
         int bindingTableIndex;
+        bool array;
+        int arraySize;
     };
 
     class DX12ShaderHeap;
@@ -42,6 +54,9 @@ namespace Framework
         Array<DX12ShaderRegisterUsage*> bindingTableBindings;
         bool changed;
         int shaderBindingTableParamCount;
+        bool useGlobalDescriptorHeap;
+        bool useTextureDescriptorHeap;
+        bool useSamplerDescriptorHeap;
 
     public:
         DLLEXPORT DX12ShaderSignature();
@@ -83,12 +98,19 @@ 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)
+         * \param array used to specify if the register referes to an array in
+         * hlsl
+         * \param arraySize the size of the array if array is true or -1 if the
+         * size is unknown (unbound array)
          */
         DLLEXPORT void addRegisterUsageLinkedToDescriptorHeap(
             int descriptorHeapIndex,
             DX12ShaderRegister registerType,
             int registerIndex,
-            int spaceIndex = 0);
+            int spaceIndex = 0,
+            DX12DescriptorHeapType descriptorHeapType = GLOBAL_DESCRIPTOR_HEAP,
+            bool array = false,
+            int arraySize = -1);
         /**
          * Creates the root signature.
          */
@@ -98,6 +120,9 @@ namespace Framework
         DLLEXPORT const Array<DX12ShaderRegisterUsage*>&
         getDescriptorHeapBindings() const;
         DLLEXPORT int gerShaderBindingTableParamCount() const;
+        DLLEXPORT bool doesUseGlobalDescriptorHeap() const;
+        DLLEXPORT bool doesUseTextureDescriptorHeap() const;
+        DLLEXPORT bool doesUseSamplerDescriptorHeap() const;
     };
 
     enum DX12ShaderFunctionType
@@ -204,7 +229,8 @@ namespace Framework
             PFN_D3D12_SERIALIZE_ROOT_SIGNATURE pfnD3D12SerializeRootSignature);
         DLLEXPORT ID3D12StateObject* zPipelineState() const;
         DLLEXPORT DX12ShaderBindingTable* createShaderBindingTable();
-        DLLEXPORT DX12GlobalDescriptorHeap* createGlobalDescriptorHeap();
+        DLLEXPORT DX12GlobalDescriptorHeap* createGlobalDescriptorHeap(
+            DX12DescriptorHeapType type);
         DLLEXPORT const RCArray<DX12Shader>& getShaders() const;
         DLLEXPORT const Array<const DX12ShaderFunction*>&
         getFunctionsWithoutHitGroups() const;
@@ -226,9 +252,11 @@ namespace Framework
         Array<DX12ShaderRegisterInput*> registerInputs;
         int lastDescriptorHeapSize;
         ID3D12Device5* zDevice;
+        DX12DescriptorHeapType type;
 
     public:
-        DX12GlobalDescriptorHeap(DX12Pipeline* pipeline);
+        DX12GlobalDescriptorHeap(
+            DX12Pipeline* pipeline, DX12DescriptorHeapType type);
         ~DX12GlobalDescriptorHeap();
 
     private:
@@ -245,6 +273,7 @@ namespace Framework
         DLLEXPORT void addTLASInput(DX12ShaderRegister type, DX12TLAS* zTLAS);
         DLLEXPORT void updateTLASInput(
             int heapIndex, DX12ShaderRegister type, DX12TLAS* zTLAS);
+        DLLEXPORT void addSamplerInput(DX12SamplerState* zSampler);
         DLLEXPORT void updateDescriptorHeap(ID3D12Device5* zDevice);
         DLLEXPORT DX12Pipeline* zPipeline() const;
         DLLEXPORT ID3D12DescriptorHeap* zDescriptorHeap() const;
@@ -256,6 +285,8 @@ namespace Framework
         DX12Pipeline* pipeline;
         DX12Buffer* shaderBindingTableBuffer;
         DX12GlobalDescriptorHeap* globalDescriptorHeap;
+        DX12GlobalDescriptorHeap* textureDescriptorHeap;
+        DX12GlobalDescriptorHeap* samplerDescriptorHeap;
         int rayGenRecordSize;
         int rayGenCount;
         int missRecordSize;
@@ -275,6 +306,10 @@ namespace Framework
         DLLEXPORT ~DX12ShaderBindingTable();
         DLLEXPORT void setGlobalDescriptorHeap(
             DX12GlobalDescriptorHeap* zGlobalDescriptorHeap);
+        DLLEXPORT void setTextureDescriptorHeap(
+            DX12GlobalDescriptorHeap* zTextureDescriptorHeap);
+        DLLEXPORT void setSamplerDescriptorHeap(
+            DX12GlobalDescriptorHeap* zSamplerDescriptorHeap);
         DLLEXPORT void startUpdate();
 
     private:

+ 47 - 1
Framework Tests/Camera3D.cpp

@@ -4,9 +4,11 @@
 #include "CppUnitTest.h"
 #include "DX12GraphicsApi.h"
 #include "Globals.h"
+#include "Image.h"
 #include "Model3D.h"
 #include "RenderThread.h"
 #include "Screen.h"
+#include "Texture.h"
 #include "Window.h"
 #include "World3D.h"
 
@@ -237,9 +239,50 @@ namespace FrameworkTests
             p->indexList[5] = 2 + 20;
             data->addPolygon(p);
             data->calculateNormals();
+
+            Framework::Image* img1 = new Framework::Image();
+            img1->newImage(1, 1, 0xFFFF0000);
+            Framework::Texture* red
+                = screen.zGraphicsApi()->createOrGetTexture("red", img1);
+
+            Framework::Image* img2 = new Framework::Image();
+            img2->newImage(1, 1, 0xFF00FF00);
+            Framework::Texture* green
+                = screen.zGraphicsApi()->createOrGetTexture("green", img2);
+
+            Framework::Image* img3 = new Framework::Image();
+            img3->newImage(1, 1, 0xFF0000FF);
+            Framework::Texture* blue
+                = screen.zGraphicsApi()->createOrGetTexture("blue", img3);
+
+            Framework::Image* img4 = new Framework::Image();
+            img4->newImage(1, 1, 0xFFFFFF00);
+            Framework::Texture* yellow
+                = screen.zGraphicsApi()->createOrGetTexture("yellow", img4);
+
+            Framework::Image* img5 = new Framework::Image();
+            img5->newImage(1, 1, 0xFFFF00FF);
+            Framework::Texture* pink
+                = screen.zGraphicsApi()->createOrGetTexture("pink", img5);
+
+            Framework::Image* img6 = new Framework::Image();
+            img6->newImage(1, 1, 0xFFFFFFFF);
+            Framework::Texture* white
+                = screen.zGraphicsApi()->createOrGetTexture("white", img6);
+
+            Framework::Model3DTexture* texture
+                = new Framework::Model3DTexture();
+            texture->setPolygonTexture(0, red);
+            texture->setPolygonTexture(1, green);
+            texture->setPolygonTexture(2, blue);
+            texture->setPolygonTexture(3, yellow);
+            texture->setPolygonTexture(4, pink);
+            texture->setPolygonTexture(5, white);
+
             Framework::Array<Framework::Model3D*> cubes;
+
             std::function<void(int, int, int)> addCube
-                = [&cubes, &world, &data](int x, int y, int z) {
+                = [&cubes, &world, &data, &texture](int x, int y, int z) {
                       Framework::Model3D* cube = new Framework::Model3D();
                       cube->setModelData(dynamic_cast<Framework::Model3DData*>(
                           data->getThis()));
@@ -247,6 +290,9 @@ namespace FrameworkTests
                       cube->setSize(5 + rand() % 5);
                       cube->setRotation(
                           rand() % 10 / 5, rand() % 10 / 5, rand() % 10 / 5);
+                      cube->setModelTextur(
+                          dynamic_cast<Framework::Model3DTexture*>(
+                              texture->getThis()));
                       world.addDrawable(cube);
                       cubes.add(cube);
                   };

+ 2 - 0
Framework.vcxproj

@@ -212,6 +212,7 @@ copy "x64\Release\Framework.dll" "..\..\Spiele Platform\SMP\Fertig\x64\framework
     <ClInclude Include="DX12BLAS.h" />
     <ClInclude Include="DX12BLASModel.h" />
     <ClInclude Include="DX12GraphicsApi.h" />
+    <ClInclude Include="DX12SamplerState.h" />
     <ClInclude Include="DX12TLAS.h" />
     <ClInclude Include="DX9GraphicsApi.h" />
     <ClInclude Include="DX9Texture.h" />
@@ -329,6 +330,7 @@ copy "x64\Release\Framework.dll" "..\..\Spiele Platform\SMP\Fertig\x64\framework
     <ClCompile Include="DX11Texture.cpp" />
     <ClCompile Include="DX12BLAS.cpp" />
     <ClCompile Include="DX12BLASModel.cpp" />
+    <ClCompile Include="DX12SamplerState.cpp" />
     <ClCompile Include="DX12TLAS.cpp" />
     <ClCompile Include="DX9Texture.cpp" />
     <ClCompile Include="SelectionBox.cpp" />

+ 6 - 0
Framework.vcxproj.filters

@@ -430,6 +430,9 @@
     <ClInclude Include="Vec4.h">
       <Filter>Framework\Graphics\4D</Filter>
     </ClInclude>
+    <ClInclude Include="DX12SamplerState.h">
+      <Filter>Framework\Graphics\DX\DX12</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Model3DCollection.h">
@@ -714,6 +717,9 @@
     <ClCompile Include="DX11Texture.cpp">
       <Filter>Framework\Graphics\DX\DX11</Filter>
     </ClCompile>
+    <ClCompile Include="DX12SamplerState.cpp">
+      <Filter>Framework\Graphics\DX\DX12</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <FxCompile Include="DX11VertexShader.hlsl">

+ 29 - 1
Hit.hlsl

@@ -1,7 +1,35 @@
 #include "Common.hlsl"
 
+Texture2D<float4> textures[] : register(t0, space1);
+SamplerState gSampler : register(s0, space0);
+
+struct VertexData
+{
+    float2 texcoord;
+    float3 normal;
+};
+
+StructuredBuffer<int> textureIdBuffer : register(t1, space2);
+StructuredBuffer<int> indexBuffer : register(t1, space3);
+StructuredBuffer<VertexData> vertexData : register(t1, space4);
+StructuredBuffer<int> polygonSizeBuffer : register(t1, space5);
+
 [shader("closesthit")]
 void ClosestHit(inout HitInfo payload, Attributes attrib)
 {
-    payload.colorAndDistance = float4(1, 0, 0, RayTCurrent());
+    //payload.colorAndDistance = float4(1, 1, 1, 1.0);
+    int currentTriangle = PrimitiveIndex();
+    int textureId = 0;
+    for (int i = 0; currentTriangle >= 0; i++)
+    {
+        currentTriangle -= polygonSizeBuffer[i];
+        textureId = textureIdBuffer[i];
+    }
+    int index = PrimitiveIndex() * 3;
+    VertexData v0 = vertexData[indexBuffer[index]];
+    VertexData v1 = vertexData[indexBuffer[index + 1]];
+    VertexData v2 = vertexData[indexBuffer[index + 2]];
+    float2 texcoord = v0.texcoord * (1 - attrib.bary.x - attrib.bary.y) + v1.texcoord * attrib.bary.x + v2.texcoord * attrib.bary.y;
+    float4 color = textures[textureId].SampleLevel(gSampler, texcoord, 0);
+    payload.colorAndDistance = float4(color.rgb, RayTCurrent());
 }

+ 40 - 1
Model3D.cpp

@@ -692,7 +692,10 @@ void Framework::Model3DData::unlock()
 
 // Constructor
 Model3DTexture::Model3DTexture()
-    : ReferenceCounter()
+    : ReferenceCounter(),
+      textureIndexBuffer(0),
+      textureIndexList(new int[1]),
+      changed(0)
 {
     textures = new Texture*[1];
     textures[0] = 0;
@@ -707,6 +710,11 @@ Model3DTexture::~Model3DTexture()
         if (textures[i]) textures[i]->release();
     }
     delete[] textures;
+    delete[] textureIndexList;
+    if (textureIndexBuffer)
+    {
+        textureIndexBuffer->release();
+    }
 }
 
 // Sets which texture is for which polygon
@@ -723,10 +731,19 @@ void Model3DTexture::setPolygonTexture(int pI, Texture* txt)
             0,
             sizeof(Texture*) * (pI + 1 - textureCount));
         delete[] tmp;
+
+        int* tmp2 = new int[pI + 1];
+        memcpy(tmp2, textureIndexList, sizeof(int) * textureCount);
+        memset(tmp2 + textureCount, 0, sizeof(int) * (pI + 1 - textureCount));
+        delete[] textureIndexList;
+        textureIndexList = tmp2;
+
         textureCount = pI + 1;
     }
     if (textures[pI]) textures[pI]->release();
     textures[pI] = txt;
+    textureIndexList[pI] = txt ? txt->getId() : -1;
+    changed = 1;
 }
 
 // Returns a pointer to the texture of a polygon without increased
@@ -738,6 +755,28 @@ Texture* Model3DTexture::zPolygonTexture(int i) const
     return textures[i];
 }
 
+void Framework::Model3DTexture::updateTextureIndexBuffer(GraphicsApi* zApi)
+{
+    if (textureIndexBuffer && !changed) return;
+    if (!textureIndexBuffer)
+    {
+        textureIndexBuffer = zApi->createStructuredBuffer(sizeof(int));
+    }
+    textureIndexBuffer->setData(textureIndexList, changed);
+    textureIndexBuffer->setLength(textureCount * sizeof(int));
+    textureIndexBuffer->copyToGPU();
+}
+
+DXBuffer* Framework::Model3DTexture::zTextureIndexBuffer() const
+{
+    return textureIndexBuffer;
+}
+
+bool Framework::Model3DTexture::wasChanged() const
+{
+    return changed;
+}
+
 // Contents of the Model3D class
 // Constructor
 Model3D::Model3D()

+ 9 - 2
Model3D.h

@@ -5,8 +5,6 @@
 #include "Mat4.h"
 #include "Vec2.h"
 
-struct ID3D11Buffer;
-
 namespace Framework
 {
     struct Polygon2D;     //! Model2D.h
@@ -281,7 +279,10 @@ namespace Framework
     {
     private:
         Texture** textures;
+        DXBuffer* textureIndexBuffer;
+        int* textureIndexList;
         int textureCount;
+        bool changed;
 
     public:
         //! Constructor
@@ -295,6 +296,12 @@ namespace Framework
         //! Returns a pointer to the texture of a polygon without increased
         //! reference counter \param i The index of the polygon
         DLLEXPORT Texture* zPolygonTexture(int i) const;
+        DLLEXPORT void updateTextureIndexBuffer(GraphicsApi* zApi);
+        DLLEXPORT DXBuffer* zTextureIndexBuffer() const;
+        //! Returns true if the texture was changed since the last update
+        DLLEXPORT bool wasChanged() const;
+        //! Sets whether the texture was changed since the last update
+        DLLEXPORT void setChanged(bool changed);
     };
 
     //! A drawing of the 3D framework that can display a 3D model with

+ 6 - 30
TextureList.cpp

@@ -22,15 +22,6 @@ TextureList::~TextureList()
     names->release();
 }
 
-// Deletes all textures
-__declspec(dllexport) void TextureList::clear()
-{
-    lock.lockWrite();
-    textures->clear();
-    names->clear();
-    lock.unlockWrite();
-}
-
 // Adds a texture to the list
 //  t: The texture
 //  name: The name under which the texture is stored in the list
@@ -53,26 +44,6 @@ bool TextureList::addTexture(Texture* t, const char* name)
     return 1;
 }
 
-// Removes a texture from the list
-//  name: The name of the texture
-void TextureList::removeTexture(const char* name)
-{
-    lock.lockWrite();
-    int index = 0;
-    for (auto i : *names)
-    {
-        if (i->isEqual(name))
-        {
-            names->remove(index);
-            textures->remove(index);
-            lock.unlockWrite();
-            return;
-        }
-        index++;
-    }
-    lock.unlockWrite();
-}
-
 // Checks whether a texture has been stored under a specific name
 //  name: The name
 //  return: true if a texture with the name exists
@@ -164,4 +135,9 @@ Texture* TextureList::zTexture(int id) const
     }
     lock.unlockRead();
     return 0;
-}
+}
+
+const RCArray<Texture>* Framework::TextureList::zTextures() const
+{
+    return textures;
+}

+ 2 - 5
TextureList.h

@@ -22,15 +22,10 @@ namespace Framework
         TextureList();
         //! Destructor
         ~TextureList();
-        //! Deletes all textures
-        DLLEXPORT void clear();
         //! Adds a texture to the list
         //! \param t The texture
         //! \param name The name under which the texture is stored in the list
         DLLEXPORT bool addTexture(Texture* t, const char* name);
-        //! Removes a texture from the list
-        //! \param name The name of the texture
-        DLLEXPORT void removeTexture(const char* name);
         //! Checks whether a texture is stored under a specific name
         //! \param name The name \return true if a texture with the name exists
         DLLEXPORT bool hasTexture(const char* name) const;
@@ -46,5 +41,7 @@ namespace Framework
         //! Returns a specific texture without increased reference counter
         //! \param id The id of the texture
         DLLEXPORT Texture* zTexture(int id) const;
+        //! Returns a list of all textures without increased reference counter
+        DLLEXPORT const RCArray<Texture>* zTextures() const;
     };
 } // namespace Framework