2
$\begingroup$

I have a problem with RTPSO creation. Using local root signatures for each of rgs (ray generation shader), chs (closest hit), miss is working correctly. However, for performance sake, I want to use global root signature with dummy/empty local root signatures.

Below code works correctly:

void RaytracingResources::CreateRTPSO(ID3D12Device5* device, size_t maxPayloadSize)
{
    // Need 11 subobjects:
    // 1 for RGS program
    // 1 for Miss program
    // 1 for CHS program
    // 1 for AHS program
    // 1 for Hit Group
    // 2 for RayGen Root Signature (root-signature and association)
    // 2 for Shader Config (config and association)
    // 1 for Global Root Signature
    // 1 for Pipeline Config    
    UINT index = 0;
    std::vector<D3D12_STATE_SUBOBJECT> subobjects;
    size_t size = 0;
    size += 1; // rgs
    for (auto& hitGroup : m_hitGroups)
    {
        size += 2; // chs, miss
        size += (hitGroup.hitShader.ahs.name != nullptr) ? 1 : 0; // ahs
        size += 1; // hit group
        size += 2; // payload + association
        size += 2; // local root + association
    }
    size += 3; // global root + local root + pipeline config
    subobjects.resize(size);

    ID3D12RootSignature* dummyLocalRootSignature;
    ID3D12RootSignature* dummyGlobalRootSignature;
    // Create dummy global and local root signature
    {
        HRESULT hr = 0;
        D3D12_ROOT_SIGNATURE_DESC rootDesc = {};
        rootDesc.NumParameters = 0;
        rootDesc.pParameters = nullptr;
        rootDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE;
        ID3DBlob* serializedRootSignature;
        ID3DBlob* error;

        // Create the global root signature
        ThrowIfFailed(D3D12SerializeRootSignature(&rootDesc, D3D_ROOT_SIGNATURE_VERSION_1,
            &serializedRootSignature, &error));

        ThrowIfFailed(device->CreateRootSignature(0, serializedRootSignature->GetBufferPointer(),
            serializedRootSignature->GetBufferSize(),
            IID_PPV_ARGS(&dummyGlobalRootSignature)));

        serializedRootSignature->Release();

        rootDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_LOCAL_ROOT_SIGNATURE;
        // Create the local root signature, reusing the same descriptor but altering the creation flag
        ThrowIfFailed(D3D12SerializeRootSignature(&rootDesc, D3D_ROOT_SIGNATURE_VERSION_1,
            &serializedRootSignature, &error));

        ThrowIfFailed(device->CreateRootSignature(0, serializedRootSignature->GetBufferPointer(),
            serializedRootSignature->GetBufferSize(),
            IID_PPV_ARGS(&dummyLocalRootSignature)));

        serializedRootSignature->Release();
    }

#pragma region HitGroup creation - 1
    {
        HitGroup hitGroup = m_hitGroups[0];
        // Add state subobject for the RGS
        {
            D3D12_EXPORT_DESC rgsExportDesc = { hitGroup.rayGenShader.name, nullptr, D3D12_EXPORT_FLAG_NONE };

            D3D12_DXIL_LIBRARY_DESC rgsLibDesc = {};
            rgsLibDesc.DXILLibrary.BytecodeLength = hitGroup.rayGenShader.blob->GetBufferSize();
            rgsLibDesc.DXILLibrary.pShaderBytecode = hitGroup.rayGenShader.blob->GetBufferPointer();
            rgsLibDesc.NumExports = 1;
            rgsLibDesc.pExports = &rgsExportDesc;

            D3D12_STATE_SUBOBJECT rgs = { D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY, &rgsLibDesc };
            subobjects[index++] = rgs;
        }

        //Add state subobject for the Miss shader
        {
            D3D12_EXPORT_DESC msExportDesc = { hitGroup.missShader.name, hitGroup.missShader.exportToRename, D3D12_EXPORT_FLAG_NONE };

            D3D12_DXIL_LIBRARY_DESC msLibDesc = {};
            msLibDesc.DXILLibrary.BytecodeLength = hitGroup.missShader.blob->GetBufferSize();
            msLibDesc.DXILLibrary.pShaderBytecode = hitGroup.missShader.blob->GetBufferPointer();
            msLibDesc.NumExports = 1;
            msLibDesc.pExports = &msExportDesc;

            D3D12_STATE_SUBOBJECT ms = { D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY, &msLibDesc };
            subobjects[index++] = ms;
        }

        // Add state subobject for the Closest Hit shader
        {
            D3D12_EXPORT_DESC chsExportDesc = { hitGroup.hitShader.chs.name, hitGroup.hitShader.chs.exportToRename, D3D12_EXPORT_FLAG_NONE };

            D3D12_DXIL_LIBRARY_DESC chsLibDesc = {};
            chsLibDesc.DXILLibrary.BytecodeLength = hitGroup.hitShader.chs.blob->GetBufferSize();
            chsLibDesc.DXILLibrary.pShaderBytecode = hitGroup.hitShader.chs.blob->GetBufferPointer();
            chsLibDesc.NumExports = 1;
            chsLibDesc.pExports = &chsExportDesc;

            D3D12_STATE_SUBOBJECT chs = { D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY, &chsLibDesc };
            subobjects[index++] = chs;
        }

        // Add state subobject for the Any Hit shader
        if (hitGroup.hitShader.ahs.name != nullptr)
        {
            D3D12_EXPORT_DESC ahsExportDesc = { hitGroup.hitShader.ahs.name, hitGroup.hitShader.ahs.exportToRename, D3D12_EXPORT_FLAG_NONE };

            D3D12_DXIL_LIBRARY_DESC ahsLibDesc = {};
            ahsLibDesc.DXILLibrary.BytecodeLength = hitGroup.hitShader.ahs.blob->GetBufferSize();
            ahsLibDesc.DXILLibrary.pShaderBytecode = hitGroup.hitShader.ahs.blob->GetBufferPointer();
            ahsLibDesc.NumExports = 1;
            ahsLibDesc.pExports = &ahsExportDesc;

            D3D12_STATE_SUBOBJECT ahs = { D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY, &ahsLibDesc };
            subobjects[index++] = ahs;
        }

        // Add a state subobject for the hit group
        {
            D3D12_HIT_GROUP_DESC hitGroupDesc = {};
            hitGroupDesc.ClosestHitShaderImport = hitGroup.hitShader.chs.name;
            if (hitGroup.hitShader.ahs.name != nullptr) hitGroupDesc.AnyHitShaderImport = hitGroup.hitShader.ahs.name;
            hitGroupDesc.HitGroupExport = hitGroup.hitGroupName;

            D3D12_STATE_SUBOBJECT hitGroup = { D3D12_STATE_SUBOBJECT_TYPE_HIT_GROUP, &hitGroupDesc };
            subobjects[index++] = hitGroup;
        }

        // Add a state subobject for the shader payload configuration
        {
            D3D12_RAYTRACING_SHADER_CONFIG shaderDesc = { static_cast<UINT>(maxPayloadSize), D3D12_RAYTRACING_MAX_ATTRIBUTE_SIZE_IN_BYTES };
            D3D12_STATE_SUBOBJECT shaderConfigObject = { D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG, &shaderDesc };
            subobjects[index++] = shaderConfigObject;
        }

        // Create a list of the shader export names that use the payload
        {
            D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION shaderPayloadAssociation = {};
            if (hitGroup.hitShader.ahs.name != nullptr) {
                const WCHAR* shaderExports[] = { hitGroup.rayGenShader.name, hitGroup.missShader.name, hitGroup.hitShader.chs.name, hitGroup.hitShader.ahs.name };
                shaderPayloadAssociation = { &subobjects[(index - 1)], _countof(shaderExports), shaderExports };
            }
            else {
                const WCHAR* shaderExports[] = { hitGroup.rayGenShader.name, hitGroup.missShader.name, hitGroup.hitShader.chs.name };
                shaderPayloadAssociation = { &subobjects[(index - 1)], _countof(shaderExports), shaderExports };
            }

            D3D12_STATE_SUBOBJECT shaderPayloadAssociationObject = { D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION, &shaderPayloadAssociation };
            subobjects[index++] = shaderPayloadAssociationObject;
        }

        // Add a state subobject for the shared root signature 
        {
            D3D12_STATE_SUBOBJECT rayGenRootSigObject = { D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE, &hitGroup.rayGenShader.pRootSignature};
            subobjects[index++] = rayGenRootSigObject;
        }

        // Create a list of the shader export names that use the root signature
        {
            D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION rayGenShaderRootSigAssociation = {};
            if (hitGroup.hitShader.ahs.name != nullptr)
            {
                const WCHAR* rootSigExports[] = { m_hitGroups[0].rayGenShader.name, hitGroup.missShader.name, hitGroup.hitShader.chs.name, hitGroup.hitShader.ahs.name };
                rayGenShaderRootSigAssociation = { &subobjects[(index - 1)], _countof(rootSigExports), rootSigExports };
            }
            else
            {
                const WCHAR* rootSigExports[] = { hitGroup.rayGenShader.name, hitGroup.missShader.name, hitGroup.hitShader.chs.name };
                rayGenShaderRootSigAssociation = { &subobjects[(index - 1)], _countof(rootSigExports), rootSigExports };
            }

            D3D12_STATE_SUBOBJECT rayGenShaderRootSigAssociationObject = { D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION, &rayGenShaderRootSigAssociation };
            subobjects[index++] = rayGenShaderRootSigAssociationObject;
        }
    }
#pragma endregion



    // Setup global root signature
    {
        D3D12_STATE_SUBOBJECT globalRootSig = { D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE, &dummyGlobalRootSignature };
        subobjects[index++] = globalRootSig;
    }

    // The pipeline construction always requires an empty local root signature
    {
        D3D12_STATE_SUBOBJECT localRootSig = { D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE, &dummyLocalRootSignature };
        subobjects[index++] = localRootSig;
    }

    // Add a state subobject for the ray tracing pipeline config
    {
        D3D12_RAYTRACING_PIPELINE_CONFIG pipelineConfig = { 2 }; // Max Trace Recursion Depth
        D3D12_STATE_SUBOBJECT pipelineConfigObject = { D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG, &pipelineConfig };
        subobjects[index++] = pipelineConfigObject; 
    }

    // Finish rtpso creation and store in variable
    {
        // Describe RTPSO
        D3D12_STATE_OBJECT_DESC pipelineDesc = { D3D12_STATE_OBJECT_TYPE_RAYTRACING_PIPELINE, static_cast<UINT>(subobjects.size()), subobjects.data() };

        // Create the RT Pipeline State Object (RTPSO) / Get the RTPSO properties
        ThrowIfFailed(device->CreateStateObject(&pipelineDesc, IID_PPV_ARGS(&m_rtpso)));
        ThrowIfFailed(m_rtpso->QueryInterface(IID_PPV_ARGS(&m_rtpsoInfo)));
    }
}

However, replacing

// Setup global root signature
{
    D3D12_STATE_SUBOBJECT globalRootSig = { D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE, &dummyGlobalRootSignature };
    subobjects[index++] = globalRootSig;
}

with local signature from first code snippet that I've compiled with flag D3D12_ROOT_SIGNATURE_FLAG_NONE instead of D3D12_ROOT_SIGNATURE_FLAG_LOCAL_ROOT_SIGNATURE. Local signatures for:

    // Add a state subobject for the shared root signature 
    {
        D3D12_STATE_SUBOBJECT rayGenRootSigObject = { D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE, &hitGroup.rayGenShader.pRootSignature };
        subobjects[index++] = rayGenRootSigObject;
    }

    // Create a list of the shader export names that use the root signature
    {
        D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION rayGenShaderRootSigAssociation = {};
        if (hitGroup.hitShader.ahs.name != nullptr)
        {
            const WCHAR* rootSigExports[] = { hitGroup.missShader.name, hitGroup.hitShader.chs.name, hitGroup.hitShader.ahs.name };
            rayGenShaderRootSigAssociation = { &subobjects[(index - 1)], _countof(rootSigExports), rootSigExports };
        }
        else
        {
            const WCHAR* rootSigExports[] = { hitGroup.missShader.name, hitGroup.hitShader.chs.name };
            rayGenShaderRootSigAssociation = { &subobjects[(index - 1)], _countof(rootSigExports), rootSigExports };
        }

        D3D12_STATE_SUBOBJECT rayGenShaderRootSigAssociationObject = { D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION, &rayGenShaderRootSigAssociation };
        subobjects[index++] = rayGenShaderRootSigAssociationObject;
    }

are replaced with dummy local signatures. However, every program run is causing error of device removal:

D3D12: Removing Device.
D3D12 ERROR: ID3D12Device::RemoveDevice: Device removal has been triggered for the following reason (DXGI_ERROR_DEVICE_HUNG: The Device took an unreasonable amount of time to execute its commands, or the hardware crashed/hung. As a result, the TDR (Timeout Detection and Recovery) mechanism has been triggered. The current Device Context was executing commands when the hang occurred. The application may want to respawn and fallback to less aggressive use of the display hardware). [ EXECUTION ERROR #232: DEVICE_REMOVAL_PROCESS_AT_FAULT]

Commenting out TraceRay(...) from hlsl is causing program to continue running without causing any errors. Is there problem with my understanding of binding global root signature?

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.