diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2019-05-31 17:20:37 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-05-31 17:20:37 -0400 |
| commit | 6cbc3929a54d37bd23cb5efa8e3320ba02f78b2f (patch) | |
| tree | 5a23cb47782e9e2a77762c90dd35da1005eba8d0 /source/slang/slang-dxc-support.cpp | |
| parent | b81ff3ef968d1cc4e954b31a1812b3c391d17b02 (diff) | |
Use slang- prefix on slang compiler and core source (#973)
* Prefixing source files in source/slang with slang-
* Prefix source in source/slang with slang- prefix.
* Rename core source files with slang- prefix.
* Update project files.
* Fix problems from automatic merge.
Diffstat (limited to 'source/slang/slang-dxc-support.cpp')
| -rw-r--r-- | source/slang/slang-dxc-support.cpp | 302 |
1 files changed, 302 insertions, 0 deletions
diff --git a/source/slang/slang-dxc-support.cpp b/source/slang/slang-dxc-support.cpp new file mode 100644 index 000000000..b4bc77fe5 --- /dev/null +++ b/source/slang/slang-dxc-support.cpp @@ -0,0 +1,302 @@ +// slang-dxc-support.cpp +#include "slang-compiler.h" + +// This file implements support for invoking the `dxcompiler` +// library to translate HLSL to DXIL. + +#if defined(_WIN32) +# if !defined(SLANG_ENABLE_DXIL_SUPPORT) +# define SLANG_ENABLE_DXIL_SUPPORT 1 +# endif +#endif + +#if !defined(SLANG_ENABLE_DXIL_SUPPORT) +# define SLANG_ENABLE_DXIL_SUPPORT 0 +#endif + +#if SLANG_ENABLE_DXIL_SUPPORT + +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX +#include <Windows.h> +#include <Unknwn.h> +#include "../../external/dxc/dxcapi.h" +#undef WIN32_LEAN_AND_MEAN +#undef NOMINMAX + +#include "../core/slang-platform.h" + +namespace Slang +{ + String GetHLSLProfileName(Profile profile); + String emitHLSLForEntryPoint( + BackEndCompileRequest* compileRequest, + EntryPoint* entryPoint, + Int entryPointIndex, + TargetRequest* targetReq, + EndToEndCompileRequest* endToEndReq); + + static UnownedStringSlice _getSlice(IDxcBlob* blob) + { + if (blob) + { + const char* chars = (const char*)blob->GetBufferPointer(); + size_t len = blob->GetBufferSize(); + len -= size_t(len > 0 && chars[len - 1] == 0); + return UnownedStringSlice(chars, len); + } + return UnownedStringSlice(); + } + + SlangResult emitDXILForEntryPointUsingDXC( + BackEndCompileRequest* compileRequest, + EntryPoint* entryPoint, + Int entryPointIndex, + TargetRequest* targetReq, + EndToEndCompileRequest* endToEndReq, + List<uint8_t>& outCode) + { + auto session = compileRequest->getSession(); + auto sink = compileRequest->getSink(); + + // First deal with all the rigamarole of loading + // the `dxcompiler` library, and creating the + // top-level COM objects that will be used to + // compile things. + + auto dxcCreateInstance = (DxcCreateInstanceProc)session->getSharedLibraryFunc(Session::SharedLibraryFuncType::Dxc_DxcCreateInstance, sink); + if (!dxcCreateInstance) + { + return SLANG_FAIL; + } + + { + if (!session->getSharedLibrary(SharedLibraryType::Dxil)) + { + // If can't load dxil - dxc will not be able to sign output + // Output a suitable warning to the user + sink->diagnose(SourceLoc(), Diagnostics::dxilNotFound); + } + } + + ComPtr<IDxcCompiler> dxcCompiler; + SLANG_RETURN_ON_FAIL(dxcCreateInstance( + CLSID_DxcCompiler, + __uuidof(dxcCompiler), + (LPVOID*)dxcCompiler.writeRef())); + + ComPtr<IDxcLibrary> dxcLibrary; + SLANG_RETURN_ON_FAIL(dxcCreateInstance( + CLSID_DxcLibrary, + __uuidof(dxcLibrary), + (LPVOID*)dxcLibrary.writeRef())); + + // Now let's go ahead and generate HLSL for the entry + // point, since we'll need that to feed into dxc. + auto hlslCode = emitHLSLForEntryPoint( + compileRequest, + entryPoint, + entryPointIndex, + targetReq, + endToEndReq); + maybeDumpIntermediate(compileRequest, hlslCode.getBuffer(), CodeGenTarget::HLSL); + + // Wrap the + + // Create blob from the string + ComPtr<IDxcBlobEncoding> dxcSourceBlob; + SLANG_RETURN_ON_FAIL(dxcLibrary->CreateBlobWithEncodingFromPinned( + (LPBYTE)hlslCode.getBuffer(), + (UINT32)hlslCode.getLength(), + 0, + dxcSourceBlob.writeRef())); + + WCHAR const* args[16]; + UINT32 argCount = 0; + + // TODO: deal with + bool treatWarningsAsErrors = false; + if (treatWarningsAsErrors) + { + args[argCount++] = L"-WX"; + } + + switch( targetReq->getDefaultMatrixLayoutMode() ) + { + default: + break; + + case kMatrixLayoutMode_RowMajor: + args[argCount++] = L"-Zpr"; + break; + } + + switch( targetReq->getFloatingPointMode() ) + { + default: + break; + + case FloatingPointMode::Precise: + args[argCount++] = L"-Gis"; // "force IEEE strictness" + break; + } + + auto linkage = compileRequest->getLinkage(); + switch( linkage->optimizationLevel ) + { + default: + break; + + case OptimizationLevel::None: args[argCount++] = L"-Od"; break; + case OptimizationLevel::Default: args[argCount++] = L"-O1"; break; + case OptimizationLevel::High: args[argCount++] = L"-O2"; break; + case OptimizationLevel::Maximal: args[argCount++] = L"-O3"; break; + } + + switch( linkage->debugInfoLevel ) + { + case DebugInfoLevel::None: + break; + + default: + args[argCount++] = L"-Zi"; + break; + } + + // Slang strives to produce correct code, and by default + // we do not show the user warnings produced by a downstream + // compiler. When the downstream compiler *does* produce an + // error, then we dump its entire diagnostic log, which can + // include many distracting spurious warnings that have nothing + // to do with the user's code, and just relate to the idiomatic + // way that Slang outputs HLSL. + // + // It would be nice to use fine-grained flags to disable specific + // warnings here, so that we keep ourselves honest (e.g., only + // use `-Wno-parentheses` to eliminate that class of false positives), + // but alas dxc doesn't support these options even though they + // work on mainline Clang. Thus the only option we have available + // is the big hammer of turning off *all* warnings coming from dxc. + // + args[argCount++] = L"-no-warnings"; + + String entryPointName = getText(entryPoint->getName()); + OSString wideEntryPointName = entryPointName.toWString(); + + auto profile = getEffectiveProfile(entryPoint, targetReq); + String profileName = GetHLSLProfileName(profile); + OSString wideProfileName = profileName.toWString(); + + // We will enable the flag to generate proper code for 16-bit types + // by default, as long as the user is requesting a sufficiently + // high shader model. + // + // TODO: Need to check that this is safe to enable in all cases, + // or if it will make a shader demand hardware features that + // aren't always present. + // + // TODO: Ideally the dxc back-end should be passed some information + // on the "capabilities" that were used and/or requested in the code. + // + if( profile.GetVersion() >= ProfileVersion::DX_6_2 ) + { + args[argCount++] = L"-enable-16bit-types"; + } + + const String sourcePath = calcSourcePathForEntryPoint(endToEndReq, entryPointIndex); + + ComPtr<IDxcOperationResult> dxcResult; + SLANG_RETURN_ON_FAIL(dxcCompiler->Compile(dxcSourceBlob, + sourcePath.toWString().begin(), + profile.GetStage() == Stage::Unknown ? L"" : wideEntryPointName.begin(), + wideProfileName.begin(), + args, + argCount, + nullptr, // `#define`s + 0, // `#define` count + nullptr, // `#include` handler + dxcResult.writeRef())); + + // Retrieve result. + HRESULT resultCode = S_OK; + SLANG_RETURN_ON_FAIL(dxcResult->GetStatus(&resultCode)); + + // Note: it seems like the dxcompiler interface + // doesn't support querying diagnostic output + // *unless* the compile failed (no way to get + // warnings out!?). + + // Verify compile result + if (SLANG_FAILED(resultCode)) + { + // Compilation failed. + // Try to read any diagnostic output. + ComPtr<IDxcBlobEncoding> dxcErrorBlob; + SLANG_RETURN_ON_FAIL(dxcResult->GetErrorBuffer(dxcErrorBlob.writeRef())); + + // Note: the error blob returned by dxc doesn't always seem + // to be nul-terminated, so we should be careful and turn it + // into a string for safety. + // + + reportExternalCompileError("dxc", resultCode, _getSlice(dxcErrorBlob), compileRequest->getSink()); + return resultCode; + } + + // Okay, the compile supposedly succeeded, so we + // just need to grab the buffer with the output DXIL. + ComPtr<IDxcBlob> dxcResultBlob; + SLANG_RETURN_ON_FAIL(dxcResult->GetResult(dxcResultBlob.writeRef())); + + outCode.addRange( + (uint8_t const*)dxcResultBlob->GetBufferPointer(), + (int) dxcResultBlob->GetBufferSize()); + + return SLANG_OK; + } + + SlangResult dissassembleDXILUsingDXC( + BackEndCompileRequest* compileRequest, + void const* data, + size_t size, + String& stringOut) + { + stringOut = String(); + auto session = compileRequest->getSession(); + auto sink = compileRequest->getSink(); + + // First deal with all the rigamarole of loading + // the `dxcompiler` library, and creating the + // top-level COM objects that will be used to + // compile things. + + auto dxcCreateInstance = (DxcCreateInstanceProc)session->getSharedLibraryFunc(Session::SharedLibraryFuncType::Dxc_DxcCreateInstance, sink); + if (!dxcCreateInstance) + { + return SLANG_FAIL; + } + + ComPtr<IDxcCompiler> dxcCompiler; + SLANG_RETURN_ON_FAIL(dxcCreateInstance(CLSID_DxcCompiler, __uuidof(dxcCompiler), (LPVOID*) dxcCompiler.writeRef())); + ComPtr<IDxcLibrary> dxcLibrary; + SLANG_RETURN_ON_FAIL(dxcCreateInstance(CLSID_DxcLibrary, __uuidof(dxcLibrary), (LPVOID*) dxcLibrary.writeRef())); + + // Create blob from the input data + ComPtr<IDxcBlobEncoding> dxcSourceBlob; + SLANG_RETURN_ON_FAIL(dxcLibrary->CreateBlobWithEncodingFromPinned((LPBYTE) data, (UINT32) size, 0, dxcSourceBlob.writeRef())); + + ComPtr<IDxcBlobEncoding> dxcResultBlob; + SLANG_RETURN_ON_FAIL(dxcCompiler->Disassemble(dxcSourceBlob, dxcResultBlob.writeRef())); + + stringOut = _getSlice(dxcResultBlob); + + return SLANG_OK; + } + + +} // namespace Slang + +#endif + + + |
