• 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 #include "src/virtual_file_store.h"
22 
23 #if AMBER_PLATFORM_WINDOWS
24 #pragma warning(push)
25 #pragma warning(disable : 4267)
26 #pragma warning(disable : 4003)
27 #endif  // AMBER_PLATFORM_WINDOWS
28 
29 #pragma clang diagnostic push
30 #pragma clang diagnostic ignored "-Wreserved-id-macro"
31 #pragma clang diagnostic ignored "-Wextra-semi"
32 #pragma clang diagnostic ignored "-Wdeprecated-dynamic-exception-spec"
33 #pragma clang diagnostic ignored "-Wold-style-cast"
34 #pragma clang diagnostic ignored "-Wshadow-field-in-constructor"
35 #pragma clang diagnostic ignored "-Wconversion"
36 #pragma clang diagnostic ignored "-Wsign-conversion"
37 #pragma clang diagnostic ignored "-Wshadow"
38 #pragma clang diagnostic ignored "-Wweak-vtables"
39 #pragma clang diagnostic ignored "-Wdocumentation-unknown-command"
40 #pragma clang diagnostic ignored "-Wundef"
41 #pragma clang diagnostic ignored "-Wunused-function"
42 #pragma clang diagnostic ignored "-Wunused-parameter"
43 #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
44 #pragma GCC diagnostic push
45 #pragma GCC diagnostic ignored "-Wunused-function"
46 #pragma GCC diagnostic ignored "-Wunused-parameter"
47 #ifndef __STDC_LIMIT_MACROS
48 #define __STDC_LIMIT_MACROS
49 #endif  // __STDC_LIMIT_MACROS
50 #ifndef __STDC_CONSTANT_MACROS
51 #define __STDC_CONSTANT_MACROS
52 #endif  // __STDC_CONSTANT_MACROS
53 
54 // clang-format off
55 // The order here matters, so don't reformat.
56 #include "dxc/Support/Global.h"
57 #include "dxc/Support/HLSLOptions.h"
58 #include "dxc/dxcapi.h"
59 #include "dxc/Support/microcom.h"
60 // clang-format on
61 
62 namespace amber {
63 namespace dxchelper {
64 namespace {
65 
66 const wchar_t* kDxcFlags[] = {
67     L"-spirv",               // SPIR-V compilation
68     L"-fcgl",                // No SPIR-V Optimization
69     L"-enable-16bit-types",  // Enabling 16bit types
70 };
71 const size_t kDxcFlagsCount = sizeof(kDxcFlags) / sizeof(const wchar_t*);
72 
73 // Converts an IDxcBlob into a vector of 32-bit unsigned integers which
74 // is returned via the 'binaryWords' argument.
ConvertIDxcBlobToUint32(IDxcBlob * blob,std::vector<uint32_t> * binaryWords)75 void ConvertIDxcBlobToUint32(IDxcBlob* blob,
76                              std::vector<uint32_t>* binaryWords) {
77   size_t num32BitWords = (blob->GetBufferSize() + 3) / 4;
78   std::string binaryStr(static_cast<char*>(blob->GetBufferPointer()),
79                         blob->GetBufferSize());
80   binaryStr.resize(num32BitWords * 4, 0);
81   binaryWords->resize(num32BitWords, 0);
82   memcpy(binaryWords->data(), binaryStr.data(), binaryStr.size());
83 }
84 
85 class IncludeHandler : public IDxcIncludeHandler {
86  public:
IncludeHandler(const VirtualFileStore * file_store,IDxcLibrary * dxc_lib,IDxcIncludeHandler * fallback)87   IncludeHandler(const VirtualFileStore* file_store,
88                  IDxcLibrary* dxc_lib,
89                  IDxcIncludeHandler* fallback)
90       : file_store_(file_store), dxc_lib_(dxc_lib), fallback_(fallback) {}
91 
LoadSource(LPCWSTR pFilename,IDxcBlob ** ppIncludeSource)92   HRESULT STDMETHODCALLTYPE LoadSource(LPCWSTR pFilename,
93                                        IDxcBlob** ppIncludeSource) override {
94     std::wstring wide_path(pFilename);
95     std::string path = std::string(wide_path.begin(), wide_path.end());
96 
97     std::string content;
98     Result r = file_store_->Get(path, &content);
99     if (r.IsSuccess()) {
100       IDxcBlobEncoding* source;
101       auto res = dxc_lib_->CreateBlobWithEncodingOnHeapCopy(
102           content.data(), static_cast<uint32_t>(content.size()), CP_UTF8,
103           &source);
104       if (res != S_OK) {
105         DxcCleanupThreadMalloc();
106         return res;
107       }
108       *ppIncludeSource = source;
109       return S_OK;
110     }
111 
112     return fallback_->LoadSource(pFilename, ppIncludeSource);
113   }
114 
QueryInterface(REFIID iid,void ** ppvObject)115   HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid,
116                                            void** ppvObject) override {
117     return DoBasicQueryInterface<IDxcIncludeHandler>(this, iid, ppvObject);
118   }
119 
120  private:
121   const VirtualFileStore* const file_store_;
122   IDxcLibrary* const dxc_lib_;
123   IDxcIncludeHandler* const fallback_;
124 };
125 
126 #pragma GCC diagnostic pop
127 #pragma clang diagnostic pop
128 #if AMBER_PLATFORM_WINDOWS
129 #pragma warning(pop)
130 #endif  // AMBER_PLATFORM_WINDOWS
131 
132 }  // namespace
133 
Compile(const std::string & src,const std::string & entry,const std::string & profile,const std::string & spv_env,const std::string & filename,const VirtualFileStore * virtual_files,bool emit_debug_info,std::vector<uint32_t> * generated_binary)134 Result Compile(const std::string& src,
135                const std::string& entry,
136                const std::string& profile,
137                const std::string& spv_env,
138                const std::string& filename,
139                const VirtualFileStore* virtual_files,
140                bool emit_debug_info,
141                std::vector<uint32_t>* generated_binary) {
142   if (hlsl::options::initHlslOptTable()) {
143     DxcCleanupThreadMalloc();
144     return Result("DXC compile failure: initHlslOptTable");
145   }
146 
147   IDxcLibrary* dxc_lib;
148   if (DxcCreateInstance(CLSID_DxcLibrary, __uuidof(IDxcLibrary),
149                         reinterpret_cast<void**>(&dxc_lib)) < 0) {
150     DxcCleanupThreadMalloc();
151     return Result("DXCCreateInstance for DXCLibrary failed");
152   }
153 
154   IDxcBlobEncoding* source;
155   if (dxc_lib->CreateBlobWithEncodingOnHeapCopy(
156           src.data(), static_cast<uint32_t>(src.size()), CP_UTF8, &source) <
157       0) {
158     DxcCleanupThreadMalloc();
159     return Result("DXC compile failure: CreateBlobFromFile");
160   }
161 
162   IDxcIncludeHandler* fallback_include_handler;
163   if (dxc_lib->CreateIncludeHandler(&fallback_include_handler) < 0) {
164     DxcCleanupThreadMalloc();
165     return Result("DXC compile failure: CreateIncludeHandler");
166   }
167 
168   CComPtr<IDxcIncludeHandler> include_handler(
169       new IncludeHandler(virtual_files, dxc_lib, fallback_include_handler));
170 
171   IDxcCompiler* compiler;
172   if (DxcCreateInstance(CLSID_DxcCompiler, __uuidof(IDxcCompiler),
173                         reinterpret_cast<void**>(&compiler)) < 0) {
174     DxcCleanupThreadMalloc();
175     return Result("DXCCreateInstance for DXCCompiler failed");
176   }
177 
178   std::string filepath = filename.empty() ? ("amber." + profile) : filename;
179 
180   std::vector<const wchar_t*> dxc_flags(kDxcFlags, &kDxcFlags[kDxcFlagsCount]);
181   if (emit_debug_info) {  // Enable debug info generation
182     dxc_flags.emplace_back(L"-fspv-debug=rich");
183   }
184 
185   const wchar_t* target_env = nullptr;
186   if (!spv_env.compare("spv1.3") || !spv_env.compare("vulkan1.1")) {
187     target_env = L"-fspv-target-env=vulkan1.1";
188   } else if (!spv_env.compare("spv1.0") || !spv_env.compare("vulkan1.0")) {
189     target_env = L"-fspv-target-env=vulkan1.0";
190   } else if (!spv_env.empty()) {
191     return Result(
192         "Invalid target environment. Choose spv1.3 or vulkan1.1 for vulkan1.1 "
193         "and spv1.0 or vulkan1.0 for vulkan1.0.");
194   }
195   if (target_env)
196     dxc_flags.push_back(target_env);
197 
198   IDxcOperationResult* result;
199   if (compiler->Compile(
200           source, /* source text */
201           std::wstring(filepath.begin(), filepath.end())
202               .c_str(), /* original file source */
203           std::wstring(entry.begin(), entry.end())
204               .c_str(), /* entry point name */
205           std::wstring(profile.begin(), profile.end())
206               .c_str(),     /* shader profile to compile */
207           dxc_flags.data(), /* arguments */
208           static_cast<uint32_t>(dxc_flags.size()), /* argument count */
209           nullptr,                                 /* defines */
210           0,                                       /* define count */
211           include_handler,                         /* handler for #include */
212           &result /* output status */) < 0) {
213     DxcCleanupThreadMalloc();
214     return Result("DXC compile failure: Compile");
215   }
216 
217   // Compilation is done. We can clean up the HlslOptTable.
218   hlsl::options::cleanupHlslOptTable();
219 
220   // Get compilation results.
221   HRESULT result_status;
222   if (result->GetStatus(&result_status) < 0) {
223     DxcCleanupThreadMalloc();
224     return Result("DXC compile failure: GetStatus");
225   }
226 
227   // Get diagnostics string.
228   IDxcBlobEncoding* error_buffer;
229   if (result->GetErrorBuffer(&error_buffer)) {
230     DxcCleanupThreadMalloc();
231     return Result("DXC compile failure: GetErrorBuffer");
232   }
233 
234   const std::string diagnostics(
235       static_cast<char*>(error_buffer->GetBufferPointer()),
236       error_buffer->GetBufferSize());
237 
238   bool success = true;
239   if (static_cast<HRESULT>(result_status) >= 0) {
240     IDxcBlob* compiled_blob;
241     if (result->GetResult(&compiled_blob) < 0) {
242       DxcCleanupThreadMalloc();
243       return Result("DXC compile failure: GetResult");
244     }
245     ConvertIDxcBlobToUint32(compiled_blob, generated_binary);
246   } else {
247     success = false;
248   }
249 
250   DxcCleanupThreadMalloc();
251   return success ? Result() : Result("DXC compile failure: " + diagnostics);
252 }
253 
254 }  // namespace dxchelper
255 }  // namespace amber
256