|
@@ -0,0 +1,199 @@
|
|
|
+#include <atlbase.h> // Common COM helpers.
|
|
|
+#include "dxc/dxcapi.h" // Be sure to link with dxcompiler.lib.
|
|
|
+#include <d3d12shader.h> // Shader reflection.
|
|
|
+
|
|
|
+// Code from https://github.com/microsoft/DirectXShaderCompiler/wiki/Using-dxc.exe-and-dxcompiler.dll
|
|
|
+// Included here to verify compilation success. If this needs to be altered, please update the wiki as well
|
|
|
+
|
|
|
+int filter(unsigned int code, struct _EXCEPTION_POINTERS *pExceptionInfo) {
|
|
|
+ static char scratch[32];
|
|
|
+ // report all errors with fputs to prevent any allocation
|
|
|
+ if (code == EXCEPTION_ACCESS_VIOLATION) {
|
|
|
+ // use pExceptionInfo to document and report error
|
|
|
+ fputs("access violation. Attempted to ", stderr);
|
|
|
+ if (pExceptionInfo->ExceptionRecord->ExceptionInformation[0])
|
|
|
+ fputs("write", stderr);
|
|
|
+ else
|
|
|
+ fputs("read", stderr);
|
|
|
+ fputs(" from address ", stderr);
|
|
|
+ sprintf_s(scratch, _countof(scratch), "0x%p\n", (void*)pExceptionInfo->ExceptionRecord->ExceptionInformation[1]);
|
|
|
+ fputs(scratch, stderr);
|
|
|
+ return EXCEPTION_EXECUTE_HANDLER;
|
|
|
+ }
|
|
|
+ if (code == EXCEPTION_STACK_OVERFLOW) {
|
|
|
+ // use pExceptionInfo to document and report error
|
|
|
+ fputs("stack overflow\n", stderr);
|
|
|
+ return EXCEPTION_EXECUTE_HANDLER;
|
|
|
+ }
|
|
|
+ fputs("Unrecoverable Error ", stderr);
|
|
|
+ sprintf_s(scratch, _countof(scratch), "0x%08x\n", code);
|
|
|
+ fputs(scratch, stderr);
|
|
|
+ return EXCEPTION_CONTINUE_SEARCH;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+HRESULT Compile(IDxcCompiler3 *pCompiler, DxcBuffer *pSource, LPCWSTR pszArgs[],
|
|
|
+ int argCt, IDxcIncludeHandler *pIncludeHandler, IDxcResult **pResults) {
|
|
|
+
|
|
|
+ __try {
|
|
|
+ return pCompiler->Compile(
|
|
|
+ pSource, // Source buffer.
|
|
|
+ pszArgs, // Array of pointers to arguments.
|
|
|
+ argCt, // Number of arguments.
|
|
|
+ pIncludeHandler, // User-provided interface to handle #include directives (optional).
|
|
|
+ IID_PPV_ARGS(pResults) // Compiler output status, buffer, and errors.
|
|
|
+ );
|
|
|
+ } __except(filter(GetExceptionCode(), GetExceptionInformation())) {
|
|
|
+ // UNRECOVERABLE ERROR!
|
|
|
+ // At this point, state could be extremely corrupt. Terminate the process
|
|
|
+ return E_FAIL;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int main()
|
|
|
+{
|
|
|
+ //
|
|
|
+ // Create compiler and utils.
|
|
|
+ //
|
|
|
+ CComPtr<IDxcUtils> pUtils;
|
|
|
+ CComPtr<IDxcCompiler3> pCompiler;
|
|
|
+ DxcCreateInstance(CLSID_DxcUtils, IID_PPV_ARGS(&pUtils));
|
|
|
+ DxcCreateInstance(CLSID_DxcCompiler, IID_PPV_ARGS(&pCompiler));
|
|
|
+
|
|
|
+ //
|
|
|
+ // Create default include handler. (You can create your own...)
|
|
|
+ //
|
|
|
+ CComPtr<IDxcIncludeHandler> pIncludeHandler;
|
|
|
+ pUtils->CreateDefaultIncludeHandler(&pIncludeHandler);
|
|
|
+
|
|
|
+
|
|
|
+ //
|
|
|
+ // COMMAND LINE: dxc myshader.hlsl -E main -T ps_6_0 -Zi -D MYDEFINE=1 -Fo myshader.bin -Fd myshader.pdb -Qstrip_reflect
|
|
|
+ //
|
|
|
+ LPCWSTR pszArgs[] =
|
|
|
+ {
|
|
|
+ L"myshader.hlsl", // Optional shader source file name for error reporting and for PIX shader source view.
|
|
|
+ L"-E", L"main", // Entry point.
|
|
|
+ L"-T", L"ps_6_0", // Target.
|
|
|
+ L"-Zi", // Enable debug information.
|
|
|
+ L"-D", L"MYDEFINE=1", // A single define.
|
|
|
+ L"-Fo", L"myshader.bin", // Optional. Stored in the pdb.
|
|
|
+ L"-Fd", L"myshader.pdb", // The file name of the pdb. This must either be supplied or the autogenerated file name must be used.
|
|
|
+ L"-Qstrip_reflect", // Strip reflection into a separate blob.
|
|
|
+ };
|
|
|
+
|
|
|
+
|
|
|
+ //
|
|
|
+ // Open source file.
|
|
|
+ //
|
|
|
+ CComPtr<IDxcBlobEncoding> pSource = nullptr;
|
|
|
+ pUtils->LoadFile(L"myshader.hlsl", nullptr, &pSource);
|
|
|
+ DxcBuffer Source;
|
|
|
+ Source.Ptr = pSource->GetBufferPointer();
|
|
|
+ Source.Size = pSource->GetBufferSize();
|
|
|
+ Source.Encoding = DXC_CP_ACP; // Assume BOM says UTF8 or UTF16 or this is ANSI text.
|
|
|
+
|
|
|
+ //
|
|
|
+ // Compile it with specified arguments.
|
|
|
+ //
|
|
|
+ CComPtr<IDxcResult> pResults;
|
|
|
+ if (FAILED(Compile(pCompiler, &Source, pszArgs, _countof(pszArgs), pIncludeHandler, &pResults)))
|
|
|
+ {
|
|
|
+
|
|
|
+ // Either an unrecoverable error exception was caught or a failing HRESULT was returned
|
|
|
+ // Use fputs to prevent any chance of new allocations
|
|
|
+ // Terminate the process
|
|
|
+ puts("Internal error or API misuse! Compile Failed\n");
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ //
|
|
|
+ // Print errors if present.
|
|
|
+ //
|
|
|
+ CComPtr<IDxcBlobUtf8> pErrors = nullptr;
|
|
|
+ // Note that d3dcompiler would return null if no errors or warnings are present.
|
|
|
+ // IDxcCompiler3::Compile will always return an error buffer, but its length will be zero if there are no warnings or errors.
|
|
|
+ if (SUCCEEDED(pResults->GetOutput(DXC_OUT_ERRORS, IID_PPV_ARGS(&pErrors), nullptr)) &&
|
|
|
+ pErrors != nullptr && pErrors->GetStringLength() != 0)
|
|
|
+ wprintf(L"Warnings and Errors:\n%S\n", pErrors->GetStringPointer());
|
|
|
+
|
|
|
+ //
|
|
|
+ // Quit if the compilation failed.
|
|
|
+ //
|
|
|
+ HRESULT hrStatus;
|
|
|
+ if (FAILED(pResults->GetStatus(&hrStatus)) || FAILED(hrStatus))
|
|
|
+ {
|
|
|
+ // Compilation failed, but successful HRESULT was returned.
|
|
|
+ // Could reuse the compiler and allocator objects. For simplicity, exit here anyway
|
|
|
+ wprintf(L"Compilation Failed\n");
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ //
|
|
|
+ // Save shader binary.
|
|
|
+ //
|
|
|
+ CComPtr<IDxcBlob> pShader = nullptr;
|
|
|
+ CComPtr<IDxcBlobUtf16> pShaderName = nullptr;
|
|
|
+ if (SUCCEEDED(pResults->GetOutput(DXC_OUT_OBJECT, IID_PPV_ARGS(&pShader), &pShaderName)) &&
|
|
|
+ pShader != nullptr)
|
|
|
+ {
|
|
|
+ FILE* fp = NULL;
|
|
|
+
|
|
|
+ _wfopen_s(&fp, pShaderName->GetStringPointer(), L"wb");
|
|
|
+ fwrite(pShader->GetBufferPointer(), pShader->GetBufferSize(), 1, fp);
|
|
|
+ fclose(fp);
|
|
|
+ }
|
|
|
+
|
|
|
+ //
|
|
|
+ // Save pdb.
|
|
|
+ //
|
|
|
+ CComPtr<IDxcBlob> pPDB = nullptr;
|
|
|
+ CComPtr<IDxcBlobUtf16> pPDBName = nullptr;
|
|
|
+ if(SUCCEEDED(pResults->GetOutput(DXC_OUT_PDB, IID_PPV_ARGS(&pPDB), &pPDBName)))
|
|
|
+ {
|
|
|
+ FILE* fp = NULL;
|
|
|
+
|
|
|
+ // Note that if you don't specify -Fd, a pdb name will be automatically generated. Use this file name to save the pdb so that PIX can find it quickly.
|
|
|
+ _wfopen_s(&fp, pPDBName->GetStringPointer(), L"wb");
|
|
|
+ fwrite(pPDB->GetBufferPointer(), pPDB->GetBufferSize(), 1, fp);
|
|
|
+ fclose(fp);
|
|
|
+ }
|
|
|
+
|
|
|
+ //
|
|
|
+ // Print hash.
|
|
|
+ //
|
|
|
+ CComPtr<IDxcBlob> pHash = nullptr;
|
|
|
+ if (SUCCEEDED(pResults->GetOutput(DXC_OUT_SHADER_HASH, IID_PPV_ARGS(&pHash), nullptr)) &&
|
|
|
+ pHash != nullptr)
|
|
|
+ {
|
|
|
+ wprintf(L"Hash: ");
|
|
|
+ DxcShaderHash* pHashBuf = (DxcShaderHash*)pHash->GetBufferPointer();
|
|
|
+ for (int i = 0; i < _countof(pHashBuf->HashDigest); i++)
|
|
|
+ wprintf(L"%x", pHashBuf->HashDigest[i]);
|
|
|
+ wprintf(L"\n");
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ //
|
|
|
+ // Get separate reflection.
|
|
|
+ //
|
|
|
+ CComPtr<IDxcBlob> pReflectionData;
|
|
|
+ if (SUCCEEDED(pResults->GetOutput(DXC_OUT_REFLECTION, IID_PPV_ARGS(&pReflectionData), nullptr)) &&
|
|
|
+ pReflectionData != nullptr)
|
|
|
+ {
|
|
|
+ // Optionally, save reflection blob for later here.
|
|
|
+
|
|
|
+ // Create reflection interface.
|
|
|
+ DxcBuffer ReflectionData;
|
|
|
+ ReflectionData.Encoding = DXC_CP_ACP;
|
|
|
+ ReflectionData.Ptr = pReflectionData->GetBufferPointer();
|
|
|
+ ReflectionData.Size = pReflectionData->GetBufferSize();
|
|
|
+
|
|
|
+ CComPtr< ID3D12ShaderReflection > pReflection;
|
|
|
+ pUtils->CreateReflection(&ReflectionData, IID_PPV_ARGS(&pReflection));
|
|
|
+
|
|
|
+ // Use reflection interface here.
|
|
|
+
|
|
|
+ }
|
|
|
+}
|