• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Amber Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "src/dxc_helper.h"
16 
17 #include <algorithm>
18 #include <sstream>
19 
20 #include "src/platform.h"
21 
22 #if AMBER_PLATFORM_WINDOWS
23 #pragma warning(push)
24 #pragma warning(disable : 4267)
25 #pragma warning(disable : 4003)
26 #endif  // AMBER_PLATFORM_WINDOWS
27 
28 // clang-format off
29 // The order here matters, so don't reformat.
30 #include "dxc/Support/WinAdapter.h"
31 #include "dxc/Support/WinIncludes.h"
32 #include "dxc/Support/Global.h"
33 #include "dxc/Support/HLSLOptions.h"
34 #include "dxc/Support/dxcapi.use.h"
35 #include "dxc/dxcapi.h"
36 // clang-format on
37 
38 #if AMBER_PLATFORM_WINDOWS
39 #pragma warning(pop)
40 #endif  // AMBER_PLATFORM_WINDOWS
41 
42 namespace amber {
43 namespace dxchelper {
44 namespace {
45 
46 const wchar_t* kDxcFlags[] = {
47     L"-spirv",               // SPIR-V compilation
48     L"-fcgl",                // No SPIR-V Optimization
49     L"-enable-16bit-types",  // Enabling 16bit types
50 };
51 const size_t kDxcFlagsCount = sizeof(kDxcFlags) / sizeof(const wchar_t*);
52 
53 // Converts an IDxcBlob into a vector of 32-bit unsigned integers which
54 // is returned via the 'binaryWords' argument.
ConvertIDxcBlobToUint32(IDxcBlob * blob,std::vector<uint32_t> * binaryWords)55 void ConvertIDxcBlobToUint32(IDxcBlob* blob,
56                              std::vector<uint32_t>* binaryWords) {
57   size_t num32BitWords = (blob->GetBufferSize() + 3) / 4;
58   std::string binaryStr(static_cast<char*>(blob->GetBufferPointer()),
59                         blob->GetBufferSize());
60   binaryStr.resize(num32BitWords * 4, 0);
61   binaryWords->resize(num32BitWords, 0);
62   memcpy(binaryWords->data(), binaryStr.data(), binaryStr.size());
63 }
64 
65 }  // namespace
66 
Compile(const std::string & src,const std::string & entry,const std::string & profile,const std::string & spv_env,std::vector<uint32_t> * generated_binary)67 Result Compile(const std::string& src,
68                const std::string& entry,
69                const std::string& profile,
70                const std::string& spv_env,
71                std::vector<uint32_t>* generated_binary) {
72   DxcInitThreadMalloc();
73 
74   if (hlsl::options::initHlslOptTable()) {
75     DxcCleanupThreadMalloc();
76     return Result("DXC compile failure: initHlslOptTable");
77   }
78 
79   IDxcLibrary* dxc_lib;
80   if (DxcCreateInstance(CLSID_DxcLibrary, __uuidof(IDxcLibrary),
81                         reinterpret_cast<void**>(&dxc_lib)) < 0) {
82     DxcCleanupThreadMalloc();
83     return Result("DXCCreateInstance for DXCLibrary failed");
84   }
85 
86   IDxcBlobEncoding* source;
87   if (dxc_lib->CreateBlobWithEncodingOnHeapCopy(
88           src.data(), static_cast<uint32_t>(src.size()), CP_UTF8, &source) <
89       0) {
90     DxcCleanupThreadMalloc();
91     return Result("DXC compile failure: CreateBlobFromFile");
92   }
93 
94   IDxcIncludeHandler* include_handler;
95   if (dxc_lib->CreateIncludeHandler(&include_handler) < 0) {
96     DxcCleanupThreadMalloc();
97     return Result("DXC compile failure: CreateIncludeHandler");
98   }
99 
100   IDxcCompiler* compiler;
101   if (DxcCreateInstance(CLSID_DxcCompiler, __uuidof(IDxcCompiler),
102                         reinterpret_cast<void**>(&compiler)) < 0) {
103     DxcCleanupThreadMalloc();
104     return Result("DXCCreateInstance for DXCCompiler failed");
105   }
106 
107   IDxcOperationResult* result;
108   std::wstring src_filename =
109       L"amber." + std::wstring(profile.begin(), profile.end());
110 
111   std::vector<const wchar_t*> dxc_flags(kDxcFlags, &kDxcFlags[kDxcFlagsCount]);
112   const wchar_t* target_env = nullptr;
113   if (!spv_env.compare("spv1.3") || !spv_env.compare("vulkan1.1")) {
114     target_env = L"-fspv-target-env=vulkan1.1";
115   } else if (!spv_env.compare("spv1.0") || !spv_env.compare("vulkan1.0")) {
116     target_env = L"-fspv-target-env=vulkan1.0";
117   } else if (!spv_env.empty()) {
118     return Result(
119         "Invalid target environment. Choose spv1.3 or vulkan1.1 for vulkan1.1 "
120         "and spv1.0 or vulkan1.0 for vulkan1.0.");
121   }
122   if (target_env)
123     dxc_flags.push_back(target_env);
124 
125   if (compiler->Compile(source,               /* source text */
126                         src_filename.c_str(), /* original file source */
127                         std::wstring(entry.begin(), entry.end())
128                             .c_str(), /* entry point name */
129                         std::wstring(profile.begin(), profile.end())
130                             .c_str(),     /* shader profile to compile */
131                         dxc_flags.data(), /* arguments */
132                         dxc_flags.size(), /* argument count */
133                         nullptr,          /* defines */
134                         0,                /* define count */
135                         include_handler,  /* handler for #include */
136                         &result /* output status */) < 0) {
137     DxcCleanupThreadMalloc();
138     return Result("DXC compile failure: Compile");
139   }
140 
141   // Compilation is done. We can clean up the HlslOptTable.
142   hlsl::options::cleanupHlslOptTable();
143 
144   // Get compilation results.
145   HRESULT result_status;
146   if (result->GetStatus(&result_status) < 0) {
147     DxcCleanupThreadMalloc();
148     return Result("DXC compile failure: GetStatus");
149   }
150 
151   // Get diagnostics string.
152   IDxcBlobEncoding* error_buffer;
153   if (result->GetErrorBuffer(&error_buffer)) {
154     DxcCleanupThreadMalloc();
155     return Result("DXC compile failure: GetErrorBuffer");
156   }
157 
158   const std::string diagnostics(
159       static_cast<char*>(error_buffer->GetBufferPointer()),
160       error_buffer->GetBufferSize());
161 
162   bool success = true;
163   if (SUCCEEDED(result_status)) {
164     IDxcBlob* compiled_blob;
165     if (result->GetResult(&compiled_blob) < 0) {
166       DxcCleanupThreadMalloc();
167       return Result("DXC compile failure: GetResult");
168     }
169     ConvertIDxcBlobToUint32(compiled_blob, generated_binary);
170   } else {
171     success = false;
172   }
173 
174   DxcCleanupThreadMalloc();
175   return success ? Result() : Result("DXC compile failure: " + diagnostics);
176 }
177 
178 }  // namespace dxchelper
179 }  // namespace amber
180