1 /******************************************************************
2 Copyright (c) 2016 The Khronos Group Inc. All Rights Reserved.
3
4 This code is protected by copyright laws and contains material proprietary to the Khronos Group, Inc.
5 This is UNPUBLISHED PROPRIETARY SOURCE CODE that may not be disclosed in whole or in part to
6 third parties, and may not be reproduced, republished, distributed, transmitted, displayed,
7 broadcast or otherwise exploited in any manner without the express prior written permission
8 of Khronos Group. The receipt or possession of this code does not convey any rights to reproduce,
9 disclose, or distribute its contents, or to manufacture, use, or sell anything that it may describe,
10 in whole or in part other than under the terms of the Khronos Adopters Agreement
11 or Khronos Conformance Test Source License Agreement as executed between Khronos and the recipient.
12 ******************************************************************/
13
14 #include <stdio.h>
15 #include <string.h>
16 #include "procs.h"
17 #if !defined(_WIN32)
18 #include <unistd.h>
19 #endif
20
21 #include <iostream>
22 #include <fstream>
23 #include <string>
24 #include <sstream>
25
26 #if defined(_WIN32)
27 const std::string slash = "\\";
28 #else
29 const std::string slash = "/";
30 #endif
31
32 const std::string spvExt = ".spv";
33 std::string gAddrWidth = "";
34 std::string spvBinariesPath = "spirv_bin";
35 std::string spvBinariesPathArg = "--spirv-binaries-path";
36
readBinary(const char * file_name)37 std::vector<unsigned char> readBinary(const char *file_name)
38 {
39 using namespace std;
40
41 ifstream file(file_name, ios::in | ios::binary | ios::ate);
42
43 std::vector<char> tmpBuffer(0);
44
45 if (file.is_open()) {
46 size_t size = file.tellg();
47 tmpBuffer.resize(size);
48 file.seekg(0, ios::beg);
49 file.read(&tmpBuffer[0], size);
50 file.close();
51 } else {
52 log_error("File %s not found\n", file_name);
53 }
54
55 std::vector<unsigned char> result(tmpBuffer.begin(), tmpBuffer.end());
56
57 return result;
58 }
59
60
readSPIRV(const char * file_name)61 std::vector<unsigned char> readSPIRV(const char *file_name)
62 {
63 std::string full_name_str = spvBinariesPath + slash + file_name + spvExt + gAddrWidth;
64 return readBinary(full_name_str.c_str());
65 }
66
getTestDefinitions()67 test_definition *spirvTestsRegistry::getTestDefinitions()
68 {
69 return &testDefinitions[0];
70 }
71
getNumTests()72 size_t spirvTestsRegistry::getNumTests()
73 {
74 return testDefinitions.size();
75 }
76
addTestClass(baseTestClass * test,const char * testName,Version version)77 void spirvTestsRegistry::addTestClass(baseTestClass *test, const char *testName,
78 Version version)
79 {
80
81 testClasses.push_back(test);
82 test_definition testDef;
83 testDef.func = test->getFunction();
84 testDef.name = testName;
85 testDef.min_version = version;
86 testDefinitions.push_back(testDef);
87 }
88
getInstance()89 spirvTestsRegistry& spirvTestsRegistry::getInstance()
90 {
91 static spirvTestsRegistry instance;
92 return instance;
93 }
94
offline_get_program_with_il(clProgramWrapper & prog,const cl_device_id deviceID,const cl_context context,const char * prog_name)95 static int offline_get_program_with_il(clProgramWrapper &prog,
96 const cl_device_id deviceID,
97 const cl_context context,
98 const char *prog_name)
99 {
100 cl_int err = 0;
101 std::string outputTypeStr = "binary";
102 std::string defaultScript = std::string("..") + slash + std::string("spv_to_binary.py");
103 std::string outputFilename = spvBinariesPath + slash + std::string(prog_name);
104 std::string sourceFilename = outputFilename + spvExt;
105
106 std::string scriptArgs =
107 sourceFilename + " " +
108 outputFilename + " " +
109 gAddrWidth + " " +
110 outputTypeStr + " " +
111 "-cl-std=CL2.0";
112
113 std::string scriptToRunString = defaultScript + scriptArgs;
114
115 // execute script
116 log_info("Executing command: %s\n", scriptToRunString.c_str());
117 fflush(stdout);
118 int returnCode = system(scriptToRunString.c_str());
119 if (returnCode != 0) {
120 log_error("Command finished with error: 0x%x\n", returnCode);
121 return CL_COMPILE_PROGRAM_FAILURE;
122 }
123
124 // read output file
125 std::vector<unsigned char> buffer_vec = readBinary(outputFilename.c_str());
126 size_t file_bytes = buffer_vec.size();
127 if (file_bytes == 0) {
128 log_error("OfflinerCompiler: Failed to open binary file: %s", outputFilename.c_str());
129 return -1;
130 }
131
132 const unsigned char *buffer = &buffer_vec[0];
133 cl_int status = 0;
134 prog = clCreateProgramWithBinary(context, 1, &deviceID, &file_bytes, &buffer, &status, &err);
135 SPIRV_CHECK_ERROR((err || status), "Failed to create program with clCreateProgramWithBinary");
136 return err;
137 }
138
get_program_with_il(clProgramWrapper & prog,const cl_device_id deviceID,const cl_context context,const char * prog_name,spec_const spec_const_def)139 int get_program_with_il(clProgramWrapper &prog, const cl_device_id deviceID,
140 const cl_context context, const char *prog_name,
141 spec_const spec_const_def)
142 {
143 cl_int err = 0;
144 if (gCompilationMode == kBinary)
145 {
146 return offline_get_program_with_il(prog, deviceID, context, prog_name);
147 }
148
149 std::vector<unsigned char> buffer_vec = readSPIRV(prog_name);
150
151 int file_bytes = buffer_vec.size();
152 if (file_bytes == 0)
153 {
154 log_error("File %s not found\n", prog_name);
155 return -1;
156 }
157
158 unsigned char *buffer = &buffer_vec[0];
159 if (gCoreILProgram)
160 {
161 prog = clCreateProgramWithIL(context, buffer, file_bytes, &err);
162 SPIRV_CHECK_ERROR(
163 err, "Failed to create program with clCreateProgramWithIL");
164
165 if (spec_const_def.spec_value != NULL)
166 {
167 err = clSetProgramSpecializationConstant(
168 prog, spec_const_def.spec_id, spec_const_def.spec_size,
169 spec_const_def.spec_value);
170 SPIRV_CHECK_ERROR(
171 err, "Failed to run clSetProgramSpecializationConstant");
172 }
173 }
174 else
175 {
176 cl_platform_id platform;
177 err = clGetDeviceInfo(deviceID, CL_DEVICE_PLATFORM,
178 sizeof(cl_platform_id), &platform, NULL);
179 SPIRV_CHECK_ERROR(err,
180 "Failed to get platform info with clGetDeviceInfo");
181 clCreateProgramWithILKHR_fn clCreateProgramWithILKHR = NULL;
182
183 clCreateProgramWithILKHR = (clCreateProgramWithILKHR_fn)
184 clGetExtensionFunctionAddressForPlatform(
185 platform, "clCreateProgramWithILKHR");
186 if (clCreateProgramWithILKHR == NULL)
187 {
188 log_error(
189 "ERROR: clGetExtensionFunctionAddressForPlatform failed\n");
190 return -1;
191 }
192 prog = clCreateProgramWithILKHR(context, buffer, file_bytes, &err);
193 SPIRV_CHECK_ERROR(
194 err, "Failed to create program with clCreateProgramWithILKHR");
195 }
196
197 err = clBuildProgram(prog, 1, &deviceID, NULL, NULL, NULL);
198 SPIRV_CHECK_ERROR(err, "Failed to build program");
199
200 return err;
201 }
202
InitCL(cl_device_id id)203 test_status InitCL(cl_device_id id)
204 {
205 test_status spirv_status;
206 bool force = true;
207 spirv_status = check_spirv_compilation_readiness(id);
208 if (spirv_status != TEST_PASS)
209 {
210 return spirv_status;
211 }
212
213 cl_uint address_bits;
214 cl_uint err = clGetDeviceInfo(id, CL_DEVICE_ADDRESS_BITS, sizeof(cl_uint),
215 &address_bits, NULL);
216 if (err != CL_SUCCESS)
217 {
218 log_error("clGetDeviceInfo failed to get address bits!");
219 return TEST_FAIL;
220 }
221
222 gAddrWidth = address_bits == 32 ? "32" : "64";
223 return TEST_PASS;
224 }
225
printUsage()226 void printUsage() {
227 log_info("Reading SPIR-V files from default '%s' path.\n", spvBinariesPath.c_str());
228 log_info("In case you want to set other directory use '%s' argument.\n", spvBinariesPathArg.c_str());
229 }
230
main(int argc,const char * argv[])231 int main(int argc, const char *argv[])
232 {
233 gReSeed = 1;
234 bool modifiedSpvBinariesPath = false;
235 for (int i = 0; i < argc; ++i) {
236 int argsRemoveNum = 0;
237 if (argv[i] == spvBinariesPathArg) {
238 if (i + 1 == argc) {
239 log_error("Missing value for '%s' argument.\n", spvBinariesPathArg.c_str());
240 return TEST_FAIL;
241 } else {
242 spvBinariesPath = std::string(argv[i + 1]);
243 argsRemoveNum += 2;
244 modifiedSpvBinariesPath = true;
245 }
246 }
247
248 if (argsRemoveNum > 0) {
249 for (int j = i; j < (argc - argsRemoveNum); ++j)
250 argv[j] = argv[j + argsRemoveNum];
251
252 argc -= argsRemoveNum;
253 --i;
254 }
255 }
256 if (modifiedSpvBinariesPath == false) {
257 printUsage();
258 }
259
260 return runTestHarnessWithCheck(
261 argc, argv, spirvTestsRegistry::getInstance().getNumTests(),
262 spirvTestsRegistry::getInstance().getTestDefinitions(), false, 0,
263 InitCL);
264 }
265