/****************************************************************************** * The MIT License (MIT) * * Copyright (c) 2016 Baldur Karlsson * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. ******************************************************************************/ #include "test_common.h" #include #include const DefaultA2V DefaultTri[3] = { {Vec3f(-0.5f, -0.5f, 0.0f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, {Vec3f(0.0f, 0.5f, 0.0f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)}, {Vec3f(0.5f, -0.5f, 0.0f), Vec4f(0.0f, 0.0f, 1.0f, 1.0f), Vec2f(1.0f, 0.0f)}, }; // since tolower is int -> int, this warns below. make a char -> char alternative char toclower(char c) { return (char)tolower(c); } char tocupper(char c) { return (char)toupper(c); } std::string strlower(const std::string &str) { std::string newstr(str); std::transform(newstr.begin(), newstr.end(), newstr.begin(), toclower); return newstr; } std::string strupper(const std::string &str) { std::string newstr(str); std::transform(newstr.begin(), newstr.end(), newstr.begin(), tocupper); return newstr; } std::string trim(const std::string &str) { const char *whitespace = "\t \n\r"; size_t start = str.find_first_not_of(whitespace); size_t end = str.find_last_not_of(whitespace); // no non-whitespace characters, return the empty string if(start == std::string::npos) return ""; // searching from the start found something, so searching from the end must have too. return str.substr(start, end - start + 1); } static char printBuf[4096] = {}; void DebugPrint(const char *fmt, ...) { va_list args; va_start(args, fmt); vsnprintf(printBuf, 4095, fmt, args); va_end(args); fputs(printBuf, stdout); fflush(stdout); #if defined(WIN32) OutputDebugStringA(printBuf); #endif } #include "3rdparty/shaderc/shaderc.h" #ifndef HAVE_SHADERC #define HAVE_SHADERC 0 #endif // this define toggles on/off using the linked shaderc. This can be useful if e.g. on windows the // shaderc in VULKAN_SDK is broken. #define USE_LINKED_SHADERC (1 && HAVE_SHADERC) static shaderc_compiler_t shaderc = NULL; bool SpvCompilationSupported() { if(shaderc) return true; #if USE_LINKED_SHADERC shaderc = shaderc_compiler_initialize(); #endif if(shaderc) return true; FILE *pipe = popen("glslc" EXECUTABLE_SUFFIX " --help", "r"); if(!pipe) return false; msleep(20); int code = pclose(pipe); return WEXITSTATUS(code) == 0; } std::vector CompileShaderToSpv(const std::string &source_text, ShaderLang lang, ShaderStage stage, const char *entry_point) { std::vector ret; if(shaderc) { #if USE_LINKED_SHADERC shaderc_compile_options_t opts = shaderc_compile_options_initialize(); if(lang == ShaderLang::glsl) shaderc_compile_options_set_source_language(opts, shaderc_source_language_glsl); else if(lang == ShaderLang::hlsl) shaderc_compile_options_set_source_language(opts, shaderc_source_language_hlsl); shaderc_compile_options_set_generate_debug_info(opts); shaderc_compile_options_set_optimization_level(opts, shaderc_optimization_level_zero); shaderc_shader_kind shader_kind = shaderc_glsl_vertex_shader; switch(stage) { case ShaderStage::vert: shader_kind = shaderc_vertex_shader; break; case ShaderStage::frag: shader_kind = shaderc_fragment_shader; break; case ShaderStage::tesscontrol: shader_kind = shaderc_tess_control_shader; break; case ShaderStage::tesseval: shader_kind = shaderc_tess_evaluation_shader; break; case ShaderStage::geom: shader_kind = shaderc_geometry_shader; break; case ShaderStage::comp: shader_kind = shaderc_compute_shader; break; } shaderc_compilation_result_t res = shaderc_compile_into_spv( shaderc, source_text.c_str(), source_text.size(), shader_kind, "inshader", entry_point, opts); shaderc_compilation_status status = shaderc_result_get_compilation_status(res); if(status != shaderc_compilation_status_success) { TEST_ERROR("Couldn't compile shader with built-in shaderc: %s", shaderc_result_get_error_message(res)); if(res) shaderc_result_release(res); return ret; } size_t sz = shaderc_result_get_length(res); TEST_ASSERT((sz % 4) == 0, "shaderc result isn't 4-byte aligned"); ret.resize(sz / 4); memcpy(&ret[0], shaderc_result_get_bytes(res), sz); shaderc_result_release(res); shaderc_compile_options_release(opts); return ret; #endif } std::string command_line = "glslc" EXECUTABLE_SUFFIX " -g -O0"; command_line += " -fentry-point="; command_line += entry_point; if(lang == ShaderLang::glsl) command_line += " -x glsl"; else if(lang == ShaderLang::hlsl) command_line += " -x hlsl"; switch(stage) { case ShaderStage::vert: command_line += " -fshader-stage=vert"; break; case ShaderStage::frag: command_line += " -fshader-stage=frag"; break; case ShaderStage::tesscontrol: command_line += " -fshader-stage=tesscontrol"; break; case ShaderStage::tesseval: command_line += " -fshader-stage=tesseval"; break; case ShaderStage::geom: command_line += " -fshader-stage=geom"; break; case ShaderStage::comp: command_line += " -fshader-stage=comp"; break; } char infile[MAX_PATH] = {}; char outfile[MAX_PATH] = {}; tmpnam(infile); tmpnam(outfile); command_line += " -o "; command_line += outfile; command_line += " "; command_line += infile; FILE *f = fopen(infile, "wb"); if(f) { fwrite(source_text.c_str(), 1, source_text.size(), f); fclose(f); } FILE *pipe = popen(command_line.c_str(), "r"); if(!pipe) { TEST_ERROR("Couldn't run shaderc to compile shaders."); return ret; } msleep(100); int code = pclose(pipe); if(code != 0) { TEST_ERROR("Invoking shaderc failed: %s.", command_line.c_str()); return ret; } f = fopen(outfile, "rb"); if(f) { fseek(f, 0, SEEK_END); ret.resize(ftell(f) / sizeof(uint32_t)); fseek(f, 0, SEEK_SET); fread(&ret[0], sizeof(uint32_t), ret.size(), f); fclose(f); } unlink(infile); unlink(outfile); return ret; } bool GraphicsTest::Init(int argc, char **argv) { srand(0U); // parse parameters for(int i = 0; i < argc; i++) { if(!strcmp(argv[i], "--debug") || !strcmp(argv[i], "-debug") || !strcmp(argv[i], "--validate") || !strcmp(argv[i], "-validate")) { debugDevice = true; } if(i + 1 < argc && (!strcmp(argv[i], "--frames") || !strcmp(argv[i], "--framecount") || !strcmp(argv[i], "--max-frames"))) { maxFrameCount = atoi(argv[i + 1]); } } #if defined(WIN32) HMODULE mod = GetModuleHandleA("renderdoc.dll"); if(mod) { pRENDERDOC_GetAPI RENDERDOC_GetAPI = (pRENDERDOC_GetAPI)GetProcAddress(mod, "RENDERDOC_GetAPI"); int ret = RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_0_0, (void **)&rdoc); if(ret != 1) rdoc = NULL; } #else #endif return true; } bool GraphicsTest::FrameLimit() { curFrame++; if(maxFrameCount > 0 && curFrame >= maxFrameCount) return false; return true; }