summaryrefslogtreecommitdiffstats
path: root/source/compiler-core/slang-tint-compiler.cpp
blob: c656f9ba1780bcf2b85db05d8519f3ad2e291fb8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include "slang-tint-compiler.h"

#include "../../external/slang-tint-headers/slang-tint.h"
#include "slang-artifact-associated-impl.h"

namespace Slang
{

class TintDownstreamCompiler : public DownstreamCompilerBase
{

public:
    // IDownstreamCompiler
    virtual SLANG_NO_THROW SlangResult SLANG_MCALL
    compile(const CompileOptions& options, IArtifact** outResult) SLANG_OVERRIDE;

    virtual SLANG_NO_THROW bool SLANG_MCALL
    canConvert(const ArtifactDesc& from, const ArtifactDesc& to) SLANG_OVERRIDE;

    virtual SLANG_NO_THROW SlangResult SLANG_MCALL
    convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) SLANG_OVERRIDE;

    virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased() SLANG_OVERRIDE { return false; }

    virtual SLANG_NO_THROW SlangResult SLANG_MCALL getVersionString(slang::IBlob** outVersionString)
        SLANG_OVERRIDE;

    SlangResult compile(IArtifact* const sourceArtifact, IArtifact** outArtifact);

    SlangResult init(ISlangSharedLibrary* library);

protected:
    ComPtr<ISlangSharedLibrary> m_sharedLibrary;

private:
    tint_CompileFunc m_compile;
    tint_FreeResultFunc m_freeResult;
};

SlangResult TintDownstreamCompiler::init(ISlangSharedLibrary* library)
{
    tint_CompileFunc compile = (tint_CompileFunc)library->findFuncByName("tint_compile");
    if (compile == nullptr)
    {
        return SLANG_FAIL;
    }

    tint_FreeResultFunc freeResult =
        (tint_FreeResultFunc)library->findFuncByName("tint_free_result");
    if (freeResult == nullptr)
    {
        return SLANG_FAIL;
    }

    m_sharedLibrary = library;
    m_desc = Desc(SLANG_PASS_THROUGH_TINT);
    m_compile = compile;
    m_freeResult = freeResult;
    return SLANG_OK;
}

SlangResult TintDownstreamCompilerUtil::locateCompilers(
    const String& path,
    ISlangSharedLibraryLoader* loader,
    DownstreamCompilerSet* set)
{
    ComPtr<ISlangSharedLibrary> library;
    SLANG_RETURN_ON_FAIL(
        DownstreamCompilerUtil::loadSharedLibrary(path, loader, nullptr, "slang-tint", library));
    SLANG_ASSERT(library);

    ComPtr<IDownstreamCompiler> compiler =
        ComPtr<IDownstreamCompiler>(new TintDownstreamCompiler());
    SLANG_RETURN_ON_FAIL(static_cast<TintDownstreamCompiler*>(compiler.get())->init(library));

    set->addCompiler(compiler);
    return SLANG_OK;
}

SlangResult TintDownstreamCompiler::compile(const CompileOptions& options, IArtifact** outArtifact)
{
    IArtifact* sourceArtifact = options.sourceArtifacts[0];
    return compile(sourceArtifact, outArtifact);
}

SlangResult TintDownstreamCompiler::compile(
    IArtifact* const sourceArtifact,
    IArtifact** outArtifact)
{
    tint_CompileRequest req = {};

    if (sourceArtifact == nullptr)
        return SLANG_FAIL;

    ComPtr<ISlangBlob> sourceBlob;
    SLANG_RETURN_FALSE_ON_FAIL(sourceArtifact->loadBlob(ArtifactKeep::Yes, sourceBlob.writeRef()));

    String wgslCode(
        (char*)sourceBlob->getBufferPointer(),
        (char*)sourceBlob->getBufferPointer() + sourceBlob->getBufferSize());
    req.wgslCode = wgslCode.begin();
    req.wgslCodeLength = wgslCode.getLength();

    tint_CompileResult result = {};
    SLANG_DEFER(m_freeResult(&result));
    bool compileSucceeded = m_compile(&req, &result) == 0;

    ComPtr<ISlangBlob> spirvBlob = RawBlob::create(result.buffer, result.bufferSize);
    result.buffer = nullptr;

    ComPtr<IArtifact> resultArtifact =
        ArtifactUtil::createArtifactForCompileTarget(SlangCompileTarget::SLANG_WGSL_SPIRV);
    auto diagnostics = ArtifactDiagnostics::create();
    diagnostics->setResult(compileSucceeded ? SLANG_OK : SLANG_FAIL);
    ArtifactUtil::addAssociated(resultArtifact, diagnostics);
    if (compileSucceeded)
    {
        resultArtifact->addRepresentationUnknown(spirvBlob);
    }
    else
    {
        diagnostics->setRaw(CharSlice(result.error));
        diagnostics->requireErrorDiagnostic();
    }

    *outArtifact = resultArtifact.detach();
    return SLANG_OK;
}

bool TintDownstreamCompiler::canConvert(const ArtifactDesc& from, const ArtifactDesc& to)
{
    return (from.payload == ArtifactPayload::WGSL) && (to.payload == ArtifactPayload::SPIRV);
}

SlangResult TintDownstreamCompiler::convert(
    IArtifact* from,
    const ArtifactDesc& to,
    IArtifact** outArtifact)
{
    if (!canConvert(from->getDesc(), to))
        return SLANG_FAIL;
    return compile(from, outArtifact);
}

SlangResult TintDownstreamCompiler::getVersionString(slang::IBlob** /* outVersionString */)
{
    // We just use Tint at whatever version is in our Dawn fork, so nobody should
    // depend on the particular version at the moment.
    return SLANG_FAIL;
}

} // namespace Slang