Cleanup: fix compiler warnings.
[blender-staging.git] / intern / cycles / app / cycles_cubin_cc.cpp
1 /*
2  * Copyright 2017 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <stdint.h>
19
20 #include <string>
21 #include <vector>
22
23 #include <OpenImageIO/argparse.h>
24 #include <OpenImageIO/filesystem.h>
25
26 #include "cuew.h"
27
28 #ifdef _MSC_VER
29 # include <Windows.h>
30 #endif
31
32 using std::string;
33 using std::vector;
34
35 namespace std {
36         template<typename T>
37         std::string to_string(const T &n) {
38                 std::ostringstream s;
39                 s << n;
40                 return s.str();
41         }
42 }
43
44 class CompilationSettings
45 {
46 public:
47         CompilationSettings()
48         : target_arch(0),
49           bits(64),
50           verbose(false),
51           fast_math(false)
52         {}
53
54         string cuda_toolkit_dir;
55         string input_file;
56         string output_file;
57         string ptx_file;
58         vector<string> defines;
59         vector<string> includes;
60         int target_arch;
61         int bits;
62         bool verbose;
63         bool fast_math;
64 };
65
66 static bool compile_cuda(CompilationSettings &settings)
67 {
68         const char* headers[] = {"stdlib.h" , "float.h", "math.h", "stdio.h"};
69         const char* header_content[] = {"\n", "\n", "\n", "\n"};
70
71         printf("Building %s\n", settings.input_file.c_str());
72
73         string code;
74         if(!OIIO::Filesystem::read_text_file(settings.input_file, code)) {
75                 fprintf(stderr, "Error: unable to read %s\n", settings.input_file.c_str());
76                 return false;
77         }
78
79         vector<string> options;
80         for(size_t i = 0; i < settings.includes.size(); i++) {
81                 options.push_back("-I" + settings.includes[i]);
82         }
83
84         for(size_t i = 0; i < settings.defines.size(); i++) {
85                 options.push_back("-D" + settings.defines[i]);
86         }
87         options.push_back("-D__KERNEL_CUDA_VERSION__=" + std::to_string(cuewNvrtcVersion()));
88         options.push_back("-arch=compute_" + std::to_string(settings.target_arch));
89         options.push_back("--device-as-default-execution-space");
90         if(settings.fast_math)
91                 options.push_back("--use_fast_math");
92
93         nvrtcProgram prog;
94         nvrtcResult result = nvrtcCreateProgram(&prog,
95                 code.c_str(),                    // buffer
96                 NULL,                            // name
97                 sizeof(headers) / sizeof(void*), // numHeaders
98                 header_content,                  // headers
99                 headers);                        // includeNames
100
101         if(result != NVRTC_SUCCESS) {
102                 fprintf(stderr, "Error: nvrtcCreateProgram failed (%d)\n\n", (int)result);
103                 return false;
104         }
105
106         /* Tranfer options to a classic C array. */
107         vector<const char*> opts(options.size());
108         for(size_t i = 0; i < options.size(); i++) {
109                 opts[i] = options[i].c_str();
110         }
111
112         result = nvrtcCompileProgram(prog, options.size(), &opts[0]);
113
114         if(result != NVRTC_SUCCESS) {
115                 fprintf(stderr, "Error: nvrtcCompileProgram failed (%d)\n\n", (int)result);
116
117                 size_t log_size;
118                 nvrtcGetProgramLogSize(prog, &log_size);
119
120                 vector<char> log(log_size);
121                 nvrtcGetProgramLog(prog, &log[0]);
122                 fprintf(stderr, "%s\n", &log[0]);
123
124                 return false;
125         }
126
127         /* Retrieve the ptx code. */
128         size_t ptx_size;
129         result = nvrtcGetPTXSize(prog, &ptx_size);
130         if(result != NVRTC_SUCCESS) {
131                 fprintf(stderr, "Error: nvrtcGetPTXSize failed (%d)\n\n", (int)result);
132                 return false;
133         }
134
135         vector<char> ptx_code(ptx_size);
136         result = nvrtcGetPTX(prog, &ptx_code[0]);
137         if(result != NVRTC_SUCCESS) {
138                 fprintf(stderr, "Error: nvrtcGetPTX failed (%d)\n\n", (int)result);
139                 return false;
140         }
141
142         /* Write a file in the temp folder with the ptx code. */
143         settings.ptx_file = OIIO::Filesystem::temp_directory_path() + "/" + OIIO::Filesystem::unique_path();
144         FILE * f= fopen(settings.ptx_file.c_str(), "wb");
145         fwrite(&ptx_code[0], 1, ptx_size, f);
146         fclose(f);
147
148         return true;
149 }
150
151 static bool link_ptxas(CompilationSettings &settings)
152 {
153         string cudapath = "";
154         if(settings.cuda_toolkit_dir.size())
155                 cudapath = settings.cuda_toolkit_dir + "/bin/";
156
157         string ptx = "\"" +cudapath + "ptxas\" " + settings.ptx_file +
158                                         " -o " + settings.output_file +
159                                         " --gpu-name sm_" + std::to_string(settings.target_arch) +
160                                         " -m" + std::to_string(settings.bits);
161
162         if(settings.verbose) {
163                 ptx += " --verbose";
164                 printf("%s\n", ptx.c_str());
165         }
166
167         int pxresult = system(ptx.c_str());
168         if(pxresult) {
169                 fprintf(stderr, "Error: ptxas failed (%d)\n\n", pxresult);
170                 return false;
171         }
172
173         if(!OIIO::Filesystem::remove(settings.ptx_file)) {
174                 fprintf(stderr, "Error: removing %s\n\n", settings.ptx_file.c_str());
175         }
176
177         return true;
178 }
179
180 static bool init(CompilationSettings &settings)
181 {
182 #ifdef _MSC_VER
183         if(settings.cuda_toolkit_dir.size()) {
184                 SetDllDirectory((settings.cuda_toolkit_dir + "/bin").c_str());
185         }
186 #else
187         (void)settings;
188 #endif
189
190         int cuewresult = cuewInit(CUEW_INIT_NVRTC);
191         if(cuewresult != CUEW_SUCCESS) {
192                 fprintf(stderr, "Error: cuew init fialed (0x%d)\n\n", cuewresult);
193                 return false;
194         }
195
196         if(cuewNvrtcVersion() < 80) {
197                 fprintf(stderr, "Error: only cuda 8 and higher is supported, %d\n\n", cuewCompilerVersion());
198                 return false;
199         }
200
201         if(!nvrtcCreateProgram) {
202                 fprintf(stderr, "Error: nvrtcCreateProgram not resolved\n");
203                 return false;
204         }
205
206         if(!nvrtcCompileProgram) {
207                 fprintf(stderr, "Error: nvrtcCompileProgram not resolved\n");
208                 return false;
209         }
210
211         if(!nvrtcGetProgramLogSize) {
212                 fprintf(stderr, "Error: nvrtcGetProgramLogSize not resolved\n");
213                 return false;
214         }
215
216         if(!nvrtcGetProgramLog) {
217                 fprintf(stderr, "Error: nvrtcGetProgramLog not resolved\n");
218                 return false;
219         }
220
221         if(!nvrtcGetPTXSize) {
222                 fprintf(stderr, "Error: nvrtcGetPTXSize not resolved\n");
223                 return false;
224         }
225
226         if(!nvrtcGetPTX) {
227                 fprintf(stderr, "Error: nvrtcGetPTX not resolved\n");
228                 return false;
229         }
230
231         return true;
232 }
233
234 static bool parse_parameters(int argc, const char **argv, CompilationSettings &settings)
235 {
236         OIIO::ArgParse ap;
237         ap.options("Usage: cycles_cubin_cc [options]",
238                 "-target %d", &settings.target_arch, "target shader model",
239                 "-m %d", &settings.bits, "Cuda architecture bits",
240                 "-i %s", &settings.input_file, "Input source filename",
241                 "-o %s", &settings.output_file, "Output cubin filename",
242                 "-I %L", &settings.includes, "Add additional includepath",
243                 "-D %L", &settings.defines, "Add additional defines",
244                 "-v", &settings.verbose, "Use verbose logging",
245                 "--use_fast_math", &settings.fast_math, "Use fast math",
246                 "-cuda-toolkit-dir %s", &settings.cuda_toolkit_dir, "path to the cuda toolkit binary directory",
247                 NULL);
248
249         if(ap.parse(argc, argv) < 0) {
250                 fprintf(stderr, "%s\n", ap.geterror().c_str());
251                 ap.usage();
252                 return false;
253         }
254
255         if(!settings.output_file.size()) {
256                 fprintf(stderr, "Error: Output file not set(-o), required\n\n");
257                 return false;
258         }
259
260         if(!settings.input_file.size()) {
261                 fprintf(stderr, "Error: Input file not set(-i, required\n\n");
262                 return false;
263         }
264
265         if(!settings.target_arch) {
266                 fprintf(stderr, "Error: target shader model not set (-target), required\n\n");
267                 return false;
268         }
269
270         return true;
271 }
272
273 int main(int argc, const char **argv)
274 {
275         CompilationSettings settings;
276
277         if(!parse_parameters(argc, argv, settings)) {
278                 fprintf(stderr, "Error: invalid parameters, exiting\n");
279                 exit(EXIT_FAILURE);
280         }
281
282         if(!init(settings)) {
283                 fprintf(stderr, "Error: initialization error, exiting\n");
284                 exit(EXIT_FAILURE);
285         }
286
287         if(!compile_cuda(settings)) {
288                 fprintf(stderr, "Error: compilation error, exiting\n");
289                 exit(EXIT_FAILURE);
290         }
291
292         if(!link_ptxas(settings)) {
293                 exit(EXIT_FAILURE);
294         }
295
296         return 0;
297 }