Implementing ID3D10Include

Warning! Some information on this page is older than 5 years now. I keep it for reference, but it probably doesn't reflect my current knowledge and beliefs.

# Implementing ID3D10Include

Sat
03
Nov 2012

DirectX shaders in HLSL language can use #include preprocessor directive, just like C and C++ code. When you compile a shader from file using D3DX11CompileFromFile function, it works automatically. But what if you keep your shader source in memory and compile it with D3DX11CompileFromMemory? DirectX doesn't know the location of source file (if any), so it can't locate additional files to include.

But there is a solution. Parameter __in LPD3D10INCLUDE pInclude allows passing your own object implementing ID3D10Include interface (a typedef to ID3DInclude) that can help DirectX in loading included files while preprocessing shader source. We don't event have to deal with COM interfaces here. We can just implement and use a class like the one below. The code uses lots of stuff from my CommonLib, so it's not self-contained and ready to copy-paste, but it should give a clue about how to do it.

class CShaderInclude : public ID3DInclude
{
public:
    // shaderDir: Directory of current shader file, used by #include "FILE"
    // systemDir: Default shader includes directory, used by #include <FILE>
    CShaderInclude(const char* shaderDir, const char* systemDir) :
        m_ShaderDir(shaderDir),
        m_SystemDir(systemDir)
    {
    }

    HRESULT __stdcall Open(
        D3D_INCLUDE_TYPE IncludeType,
        LPCSTR pFileName,
        LPCVOID pParentData,
        LPCVOID *ppData,
        UINT *pBytes);
    
    HRESULT __stdcall Close(LPCVOID pData);

private:
    string m_ShaderDir;
    string m_SystemDir;
};

HRESULT __stdcall CShaderInclude::Open(
    D3D_INCLUDE_TYPE IncludeType,
    LPCSTR pFileName,
    LPCVOID pParentData,
    LPCVOID *ppData,
    UINT *pBytes)
{
    try
    {
        /*
        If pFileName is absolute: finalPath = pFileName.
        If pFileName is relative: finalPath = dir + "\\" + pFileName
        */
        string finalPath;
        switch(IncludeType)
        {
        case D3D_INCLUDE_LOCAL: // #include "FILE"
            common::RelativeToAbsolutePath(&finalPath, m_ShaderDir, pFileName);
            break;
        case D3D_INCLUDE_SYSTEM: // #include <FILE>
            common::RelativeToAbsolutePath(&finalPath, m_SystemDir, pFileName);
            break;
        default:
            assert(0);
        }

        common::FileStream fileStream(finalPath, common::FM_READ);
        uint32_t fileSize = fileStream.GetSize();

        if(fileSize)
        {
            char* buf = new char[fileSize];
            fileStream.MustRead(buf, fileSize);

            *ppData = buf;
            *pBytes = fileSize;
        }
        else
        {
            *ppData = nullptr;
            *pBytes = 0;
        }
        return S_OK;
    }
    catch(common::Error& err)
    {
        PrintError(err);
        return E_FAIL;
    }
}

HRESULT __stdcall CShaderInclude::Close(LPCVOID pData)
{
    // Here we must correctly free buffer created in Open.
    char* buf = (char*)pData;
    delete[] buf;
    return S_OK;
}

/*
Inputs:
    std::vector<char> shaderData
    const char* filePath
    const char* functionName
    const char* profile
Outputs:
    HRESULT hr
    ID3DBlob* shaderBlob
    ID3DBlob* errorBlob
*/

string shaderDir;
common::ExtractFilePath(&shaderDir, filePath);

CShaderInclude includeObj(shaderDir.c_str(), "Shaders/Include");

HRESULT hr = D3DX11CompileFromMemory(
    shaderData.data(),
    shaderData.size(),
    filePath,
    nullptr, // pDefines
    &includeObj,
    functionName,
    profile,
    0, // Flags1
    0, // Flags2
    nullptr, // pPump
    &shaderBlob,
    &errorBlob,
    nullptr); // pHResult

Comments | #directx Share

Comments

STAT NO AD
[Stat] [STAT NO AD] [Download] [Dropbox] [pub] [Mirror] [Privacy policy]
Copyright © 2004-2019