/****************************************************************** Copyright (c) 2016 The Khronos Group Inc. All Rights Reserved. This code is protected by copyright laws and contains material proprietary to the Khronos Group, Inc. This is UNPUBLISHED PROPRIETARY SOURCE CODE that may not be disclosed in whole or in part to third parties, and may not be reproduced, republished, distributed, transmitted, displayed, broadcast or otherwise exploited in any manner without the express prior written permission of Khronos Group. The receipt or possession of this code does not convey any rights to reproduce, disclose, or distribute its contents, or to manufacture, use, or sell anything that it may describe, in whole or in part other than under the terms of the Khronos Adopters Agreement or Khronos Conformance Test Source License Agreement as executed between Khronos and the recipient. ******************************************************************/ #include #include #include "procs.h" #if !defined(_WIN32) #include #endif #include #include #include #include #if defined(_WIN32) const std::string slash = "\\"; #else const std::string slash = "/"; #endif const std::string spvExt = ".spv"; std::string gAddrWidth = ""; std::string spvBinariesPath = "spirv_bin"; std::string spvBinariesPathArg = "--spirv-binaries-path"; std::vector readBinary(const char *file_name) { using namespace std; ifstream file(file_name, ios::in | ios::binary | ios::ate); std::vector tmpBuffer(0); if (file.is_open()) { size_t size = file.tellg(); tmpBuffer.resize(size); file.seekg(0, ios::beg); file.read(&tmpBuffer[0], size); file.close(); } else { log_error("File %s not found\n", file_name); } std::vector result(tmpBuffer.begin(), tmpBuffer.end()); return result; } std::vector readSPIRV(const char *file_name) { std::string full_name_str = spvBinariesPath + slash + file_name + spvExt + gAddrWidth; return readBinary(full_name_str.c_str()); } test_definition *spirvTestsRegistry::getTestDefinitions() { return &testDefinitions[0]; } size_t spirvTestsRegistry::getNumTests() { return testDefinitions.size(); } void spirvTestsRegistry::addTestClass(baseTestClass *test, const char *testName, Version version) { testClasses.push_back(test); test_definition testDef; testDef.func = test->getFunction(); testDef.name = testName; testDef.min_version = version; testDefinitions.push_back(testDef); } spirvTestsRegistry& spirvTestsRegistry::getInstance() { static spirvTestsRegistry instance; return instance; } static int offline_get_program_with_il(clProgramWrapper &prog, const cl_device_id deviceID, const cl_context context, const char *prog_name) { cl_int err = 0; std::string outputTypeStr = "binary"; std::string defaultScript = std::string("..") + slash + std::string("spv_to_binary.py"); std::string outputFilename = spvBinariesPath + slash + std::string(prog_name); std::string sourceFilename = outputFilename + spvExt; std::string scriptArgs = sourceFilename + " " + outputFilename + " " + gAddrWidth + " " + outputTypeStr + " " + "-cl-std=CL2.0"; std::string scriptToRunString = defaultScript + scriptArgs; // execute script log_info("Executing command: %s\n", scriptToRunString.c_str()); fflush(stdout); int returnCode = system(scriptToRunString.c_str()); if (returnCode != 0) { log_error("Command finished with error: 0x%x\n", returnCode); return CL_COMPILE_PROGRAM_FAILURE; } // read output file std::vector buffer_vec = readBinary(outputFilename.c_str()); size_t file_bytes = buffer_vec.size(); if (file_bytes == 0) { log_error("OfflinerCompiler: Failed to open binary file: %s", outputFilename.c_str()); return -1; } const unsigned char *buffer = &buffer_vec[0]; cl_int status = 0; prog = clCreateProgramWithBinary(context, 1, &deviceID, &file_bytes, &buffer, &status, &err); SPIRV_CHECK_ERROR((err || status), "Failed to create program with clCreateProgramWithBinary"); return err; } int get_program_with_il(clProgramWrapper &prog, const cl_device_id deviceID, const cl_context context, const char *prog_name, spec_const spec_const_def) { cl_int err = 0; if (gCompilationMode == kBinary) { return offline_get_program_with_il(prog, deviceID, context, prog_name); } std::vector buffer_vec = readSPIRV(prog_name); int file_bytes = buffer_vec.size(); if (file_bytes == 0) { log_error("File %s not found\n", prog_name); return -1; } unsigned char *buffer = &buffer_vec[0]; if (gCoreILProgram) { prog = clCreateProgramWithIL(context, buffer, file_bytes, &err); SPIRV_CHECK_ERROR( err, "Failed to create program with clCreateProgramWithIL"); if (spec_const_def.spec_value != NULL) { err = clSetProgramSpecializationConstant( prog, spec_const_def.spec_id, spec_const_def.spec_size, spec_const_def.spec_value); SPIRV_CHECK_ERROR( err, "Failed to run clSetProgramSpecializationConstant"); } } else { cl_platform_id platform; err = clGetDeviceInfo(deviceID, CL_DEVICE_PLATFORM, sizeof(cl_platform_id), &platform, NULL); SPIRV_CHECK_ERROR(err, "Failed to get platform info with clGetDeviceInfo"); clCreateProgramWithILKHR_fn clCreateProgramWithILKHR = NULL; clCreateProgramWithILKHR = (clCreateProgramWithILKHR_fn) clGetExtensionFunctionAddressForPlatform( platform, "clCreateProgramWithILKHR"); if (clCreateProgramWithILKHR == NULL) { log_error( "ERROR: clGetExtensionFunctionAddressForPlatform failed\n"); return -1; } prog = clCreateProgramWithILKHR(context, buffer, file_bytes, &err); SPIRV_CHECK_ERROR( err, "Failed to create program with clCreateProgramWithILKHR"); } err = clBuildProgram(prog, 1, &deviceID, NULL, NULL, NULL); SPIRV_CHECK_ERROR(err, "Failed to build program"); return err; } test_status InitCL(cl_device_id id) { test_status spirv_status; bool force = true; spirv_status = check_spirv_compilation_readiness(id); if (spirv_status != TEST_PASS) { return spirv_status; } cl_uint address_bits; cl_uint err = clGetDeviceInfo(id, CL_DEVICE_ADDRESS_BITS, sizeof(cl_uint), &address_bits, NULL); if (err != CL_SUCCESS) { log_error("clGetDeviceInfo failed to get address bits!"); return TEST_FAIL; } gAddrWidth = address_bits == 32 ? "32" : "64"; return TEST_PASS; } void printUsage() { log_info("Reading SPIR-V files from default '%s' path.\n", spvBinariesPath.c_str()); log_info("In case you want to set other directory use '%s' argument.\n", spvBinariesPathArg.c_str()); } int main(int argc, const char *argv[]) { gReSeed = 1; bool modifiedSpvBinariesPath = false; for (int i = 0; i < argc; ++i) { int argsRemoveNum = 0; if (argv[i] == spvBinariesPathArg) { if (i + 1 == argc) { log_error("Missing value for '%s' argument.\n", spvBinariesPathArg.c_str()); return TEST_FAIL; } else { spvBinariesPath = std::string(argv[i + 1]); argsRemoveNum += 2; modifiedSpvBinariesPath = true; } } if (argsRemoveNum > 0) { for (int j = i; j < (argc - argsRemoveNum); ++j) argv[j] = argv[j + argsRemoveNum]; argc -= argsRemoveNum; --i; } } if (modifiedSpvBinariesPath == false) { printUsage(); } return runTestHarnessWithCheck( argc, argv, spirvTestsRegistry::getInstance().getNumTests(), spirvTestsRegistry::getInstance().getTestDefinitions(), false, 0, InitCL); }