summaryrefslogtreecommitdiffstats
path: root/source/slang/slang-dxc-support.cpp
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2019-05-31 17:20:37 -0400
committerGitHub <noreply@github.com>2019-05-31 17:20:37 -0400
commit6cbc3929a54d37bd23cb5efa8e3320ba02f78b2f (patch)
tree5a23cb47782e9e2a77762c90dd35da1005eba8d0 /source/slang/slang-dxc-support.cpp
parentb81ff3ef968d1cc4e954b31a1812b3c391d17b02 (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.cpp302
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
+
+
+