diff --git a/.gitignore b/.gitignore index d93c20228e..66cbff97c0 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ build/ Test/localResults/ Test/multiThread.out Test/singleThread.out +External/googletest diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d723d87c2..ac756f556d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,7 @@ cmake_minimum_required(VERSION 2.8) +enable_testing() + set(CMAKE_INSTALL_PREFIX "install" CACHE STRING "prefix") project(glslang) @@ -20,7 +22,12 @@ elseif(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") add_definitions(-std=c++11) endif() +# We depend on these for later projects, so they should come first. +add_subdirectory(External) + add_subdirectory(glslang) add_subdirectory(OGLCompilersDLL) add_subdirectory(StandAlone) add_subdirectory(SPIRV) + +add_subdirectory(gtests) diff --git a/External/CMakeLists.txt b/External/CMakeLists.txt new file mode 100644 index 0000000000..d43cf9d0c5 --- /dev/null +++ b/External/CMakeLists.txt @@ -0,0 +1,16 @@ +# Suppress all warnings from external projects. +set_property(DIRECTORY APPEND PROPERTY COMPILE_OPTIONS -w) + +if (TARGET gmock) + message(STATUS "Google Mock already configured - use it") +elseif(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/googletest) + # We need to make sure Google Test does not mess up with the + # global CRT settings on Windows. + if(WIN32) + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + endif(WIN32) + add_subdirectory(googletest) +else() + message(STATUS + "Google Mock was not found - tests based on that will not build") +endif() diff --git a/README.md b/README.md index 7a60e280b1..7750877462 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,12 @@ bison --defines=MachineIndependent/glslang_tab.cpp.h -o MachineIndependent/glslang_tab.cpp ``` +Glslang is adding the ability to test with +[Google Test](https://github.com/google/googletest) framework. If you want to +build and run those tests, please make sure you have a copy of Google Tests +checked out in the `External/` directory: +`git clone https://github.com/google/googletest.git`. + Programmatic Interfaces ----------------------- @@ -118,7 +124,11 @@ Testing ------- Test results should always be included with a pull request that modifies -functionality. There is a simple process for doing this, described here: +functionality. And since glslang is adding the ability to test with +[Google Test](https://github.com/google/googletest) framework, +please write your new tests using Google Test. + +The old (deprecated) testing process is: `Test` is an active test directory that contains test input and a subdirectory `baseResults` that contains the expected results of the diff --git a/StandAlone/CMakeLists.txt b/StandAlone/CMakeLists.txt index 38cb2bdbba..51f332a63c 100644 --- a/StandAlone/CMakeLists.txt +++ b/StandAlone/CMakeLists.txt @@ -1,5 +1,13 @@ cmake_minimum_required(VERSION 2.8) +add_library(glslang-default-resource-limits + ${CMAKE_CURRENT_SOURCE_DIR}/DefaultResourceLimits.cpp +) +target_include_directories(glslang-default-resource-limits + PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} + PUBLIC ${PROJECT_SOURCE_DIR} +) + set(SOURCES StandAlone.cpp) set(REMAPPER_SOURCES spirv-remap.cpp) @@ -10,7 +18,8 @@ set(LIBRARIES glslang OGLCompiler OSDependent - SPIRV) + SPIRV + glslang-default-resource-limits) if(WIN32) set(LIBRARIES ${LIBRARIES} psapi) diff --git a/StandAlone/DefaultResourceLimits.cpp b/StandAlone/DefaultResourceLimits.cpp new file mode 100644 index 0000000000..66032de12e --- /dev/null +++ b/StandAlone/DefaultResourceLimits.cpp @@ -0,0 +1,239 @@ +// +// Copyright (C) 2016 Google, Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include + +#include "DefaultResourceLimits.h" + +namespace glslang { + +const TBuiltInResource DefaultTBuiltInResource = { + /* .MaxLights = */ 32, + /* .MaxClipPlanes = */ 6, + /* .MaxTextureUnits = */ 32, + /* .MaxTextureCoords = */ 32, + /* .MaxVertexAttribs = */ 64, + /* .MaxVertexUniformComponents = */ 4096, + /* .MaxVaryingFloats = */ 64, + /* .MaxVertexTextureImageUnits = */ 32, + /* .MaxCombinedTextureImageUnits = */ 80, + /* .MaxTextureImageUnits = */ 32, + /* .MaxFragmentUniformComponents = */ 4096, + /* .MaxDrawBuffers = */ 32, + /* .MaxVertexUniformVectors = */ 128, + /* .MaxVaryingVectors = */ 8, + /* .MaxFragmentUniformVectors = */ 16, + /* .MaxVertexOutputVectors = */ 16, + /* .MaxFragmentInputVectors = */ 15, + /* .MinProgramTexelOffset = */ -8, + /* .MaxProgramTexelOffset = */ 7, + /* .MaxClipDistances = */ 8, + /* .MaxComputeWorkGroupCountX = */ 65535, + /* .MaxComputeWorkGroupCountY = */ 65535, + /* .MaxComputeWorkGroupCountZ = */ 65535, + /* .MaxComputeWorkGroupSizeX = */ 1024, + /* .MaxComputeWorkGroupSizeY = */ 1024, + /* .MaxComputeWorkGroupSizeZ = */ 64, + /* .MaxComputeUniformComponents = */ 1024, + /* .MaxComputeTextureImageUnits = */ 16, + /* .MaxComputeImageUniforms = */ 8, + /* .MaxComputeAtomicCounters = */ 8, + /* .MaxComputeAtomicCounterBuffers = */ 1, + /* .MaxVaryingComponents = */ 60, + /* .MaxVertexOutputComponents = */ 64, + /* .MaxGeometryInputComponents = */ 64, + /* .MaxGeometryOutputComponents = */ 128, + /* .MaxFragmentInputComponents = */ 128, + /* .MaxImageUnits = */ 8, + /* .MaxCombinedImageUnitsAndFragmentOutputs = */ 8, + /* .MaxCombinedShaderOutputResources = */ 8, + /* .MaxImageSamples = */ 0, + /* .MaxVertexImageUniforms = */ 0, + /* .MaxTessControlImageUniforms = */ 0, + /* .MaxTessEvaluationImageUniforms = */ 0, + /* .MaxGeometryImageUniforms = */ 0, + /* .MaxFragmentImageUniforms = */ 8, + /* .MaxCombinedImageUniforms = */ 8, + /* .MaxGeometryTextureImageUnits = */ 16, + /* .MaxGeometryOutputVertices = */ 256, + /* .MaxGeometryTotalOutputComponents = */ 1024, + /* .MaxGeometryUniformComponents = */ 1024, + /* .MaxGeometryVaryingComponents = */ 64, + /* .MaxTessControlInputComponents = */ 128, + /* .MaxTessControlOutputComponents = */ 128, + /* .MaxTessControlTextureImageUnits = */ 16, + /* .MaxTessControlUniformComponents = */ 1024, + /* .MaxTessControlTotalOutputComponents = */ 4096, + /* .MaxTessEvaluationInputComponents = */ 128, + /* .MaxTessEvaluationOutputComponents = */ 128, + /* .MaxTessEvaluationTextureImageUnits = */ 16, + /* .MaxTessEvaluationUniformComponents = */ 1024, + /* .MaxTessPatchComponents = */ 120, + /* .MaxPatchVertices = */ 32, + /* .MaxTessGenLevel = */ 64, + /* .MaxViewports = */ 16, + /* .MaxVertexAtomicCounters = */ 0, + /* .MaxTessControlAtomicCounters = */ 0, + /* .MaxTessEvaluationAtomicCounters = */ 0, + /* .MaxGeometryAtomicCounters = */ 0, + /* .MaxFragmentAtomicCounters = */ 8, + /* .MaxCombinedAtomicCounters = */ 8, + /* .MaxAtomicCounterBindings = */ 1, + /* .MaxVertexAtomicCounterBuffers = */ 0, + /* .MaxTessControlAtomicCounterBuffers = */ 0, + /* .MaxTessEvaluationAtomicCounterBuffers = */ 0, + /* .MaxGeometryAtomicCounterBuffers = */ 0, + /* .MaxFragmentAtomicCounterBuffers = */ 1, + /* .MaxCombinedAtomicCounterBuffers = */ 1, + /* .MaxAtomicCounterBufferSize = */ 16384, + /* .MaxTransformFeedbackBuffers = */ 4, + /* .MaxTransformFeedbackInterleavedComponents = */ 64, + /* .MaxCullDistances = */ 8, + /* .MaxCombinedClipAndCullDistances = */ 8, + /* .MaxSamples = */ 4, + /* .limits = */ { + /* .nonInductiveForLoops = */ 1, + /* .whileLoops = */ 1, + /* .doWhileLoops = */ 1, + /* .generalUniformIndexing = */ 1, + /* .generalAttributeMatrixVectorIndexing = */ 1, + /* .generalVaryingIndexing = */ 1, + /* .generalSamplerIndexing = */ 1, + /* .generalVariableIndexing = */ 1, + /* .generalConstantMatrixVectorIndexing = */ 1, + }}; + +std::string GetDefaultTBuiltInResourceString() +{ + std::ostringstream ostream; + + ostream << "MaxLights " << DefaultTBuiltInResource.maxLights << "\n" + << "MaxClipPlanes " << DefaultTBuiltInResource.maxClipPlanes << "\n" + << "MaxTextureUnits " << DefaultTBuiltInResource.maxTextureUnits << "\n" + << "MaxTextureCoords " << DefaultTBuiltInResource.maxTextureCoords << "\n" + << "MaxVertexAttribs " << DefaultTBuiltInResource.maxVertexAttribs << "\n" + << "MaxVertexUniformComponents " << DefaultTBuiltInResource.maxVertexUniformComponents << "\n" + << "MaxVaryingFloats " << DefaultTBuiltInResource.maxVaryingFloats << "\n" + << "MaxVertexTextureImageUnits " << DefaultTBuiltInResource.maxVertexTextureImageUnits << "\n" + << "MaxCombinedTextureImageUnits " << DefaultTBuiltInResource.maxCombinedTextureImageUnits << "\n" + << "MaxTextureImageUnits " << DefaultTBuiltInResource.maxTextureImageUnits << "\n" + << "MaxFragmentUniformComponents " << DefaultTBuiltInResource.maxFragmentUniformComponents << "\n" + << "MaxDrawBuffers " << DefaultTBuiltInResource.maxDrawBuffers << "\n" + << "MaxVertexUniformVectors " << DefaultTBuiltInResource.maxVertexUniformVectors << "\n" + << "MaxVaryingVectors " << DefaultTBuiltInResource.maxVaryingVectors << "\n" + << "MaxFragmentUniformVectors " << DefaultTBuiltInResource.maxFragmentUniformVectors << "\n" + << "MaxVertexOutputVectors " << DefaultTBuiltInResource.maxVertexOutputVectors << "\n" + << "MaxFragmentInputVectors " << DefaultTBuiltInResource.maxFragmentInputVectors << "\n" + << "MinProgramTexelOffset " << DefaultTBuiltInResource.minProgramTexelOffset << "\n" + << "MaxProgramTexelOffset " << DefaultTBuiltInResource.maxProgramTexelOffset << "\n" + << "MaxClipDistances " << DefaultTBuiltInResource.maxClipDistances << "\n" + << "MaxComputeWorkGroupCountX " << DefaultTBuiltInResource.maxComputeWorkGroupCountX << "\n" + << "MaxComputeWorkGroupCountY " << DefaultTBuiltInResource.maxComputeWorkGroupCountY << "\n" + << "MaxComputeWorkGroupCountZ " << DefaultTBuiltInResource.maxComputeWorkGroupCountZ << "\n" + << "MaxComputeWorkGroupSizeX " << DefaultTBuiltInResource.maxComputeWorkGroupSizeX << "\n" + << "MaxComputeWorkGroupSizeY " << DefaultTBuiltInResource.maxComputeWorkGroupSizeY << "\n" + << "MaxComputeWorkGroupSizeZ " << DefaultTBuiltInResource.maxComputeWorkGroupSizeZ << "\n" + << "MaxComputeUniformComponents " << DefaultTBuiltInResource.maxComputeUniformComponents << "\n" + << "MaxComputeTextureImageUnits " << DefaultTBuiltInResource.maxComputeTextureImageUnits << "\n" + << "MaxComputeImageUniforms " << DefaultTBuiltInResource.maxComputeImageUniforms << "\n" + << "MaxComputeAtomicCounters " << DefaultTBuiltInResource.maxComputeAtomicCounters << "\n" + << "MaxComputeAtomicCounterBuffers " << DefaultTBuiltInResource.maxComputeAtomicCounterBuffers << "\n" + << "MaxVaryingComponents " << DefaultTBuiltInResource.maxVaryingComponents << "\n" + << "MaxVertexOutputComponents " << DefaultTBuiltInResource.maxVertexOutputComponents << "\n" + << "MaxGeometryInputComponents " << DefaultTBuiltInResource.maxGeometryInputComponents << "\n" + << "MaxGeometryOutputComponents " << DefaultTBuiltInResource.maxGeometryOutputComponents << "\n" + << "MaxFragmentInputComponents " << DefaultTBuiltInResource.maxFragmentInputComponents << "\n" + << "MaxImageUnits " << DefaultTBuiltInResource.maxImageUnits << "\n" + << "MaxCombinedImageUnitsAndFragmentOutputs " << DefaultTBuiltInResource.maxCombinedImageUnitsAndFragmentOutputs << "\n" + << "MaxCombinedShaderOutputResources " << DefaultTBuiltInResource.maxCombinedShaderOutputResources << "\n" + << "MaxImageSamples " << DefaultTBuiltInResource.maxImageSamples << "\n" + << "MaxVertexImageUniforms " << DefaultTBuiltInResource.maxVertexImageUniforms << "\n" + << "MaxTessControlImageUniforms " << DefaultTBuiltInResource.maxTessControlImageUniforms << "\n" + << "MaxTessEvaluationImageUniforms " << DefaultTBuiltInResource.maxTessEvaluationImageUniforms << "\n" + << "MaxGeometryImageUniforms " << DefaultTBuiltInResource.maxGeometryImageUniforms << "\n" + << "MaxFragmentImageUniforms " << DefaultTBuiltInResource.maxFragmentImageUniforms << "\n" + << "MaxCombinedImageUniforms " << DefaultTBuiltInResource.maxCombinedImageUniforms << "\n" + << "MaxGeometryTextureImageUnits " << DefaultTBuiltInResource.maxGeometryTextureImageUnits << "\n" + << "MaxGeometryOutputVertices " << DefaultTBuiltInResource.maxGeometryOutputVertices << "\n" + << "MaxGeometryTotalOutputComponents " << DefaultTBuiltInResource.maxGeometryTotalOutputComponents << "\n" + << "MaxGeometryUniformComponents " << DefaultTBuiltInResource.maxGeometryUniformComponents << "\n" + << "MaxGeometryVaryingComponents " << DefaultTBuiltInResource.maxGeometryVaryingComponents << "\n" + << "MaxTessControlInputComponents " << DefaultTBuiltInResource.maxTessControlInputComponents << "\n" + << "MaxTessControlOutputComponents " << DefaultTBuiltInResource.maxTessControlOutputComponents << "\n" + << "MaxTessControlTextureImageUnits " << DefaultTBuiltInResource.maxTessControlTextureImageUnits << "\n" + << "MaxTessControlUniformComponents " << DefaultTBuiltInResource.maxTessControlUniformComponents << "\n" + << "MaxTessControlTotalOutputComponents " << DefaultTBuiltInResource.maxTessControlTotalOutputComponents << "\n" + << "MaxTessEvaluationInputComponents " << DefaultTBuiltInResource.maxTessEvaluationInputComponents << "\n" + << "MaxTessEvaluationOutputComponents " << DefaultTBuiltInResource.maxTessEvaluationOutputComponents << "\n" + << "MaxTessEvaluationTextureImageUnits " << DefaultTBuiltInResource.maxTessEvaluationTextureImageUnits << "\n" + << "MaxTessEvaluationUniformComponents " << DefaultTBuiltInResource.maxTessEvaluationUniformComponents << "\n" + << "MaxTessPatchComponents " << DefaultTBuiltInResource.maxTessPatchComponents << "\n" + << "MaxPatchVertices " << DefaultTBuiltInResource.maxPatchVertices << "\n" + << "MaxTessGenLevel " << DefaultTBuiltInResource.maxTessGenLevel << "\n" + << "MaxViewports " << DefaultTBuiltInResource.maxViewports << "\n" + << "MaxVertexAtomicCounters " << DefaultTBuiltInResource.maxVertexAtomicCounters << "\n" + << "MaxTessControlAtomicCounters " << DefaultTBuiltInResource.maxTessControlAtomicCounters << "\n" + << "MaxTessEvaluationAtomicCounters " << DefaultTBuiltInResource.maxTessEvaluationAtomicCounters << "\n" + << "MaxGeometryAtomicCounters " << DefaultTBuiltInResource.maxGeometryAtomicCounters << "\n" + << "MaxFragmentAtomicCounters " << DefaultTBuiltInResource.maxFragmentAtomicCounters << "\n" + << "MaxCombinedAtomicCounters " << DefaultTBuiltInResource.maxCombinedAtomicCounters << "\n" + << "MaxAtomicCounterBindings " << DefaultTBuiltInResource.maxAtomicCounterBindings << "\n" + << "MaxVertexAtomicCounterBuffers " << DefaultTBuiltInResource.maxVertexAtomicCounterBuffers << "\n" + << "MaxTessControlAtomicCounterBuffers " << DefaultTBuiltInResource.maxTessControlAtomicCounterBuffers << "\n" + << "MaxTessEvaluationAtomicCounterBuffers " << DefaultTBuiltInResource.maxTessEvaluationAtomicCounterBuffers << "\n" + << "MaxGeometryAtomicCounterBuffers " << DefaultTBuiltInResource.maxGeometryAtomicCounterBuffers << "\n" + << "MaxFragmentAtomicCounterBuffers " << DefaultTBuiltInResource.maxFragmentAtomicCounterBuffers << "\n" + << "MaxCombinedAtomicCounterBuffers " << DefaultTBuiltInResource.maxCombinedAtomicCounterBuffers << "\n" + << "MaxAtomicCounterBufferSize " << DefaultTBuiltInResource.maxAtomicCounterBufferSize << "\n" + << "MaxTransformFeedbackBuffers " << DefaultTBuiltInResource.maxTransformFeedbackBuffers << "\n" + << "MaxTransformFeedbackInterleavedComponents " << DefaultTBuiltInResource.maxTransformFeedbackInterleavedComponents << "\n" + << "MaxCullDistances " << DefaultTBuiltInResource.maxCullDistances << "\n" + << "MaxCombinedClipAndCullDistances " << DefaultTBuiltInResource.maxCombinedClipAndCullDistances << "\n" + << "MaxSamples " << DefaultTBuiltInResource.maxSamples << "\n" + + << "nonInductiveForLoops " << DefaultTBuiltInResource.limits.nonInductiveForLoops << "\n" + << "whileLoops " << DefaultTBuiltInResource.limits.whileLoops << "\n" + << "doWhileLoops " << DefaultTBuiltInResource.limits.doWhileLoops << "\n" + << "generalUniformIndexing " << DefaultTBuiltInResource.limits.generalUniformIndexing << "\n" + << "generalAttributeMatrixVectorIndexing " << DefaultTBuiltInResource.limits.generalAttributeMatrixVectorIndexing << "\n" + << "generalVaryingIndexing " << DefaultTBuiltInResource.limits.generalVaryingIndexing << "\n" + << "generalSamplerIndexing " << DefaultTBuiltInResource.limits.generalSamplerIndexing << "\n" + << "generalVariableIndexing " << DefaultTBuiltInResource.limits.generalVariableIndexing << "\n" + << "generalConstantMatrixVectorIndexing " << DefaultTBuiltInResource.limits.generalConstantMatrixVectorIndexing << "\n" + ; + + return ostream.str(); +} + +} // end namespace glslang diff --git a/StandAlone/DefaultResourceLimits.h b/StandAlone/DefaultResourceLimits.h new file mode 100644 index 0000000000..fa52a2a7f4 --- /dev/null +++ b/StandAlone/DefaultResourceLimits.h @@ -0,0 +1,54 @@ +// +// Copyright (C) 2016 Google, Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#ifndef _DEFAULT_RESOURCE_LIMITS_INCLUDED_ +#define _DEFAULT_RESOURCE_LIMITS_INCLUDED_ + +#include + +#include "glslang/Include/ResourceLimits.h" + +namespace glslang { + +// These are the default resources for TBuiltInResources, used for both +// - parsing this string for the case where the user didn't supply one, +// - dumping out a template for user construction of a config file. +extern const TBuiltInResource DefaultTBuiltInResource; + +// Returns the DefaultTBuiltInResource as a human-readable string. +std::string GetDefaultTBuiltInResourceString(); + +} // end namespace glslang + +#endif // _DEFAULT_RESOURCE_LIMITS_INCLUDED_ diff --git a/StandAlone/StandAlone.cpp b/StandAlone/StandAlone.cpp index 6ebdb7f5cd..e8ab7b56de 100644 --- a/StandAlone/StandAlone.cpp +++ b/StandAlone/StandAlone.cpp @@ -37,6 +37,7 @@ // this only applies to the standalone wrapper, not the front end in general #define _CRT_SECURE_NO_WARNINGS +#include "DefaultResourceLimits.h" #include "Worklist.h" #include "./../glslang/Include/ShHandle.h" #include "./../glslang/Include/revision.h" @@ -110,107 +111,6 @@ int NumShaderStrings; TBuiltInResource Resources; std::string ConfigFile; -// -// These are the default resources for TBuiltInResources, used for both -// - parsing this string for the case where the user didn't supply one -// - dumping out a template for user construction of a config file -// -const char* DefaultConfig = - "MaxLights 32\n" - "MaxClipPlanes 6\n" - "MaxTextureUnits 32\n" - "MaxTextureCoords 32\n" - "MaxVertexAttribs 64\n" - "MaxVertexUniformComponents 4096\n" - "MaxVaryingFloats 64\n" - "MaxVertexTextureImageUnits 32\n" - "MaxCombinedTextureImageUnits 80\n" - "MaxTextureImageUnits 32\n" - "MaxFragmentUniformComponents 4096\n" - "MaxDrawBuffers 32\n" - "MaxVertexUniformVectors 128\n" - "MaxVaryingVectors 8\n" - "MaxFragmentUniformVectors 16\n" - "MaxVertexOutputVectors 16\n" - "MaxFragmentInputVectors 15\n" - "MinProgramTexelOffset -8\n" - "MaxProgramTexelOffset 7\n" - "MaxClipDistances 8\n" - "MaxComputeWorkGroupCountX 65535\n" - "MaxComputeWorkGroupCountY 65535\n" - "MaxComputeWorkGroupCountZ 65535\n" - "MaxComputeWorkGroupSizeX 1024\n" - "MaxComputeWorkGroupSizeY 1024\n" - "MaxComputeWorkGroupSizeZ 64\n" - "MaxComputeUniformComponents 1024\n" - "MaxComputeTextureImageUnits 16\n" - "MaxComputeImageUniforms 8\n" - "MaxComputeAtomicCounters 8\n" - "MaxComputeAtomicCounterBuffers 1\n" - "MaxVaryingComponents 60\n" - "MaxVertexOutputComponents 64\n" - "MaxGeometryInputComponents 64\n" - "MaxGeometryOutputComponents 128\n" - "MaxFragmentInputComponents 128\n" - "MaxImageUnits 8\n" - "MaxCombinedImageUnitsAndFragmentOutputs 8\n" - "MaxCombinedShaderOutputResources 8\n" - "MaxImageSamples 0\n" - "MaxVertexImageUniforms 0\n" - "MaxTessControlImageUniforms 0\n" - "MaxTessEvaluationImageUniforms 0\n" - "MaxGeometryImageUniforms 0\n" - "MaxFragmentImageUniforms 8\n" - "MaxCombinedImageUniforms 8\n" - "MaxGeometryTextureImageUnits 16\n" - "MaxGeometryOutputVertices 256\n" - "MaxGeometryTotalOutputComponents 1024\n" - "MaxGeometryUniformComponents 1024\n" - "MaxGeometryVaryingComponents 64\n" - "MaxTessControlInputComponents 128\n" - "MaxTessControlOutputComponents 128\n" - "MaxTessControlTextureImageUnits 16\n" - "MaxTessControlUniformComponents 1024\n" - "MaxTessControlTotalOutputComponents 4096\n" - "MaxTessEvaluationInputComponents 128\n" - "MaxTessEvaluationOutputComponents 128\n" - "MaxTessEvaluationTextureImageUnits 16\n" - "MaxTessEvaluationUniformComponents 1024\n" - "MaxTessPatchComponents 120\n" - "MaxPatchVertices 32\n" - "MaxTessGenLevel 64\n" - "MaxViewports 16\n" - "MaxVertexAtomicCounters 0\n" - "MaxTessControlAtomicCounters 0\n" - "MaxTessEvaluationAtomicCounters 0\n" - "MaxGeometryAtomicCounters 0\n" - "MaxFragmentAtomicCounters 8\n" - "MaxCombinedAtomicCounters 8\n" - "MaxAtomicCounterBindings 1\n" - "MaxVertexAtomicCounterBuffers 0\n" - "MaxTessControlAtomicCounterBuffers 0\n" - "MaxTessEvaluationAtomicCounterBuffers 0\n" - "MaxGeometryAtomicCounterBuffers 0\n" - "MaxFragmentAtomicCounterBuffers 1\n" - "MaxCombinedAtomicCounterBuffers 1\n" - "MaxAtomicCounterBufferSize 16384\n" - "MaxTransformFeedbackBuffers 4\n" - "MaxTransformFeedbackInterleavedComponents 64\n" - "MaxCullDistances 8\n" - "MaxCombinedClipAndCullDistances 8\n" - "MaxSamples 4\n" - - "nonInductiveForLoops 1\n" - "whileLoops 1\n" - "doWhileLoops 1\n" - "generalUniformIndexing 1\n" - "generalAttributeMatrixVectorIndexing 1\n" - "generalVaryingIndexing 1\n" - "generalSamplerIndexing 1\n" - "generalVariableIndexing 1\n" - "generalConstantMatrixVectorIndexing 1\n" - ; - // // Parse either a .conf file provided by the user or the default string above. // @@ -229,8 +129,8 @@ void ProcessConfigFile() } if (config == 0) { - config = new char[strlen(DefaultConfig) + 1]; - strcpy(config, DefaultConfig); + Resources = glslang::DefaultTBuiltInResource; + return; } const char* delims = " \t\n\r"; @@ -832,7 +732,7 @@ int C_DECL main(int argc, char* argv[]) ProcessArguments(argc, argv); if (Options & EOptionDumpConfig) { - printf("%s", DefaultConfig); + printf("%s", glslang::GetDefaultTBuiltInResourceString().c_str()); if (Worklist.empty()) return ESuccess; } diff --git a/Test/baseResults/spv.330.geom.out b/Test/baseResults/spv.330.geom.out old mode 100755 new mode 100644 diff --git a/Test/baseResults/spv.test.frag.out b/Test/baseResults/spv.test.frag.out old mode 100755 new mode 100644 diff --git a/Test/baseResults/spv.test.vert.out b/Test/baseResults/spv.test.vert.out old mode 100755 new mode 100644 diff --git a/gtests/AST.FromFile.cpp b/gtests/AST.FromFile.cpp new file mode 100644 index 0000000000..5e0b31e9d6 --- /dev/null +++ b/gtests/AST.FromFile.cpp @@ -0,0 +1,191 @@ +// +// Copyright (C) 2016 Google, Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include + +#include "TestFixture.h" + +namespace glslangtest { +namespace { + +using CompileToAstTest = GlslangTest<::testing::TestWithParam>; + +TEST_P(CompileToAstTest, FromFile) +{ + loadFileCompileAndCheck(GLSLANG_TEST_DIRECTORY, GetParam(), + Semantics::OpenGL, Target::AST); +} + +// clang-format off +INSTANTIATE_TEST_CASE_P( + Glsl, CompileToAstTest, + ::testing::ValuesIn(std::vector({ + "sample.frag", + "sample.vert", + "decls.frag", + "specExamples.frag", + "specExamples.vert", + "versionsClean.frag", + "versionsClean.vert", + "versionsErrors.frag", + "versionsErrors.vert", + "100.frag", + "120.vert", + "120.frag", + "130.vert", + "130.frag", + "140.vert", + "140.frag", + "150.vert", + "150.geom", + "150.frag", + "precision.frag", + "precision.vert", + "nonSquare.vert", + "matrixError.vert", + "cppSimple.vert", + "cppIndent.vert", + "cppNest.vert", + "cppComplexExpr.vert", + "badChars.frag", + "pointCoord.frag", + "array.frag", + "array100.frag", + "comment.frag", + "300.vert", + "300.frag", + "300BuiltIns.frag", + "300layout.vert", + "300layout.frag", + "300operations.frag", + "300block.frag", + "310.comp", + "310.vert", + "310.geom", + "310.frag", + "310.tesc", + "310.tese", + "310implicitSizeArrayError.vert", + "310AofA.vert", + "330.frag", + "330comp.frag", + "constErrors.frag", + "constFold.frag", + "errors.frag", + "forwardRef.frag", + "uint.frag", + "switch.frag", + "tokenLength.vert", + "100Limits.vert", + "100scope.vert", + "110scope.vert", + "300scope.vert", + "400.frag", + "420.frag", + "420.vert", + "420.geom", + "420_size_gl_in.geom", + "430scope.vert", + "lineContinuation100.vert", + "lineContinuation.vert", + "numeral.frag", + "400.geom", + "400.tesc", + "400.tese", + "410.tesc", + "420.tesc", + "420.tese", + "410.geom", + "430.vert", + "430.comp", + "430AofA.frag", + "440.vert", + "440.frag", + "450.vert", + "450.geom", + "450.tesc", + "450.tese", + "450.frag", + "450.comp", + "dce.frag", + "atomic_uint.frag", + "aggOps.frag", + "always-discard.frag", + "always-discard2.frag", + "conditionalDiscard.frag", + "conversion.frag", + "dataOut.frag", + "dataOutIndirect.frag", + "deepRvalue.frag", + "depthOut.frag", + "discard-dce.frag", + "doWhileLoop.frag", + "earlyReturnDiscard.frag", + "flowControl.frag", + "forLoop.frag", + "functionCall.frag", + "functionSemantics.frag", + "length.frag", + "localAggregates.frag", + "loops.frag", + "loopsArtificial.frag", + "matrix.frag", + "matrix2.frag", + "newTexture.frag", + "Operations.frag", + "prepost.frag", + "simpleFunctionCall.frag", + "structAssignment.frag", + "structDeref.frag", + "structure.frag", + "swizzle.frag", + "syntaxError.frag", + "test.frag", + "texture.frag", + "types.frag", + "uniformArray.frag", + "variableArrayIndex.frag", + "varyingArray.frag", + "varyingArrayIndirect.frag", + "voidFunction.frag", + "whileLoop.frag", + "nonVulkan.frag", + "spv.atomic.comp", + })), + FileNameAsCustomTestName +); +// clang-format on + +} // anonymous namespace +} // namespace glslangtest diff --git a/gtests/BuiltInResource.FromFile.cpp b/gtests/BuiltInResource.FromFile.cpp new file mode 100644 index 0000000000..c2d2b8b60b --- /dev/null +++ b/gtests/BuiltInResource.FromFile.cpp @@ -0,0 +1,57 @@ +// +// Copyright (C) 2016 Google, Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include + +#include + +#include "StandAlone/DefaultResourceLimits.h" +#include "TestFixture.h" + +namespace glslangtest { +namespace { + +using DefaultResourceTest = GlslangTest<::testing::Test>; + +TEST_F(DefaultResourceTest, FromFile) +{ + const std::string path = GLSLANG_TEST_DIRECTORY "/baseResults/test.conf"; + std::string expectedConfig; + tryLoadFile(path, "expected resource limit", &expectedConfig); + const std::string realConfig = glslang::GetDefaultTBuiltInResourceString(); + ASSERT_EQ(expectedConfig, realConfig); +} + +} // anonymous namespace +} // namespace glslangtest diff --git a/gtests/CMakeLists.txt b/gtests/CMakeLists.txt new file mode 100644 index 0000000000..57378cea8e --- /dev/null +++ b/gtests/CMakeLists.txt @@ -0,0 +1,32 @@ +if (TARGET gmock) + message(STATUS "Google Mock found - building tests") + + set(TEST_SOURCES + # Framework related source files + ${CMAKE_CURRENT_SOURCE_DIR}/Initializer.h + ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Settings.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Settings.h + ${CMAKE_CURRENT_SOURCE_DIR}/TestFixture.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/TestFixture.h + + # Test related source files + ${CMAKE_CURRENT_SOURCE_DIR}/AST.FromFile.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/BuiltInResource.FromFile.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Pp.FromFile.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Spv.FromFile.cpp + ) + + add_executable(glslangtests ${TEST_SOURCES}) + target_compile_definitions(glslangtests + PRIVATE GLSLANG_TEST_DIRECTORY="${CMAKE_CURRENT_SOURCE_DIR}/../Test") + target_include_directories(glslangtests PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${PROJECT_SOURCE_DIR} + ${gmock_SOURCE_DIR}/include + ${gtest_SOURCE_DIR}/include) + target_link_libraries(glslangtests PRIVATE + glslang OSDependent OGLCompiler glslang + SPIRV glslang-default-resource-limits gmock) + add_test(NAME glslang-gtests COMMAND glslangtests) +endif() diff --git a/gtests/Initializer.h b/gtests/Initializer.h new file mode 100644 index 0000000000..e8fa30d1a4 --- /dev/null +++ b/gtests/Initializer.h @@ -0,0 +1,119 @@ +// +// Copyright (C) 2016 Google, Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#ifndef GLSLANG_GTESTS_INITIALIZER_H +#define GLSLANG_GTESTS_INITIALIZER_H + +#include + +#include "glslang/Public/ShaderLang.h" + +namespace glslangtest { + +// Initializes glslang on creation, and destroys it on completion. +// And provides .Acquire() as a way to reinitialize glslang if semantics change. +// This object is expected to be a singleton, so that internal glslang state +// can be correctly handled. +// +// TODO(antiagainst): It's a known bug that some of the internal states need to +// be reset if semantics change: +// https://github.com/KhronosGroup/glslang/issues/166 +// Therefore, the following mechanism is needed. Remove this once the above bug +// gets fixed. +class GlslangInitializer { +public: + GlslangInitializer() : lastMessages(EShMsgDefault) + { + glslang::InitializeProcess(); + } + + ~GlslangInitializer() { glslang::FinalizeProcess(); } + + // A token indicates that the glslang is reinitialized (if necessary) to the + // required semantics. And that won't change until the token is destroyed. + class InitializationToken { + public: + InitializationToken() : initializer(nullptr) {} + ~InitializationToken() + { + if (initializer) { + initializer->release(); + } + } + + InitializationToken(InitializationToken&& other) + : initializer(other.initializer) + { + other.initializer = nullptr; + } + + InitializationToken(const InitializationToken&) = delete; + + private: + InitializationToken(GlslangInitializer* initializer) + : initializer(initializer) {} + + friend class GlslangInitializer; + GlslangInitializer* initializer; + }; + + // Obtains exclusive access to the glslang state. The state remains + // exclusive until the Initialization Token has been destroyed. + // Re-initializes glsl state iff the previous messages and the current + // messages are incompatible. + InitializationToken acquire(EShMessages new_messages) + { + stateLock.lock(); + + if ((lastMessages ^ new_messages) & + (EShMsgVulkanRules | EShMsgSpvRules)) { + glslang::FinalizeProcess(); + glslang::InitializeProcess(); + } + lastMessages = new_messages; + return InitializationToken(this); + } + +private: + void release() { stateLock.unlock(); } + + friend class InitializationToken; + + EShMessages lastMessages; + std::mutex stateLock; +}; + +} // namespace glslangtest + +#endif // GLSLANG_GTESTS_INITIALIZER_H diff --git a/gtests/Pp.FromFile.cpp b/gtests/Pp.FromFile.cpp new file mode 100644 index 0000000000..cfd987ba8e --- /dev/null +++ b/gtests/Pp.FromFile.cpp @@ -0,0 +1,74 @@ +// +// Copyright (C) 2016 Google, Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include + +#include "TestFixture.h" + +namespace glslangtest { +namespace { + +using PreprocessingTest = GlslangTest<::testing::TestWithParam>; + +TEST_P(PreprocessingTest, FromFile) +{ + loadFilePreprocessAndCheck(GLSLANG_TEST_DIRECTORY, GetParam()); +} + +// clang-format off +INSTANTIATE_TEST_CASE_P( + Glsl, PreprocessingTest, + ::testing::ValuesIn(std::vector({ + "preprocessor.cpp_style_line_directive.vert", + "preprocessor.cpp_style___FILE__.vert", + "preprocessor.edge_cases.vert", + "preprocessor.errors.vert", + "preprocessor.extensions.vert", + "preprocessor.function_macro.vert", + "preprocessor.include.enabled.vert", + "preprocessor.include.disabled.vert", + "preprocessor.line.vert", + "preprocessor.line.frag", + "preprocessor.pragma.vert", + "preprocessor.simple.vert", + "preprocessor.success_if_parse_would_fail.vert", + "preprocessor.defined.vert", + "preprocessor.many.endif.vert", + })), + FileNameAsCustomTestName +); +// clang-format on + +} // anonymous namespace +} // namespace glslangtest diff --git a/gtests/README.md b/gtests/README.md new file mode 100644 index 0000000000..c8261cc46a --- /dev/null +++ b/gtests/README.md @@ -0,0 +1,26 @@ +Glslang Tests based on the Google Test Framework +================================================ + +This directory contains [Google Test][gtest] based test fixture and test +cases for glslang. + +Apart from typical unit tests, necessary utility methods are added into +the [`GlslangTests`](TestFixture.h) fixture to provide the ability to do +file-based integration tests. Various `*.FromFile.cpp` files lists names +of files containing input shader code in the `Test/` directory. Utility +methods will load the input shader source, compile them, and compare with +the corresponding expected output in the `Test/baseResults/` directory. + +How to run the tests +-------------------- + +Please make sure you have a copy of [Google Test][gtest] checked out under +the `External` directory before building. After building, just run the +`ctest` command or the `gtests/glslangtests` binary in your build directory. + +The `gtests/glslangtests` binary also provides an `--update-mode` command +line option, which, if supplied, will overwrite the golden files under +the `Test/baseResults/` directory with real output from that invocation. +This serves as an easy way to update golden files. + +[gtest]: https://github.com/google/googletest diff --git a/gtests/Settings.cpp b/gtests/Settings.cpp new file mode 100644 index 0000000000..4ba7989b4a --- /dev/null +++ b/gtests/Settings.cpp @@ -0,0 +1,41 @@ +// +// Copyright (C) 2016 Google, Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include "Settings.h" + +namespace glslangtest { + +GTestSettings GlobalTestSettings = {nullptr, false}; + +} // namespace glslangtest diff --git a/gtests/Settings.h b/gtests/Settings.h new file mode 100644 index 0000000000..30056a7bac --- /dev/null +++ b/gtests/Settings.h @@ -0,0 +1,54 @@ +// +// Copyright (C) 2016 Google, Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#ifndef GLSLANG_GTESTS_SETTINGS_H +#define GLSLANG_GTESTS_SETTINGS_H + +namespace glslangtest { + +class GlslangInitializer; + +struct GTestSettings { + // A handle to GlslangInitializer instance. + GlslangInitializer* initializer; + // An indicator of whether GTest should write real output to the file for + // the expected output. + bool updateMode; +}; + +extern GTestSettings GlobalTestSettings; + +} // namespace glslangtest + +#endif // GLSLANG_GTESTS_SETTINGS_H diff --git a/gtests/Spv.FromFile.cpp b/gtests/Spv.FromFile.cpp new file mode 100644 index 0000000000..9cd0787a20 --- /dev/null +++ b/gtests/Spv.FromFile.cpp @@ -0,0 +1,188 @@ +// +// Copyright (C) 2016 Google, Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include + +#include + +#include "TestFixture.h" + +namespace glslangtest { +namespace { + +using CompileToSpirvTest = GlslangTest<::testing::TestWithParam>; +using VulkanSemantics = GlslangTest<::testing::TestWithParam>; + +// Compiling GLSL to SPIR-V under Vulkan semantics. Expected to successfully +// generate SPIR-V. +TEST_P(CompileToSpirvTest, FromFile) +{ + loadFileCompileAndCheck(GLSLANG_TEST_DIRECTORY, GetParam(), + Semantics::Vulkan, Target::Spirv); +} + +// GLSL-level Vulkan semantics test. Expected to error out before generating +// SPIR-V. +TEST_P(VulkanSemantics, FromFile) +{ + loadFileCompileAndCheck(GLSLANG_TEST_DIRECTORY, GetParam(), + Semantics::Vulkan, Target::Spirv); +} + +// clang-format off +INSTANTIATE_TEST_CASE_P( + Glsl, CompileToSpirvTest, + ::testing::ValuesIn(std::vector({ + // Test looping constructs. + // No tests yet for making sure break and continue from a nested loop + // goes to the innermost target. + "spv.do-simple.vert", + "spv.do-while-continue-break.vert", + "spv.for-complex-condition.vert", + "spv.for-continue-break.vert", + "spv.for-simple.vert", + "spv.for-notest.vert", + "spv.for-nobody.vert", + "spv.while-continue-break.vert", + "spv.while-simple.vert", + // vulkan-specific tests + "spv.set.vert", + "spv.double.comp", + "spv.100ops.frag", + "spv.130.frag", + "spv.140.frag", + "spv.150.geom", + "spv.150.vert", + "spv.300BuiltIns.vert", + "spv.300layout.frag", + "spv.300layout.vert", + "spv.300layoutp.vert", + "spv.310.comp", + "spv.330.geom", + "spv.400.frag", + "spv.400.tesc", + "spv.400.tese", + "spv.420.geom", + "spv.430.vert", + "spv.accessChain.frag", + "spv.aggOps.frag", + "spv.always-discard.frag", + "spv.always-discard2.frag", + "spv.bitCast.frag", + "spv.bool.vert", + "spv.boolInBlock.frag", + "spv.branch-return.vert", + "spv.conditionalDiscard.frag", + "spv.conversion.frag", + "spv.dataOut.frag", + "spv.dataOutIndirect.frag", + "spv.dataOutIndirect.vert", + "spv.deepRvalue.frag", + "spv.depthOut.frag", + "spv.discard-dce.frag", + "spv.doWhileLoop.frag", + "spv.earlyReturnDiscard.frag", + "spv.flowControl.frag", + "spv.forLoop.frag", + "spv.forwardFun.frag", + "spv.functionCall.frag", + "spv.functionSemantics.frag", + "spv.interpOps.frag", + "spv.layoutNested.vert", + "spv.length.frag", + "spv.localAggregates.frag", + "spv.loops.frag", + "spv.loopsArtificial.frag", + "spv.matFun.vert", + "spv.matrix.frag", + "spv.matrix2.frag", + "spv.memoryQualifier.frag", + "spv.merge-unreachable.frag", + "spv.newTexture.frag", + "spv.noDeadDecorations.vert", + "spv.nonSquare.vert", + "spv.Operations.frag", + "spv.intOps.vert", + "spv.precision.frag", + "spv.prepost.frag", + "spv.qualifiers.vert", + "spv.shiftOps.frag", + "spv.simpleFunctionCall.frag", + "spv.simpleMat.vert", + "spv.sparseTexture.frag", + "spv.sparseTextureClamp.frag", + "spv.structAssignment.frag", + "spv.structDeref.frag", + "spv.structure.frag", + "spv.switch.frag", + "spv.swizzle.frag", + "spv.test.frag", + "spv.test.vert", + "spv.texture.frag", + "spv.texture.vert", + "spv.image.frag", + "spv.types.frag", + "spv.uint.frag", + "spv.uniformArray.frag", + "spv.variableArrayIndex.frag", + "spv.varyingArray.frag", + "spv.varyingArrayIndirect.frag", + "spv.voidFunction.frag", + "spv.whileLoop.frag", + "spv.AofA.frag", + "spv.queryL.frag", + "spv.separate.frag", + "spv.shortCircuit.frag", + "spv.pushConstant.vert", + "spv.subpass.frag", + "spv.specConstant.vert", + "spv.specConstant.comp", + "spv.specConstantComposite.vert", + })), + FileNameAsCustomTestName +); + +INSTANTIATE_TEST_CASE_P( + Glsl, VulkanSemantics, + ::testing::ValuesIn(std::vector({ + "vulkan.frag", + "vulkan.vert", + "vulkan.comp", + })), + FileNameAsCustomTestName +); +// clang-format on + +} // anonymous namespace +} // namespace glslangtest diff --git a/gtests/TestFixture.cpp b/gtests/TestFixture.cpp new file mode 100644 index 0000000000..744fa558f3 --- /dev/null +++ b/gtests/TestFixture.cpp @@ -0,0 +1,124 @@ +// +// Copyright (C) 2016 Google, Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include "TestFixture.h" + +namespace glslangtest { + +std::string FileNameAsCustomTestName( + const ::testing::TestParamInfo& info) +{ + std::string name = info.param; + // A valid test case suffix cannot have '.' and '-' inside. + std::replace(name.begin(), name.end(), '.', '_'); + std::replace(name.begin(), name.end(), '-', '_'); + return name; +} + +EShLanguage GetGlslLanguageForStage(const std::string& stage) +{ + if (stage == "vert") { + return EShLangVertex; + } else if (stage == "tesc") { + return EShLangTessControl; + } else if (stage == "tese") { + return EShLangTessEvaluation; + } else if (stage == "geom") { + return EShLangGeometry; + } else if (stage == "frag") { + return EShLangFragment; + } else if (stage == "comp") { + return EShLangCompute; + } else { + assert(0 && "Unknown shader stage"); + return EShLangCount; + } +} + +EShMessages GetSpirvMessageOptionsForSemanticsAndTarget(Semantics semantics, + Target target) +{ + EShMessages result = EShMsgDefault; + + switch (target) { + case Target::AST: + result = EShMsgAST; + break; + case Target::Spirv: + result = EShMsgSpvRules; + break; + }; + + switch (semantics) { + case Semantics::OpenGL: + break; + case Semantics::Vulkan: + result = static_cast(result | EShMsgVulkanRules); + break; + } + + return result; +} + +std::pair ReadFile(const std::string& path) +{ + std::ifstream fstream(path, std::ios::in); + if (fstream) { + std::string contents; + fstream.seekg(0, std::ios::end); + contents.reserve(fstream.tellg()); + fstream.seekg(0, std::ios::beg); + contents.assign((std::istreambuf_iterator(fstream)), + std::istreambuf_iterator()); + return std::make_pair(true, contents); + } + return std::make_pair(false, ""); +} + +bool WriteFile(const std::string& path, const std::string& contents) +{ + std::ofstream fstream(path, std::ios::out); + if (!fstream) return false; + fstream << contents; + fstream.flush(); + return true; +} + +std::string GetSuffix(const std::string& name) +{ + const size_t pos = name.rfind('.'); + return (pos == std::string::npos) ? "" : name.substr(name.rfind('.') + 1); +} + +} // namespace glslangtest diff --git a/gtests/TestFixture.h b/gtests/TestFixture.h new file mode 100644 index 0000000000..87a365b5eb --- /dev/null +++ b/gtests/TestFixture.h @@ -0,0 +1,307 @@ +// +// Copyright (C) 2016 Google, Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#ifndef GLSLANG_GTESTS_TEST_FIXTURE_H +#define GLSLANG_GTESTS_TEST_FIXTURE_H + +#include +#include +#include +#include +#include + +#include + +#include "SPIRV/GlslangToSpv.h" +#include "SPIRV/disassemble.h" +#include "SPIRV/doc.h" +#include "StandAlone/DefaultResourceLimits.h" +#include "glslang/Public/ShaderLang.h" + +#include "Initializer.h" +#include "Settings.h" + +// We need CMake to provide us the absolute path to the directory containing +// test files, so we are certain to find those files no matter where the test +// harness binary is generated. This provides out-of-source build capability. +#ifndef GLSLANG_TEST_DIRECTORY +#error \ + "GLSLANG_TEST_DIRECTORY needs to be defined for gtest to locate test files." +#endif + +namespace glslangtest { + +// This function is used to provide custom test name suffixes based on the +// shader source file names. Otherwise, the test name suffixes will just be +// numbers, which are not quite obvious. +std::string FileNameAsCustomTestName( + const ::testing::TestParamInfo& info); + +// Enum for shader compilation semantics. +enum class Semantics { + OpenGL, + Vulkan, +}; + +// Enum for compilation target. +enum class Target { + AST, + Spirv, +}; + +EShLanguage GetGlslLanguageForStage(const std::string& stage); + +EShMessages GetSpirvMessageOptionsForSemanticsAndTarget(Semantics semantics, + Target target); + +// Reads the content of the file at the given |path|. On success, returns true +// and the contents; otherwise, returns false and an empty string. +std::pair ReadFile(const std::string& path); + +// Writes the given |contents| into the file at the given |path|. Returns true +// on successful output. +bool WriteFile(const std::string& path, const std::string& contents); + +// Returns the suffix of the given |name|. +std::string GetSuffix(const std::string& name); + +// Base class for glslang integration tests. It contains many handy utility-like +// methods such as reading shader source files, compiling into AST/SPIR-V, and +// comparing with expected outputs. +// +// To write value-Parameterized tests: +// using ValueParamTest = GlslangTest<::testing::TestWithParam>; +// To use as normal fixture: +// using FixtureTest = GlslangTest<::testing::Test>; +template +class GlslangTest : public GT { +public: + GlslangTest() + : defaultVersion(100), + defaultProfile(ENoProfile), + forceVersionProfile(false), + isForwardCompatible(false) {} + + // Tries to load the contents from the file at the given |path|. On success, + // writes the contents into |contents|. On failure, errors out. + void tryLoadFile(const std::string& path, const std::string& tag, + std::string* contents) + { + bool fileReadOk; + std::tie(fileReadOk, *contents) = ReadFile(path); + ASSERT_TRUE(fileReadOk) << "Cannot open " << tag << " file: " << path; + } + + // Checks the equality of |expected| and |real|. If they are not equal, + // write + // |real| to the given file named as |fname| if update mode is on. + void checkEqAndUpdateIfRequested(const std::string& expected, + const std::string& real, + const std::string& fname) + { + // In order to output the message we want under proper circumstances, we + // need the following operator<< stuff. + EXPECT_EQ(expected, real) + << (GlobalTestSettings.updateMode + ? ("Mismatch found and update mode turned on - " + "flushing expected result output.") + : ""); + + // Update the expected output file if requested. + // It looks weird to duplicate the comparison between expected_output + // and + // stream.str(). However, if creating a variable for the comparison + // result, + // we cannot have pretty print of the string diff in the above. + if (GlobalTestSettings.updateMode && expected != real) { + EXPECT_TRUE(WriteFile(fname, real)) << "Flushing failed"; + } + } + + // A struct for holding all the information returned by glslang compilation + // and linking. + struct GlslangResult { + const std::string compilationOutput; + const std::string compilationError; + const std::string linkingOutput; + const std::string linkingError; + const std::string spirv; // Optional SPIR-V disassembly text. + }; + + // Compiles and linkes the given GLSL |source| code of the given shader + // |stage| into the given |target| under the given |semantics|. Returns + // a GlslangResult instance containing all the information generated + // during the process. If |target| is Target::Spirv, also disassembles + // the result and returns disassembly text. + GlslangResult compileGlsl(const std::string& source, + const std::string& stage, Semantics semantics, + Target target) + { + const char* shaderStrings = source.data(); + const int shaderLengths = static_cast(source.size()); + const EShLanguage language = GetGlslLanguageForStage(stage); + + glslang::TShader shader(language); + shader.setStringsWithLengths(&shaderStrings, &shaderLengths, 1); + const EShMessages messages = + GetSpirvMessageOptionsForSemanticsAndTarget(semantics, target); + // Reinitialize glslang if the semantics change. + GlslangInitializer::InitializationToken token = + GlobalTestSettings.initializer->acquire(messages); + bool success = + shader.parse(&glslang::DefaultTBuiltInResource, defaultVersion, + isForwardCompatible, messages); + + glslang::TProgram program; + program.addShader(&shader); + success &= program.link(messages); + + if (success && target == Target::Spirv) { + std::vector spirv_binary; + glslang::GlslangToSpv(*program.getIntermediate(language), + spirv_binary); + + std::ostringstream disassembly_stream; + spv::Parameterize(); + spv::Disassemble(disassembly_stream, spirv_binary); + return {shader.getInfoLog(), shader.getInfoDebugLog(), + program.getInfoLog(), program.getInfoDebugLog(), + disassembly_stream.str()}; + } else { + return {shader.getInfoLog(), shader.getInfoDebugLog(), + program.getInfoLog(), program.getInfoDebugLog(), ""}; + } + } + + void loadFileCompileAndCheck(const std::string& testDir, + const std::string& testName, + Semantics semantics, Target target) + { + const std::string inputFname = testDir + "/" + testName; + const std::string expectedOutputFname = + testDir + "/baseResults/" + testName + ".out"; + std::string input, expectedOutput; + + tryLoadFile(inputFname, "input", &input); + tryLoadFile(expectedOutputFname, "expected output", &expectedOutput); + + GlslangResult result = + compileGlsl(input, GetSuffix(testName), semantics, target); + + // Generate the hybrid output in the way of glslangValidator. + std::ostringstream stream; + + const auto outputIfNotEmpty = [&stream](const std::string& str) { + if (!str.empty()) stream << str << "\n"; + }; + + stream << testName << "\n"; + outputIfNotEmpty(result.compilationOutput); + outputIfNotEmpty(result.compilationError); + outputIfNotEmpty(result.linkingOutput); + outputIfNotEmpty(result.linkingError); + if (target == Target::Spirv) { + stream + << (result.spirv.empty() + ? "SPIR-V is not generated for failed compile or link\n" + : result.spirv); + } + + checkEqAndUpdateIfRequested(expectedOutput, stream.str(), + expectedOutputFname); + } + + // Preprocesses the given GLSL |source| code. On success, returns true, the + // preprocessed shader, and warning messages. Otherwise, returns false, an + // empty string, and error messages. + std::tuple preprocessGlsl( + const std::string& source) + { + const char* shaderStrings = source.data(); + const int shaderLengths = static_cast(source.size()); + + glslang::TShader shader(EShLangVertex); + shader.setStringsWithLengths(&shaderStrings, &shaderLengths, 1); + std::string ppShader; + glslang::TShader::ForbidInclude includer; + const bool success = shader.preprocess( + &glslang::DefaultTBuiltInResource, defaultVersion, defaultProfile, + forceVersionProfile, isForwardCompatible, EShMsgOnlyPreprocessor, + &ppShader, includer); + + std::string log = shader.getInfoLog(); + log += shader.getInfoDebugLog(); + if (success) { + return std::make_tuple(true, ppShader, log); + } else { + return std::make_tuple(false, "", log); + } + } + + void loadFilePreprocessAndCheck(const std::string& testDir, + const std::string& testName) + { + const std::string inputFname = testDir + "/" + testName; + const std::string expectedOutputFname = + testDir + "/baseResults/" + testName + ".out"; + const std::string expectedErrorFname = + testDir + "/baseResults/" + testName + ".err"; + std::string input, expectedOutput, expectedError; + + tryLoadFile(inputFname, "input", &input); + tryLoadFile(expectedOutputFname, "expected output", &expectedOutput); + tryLoadFile(expectedErrorFname, "expected error", &expectedError); + + bool ppOk; + std::string output, error; + std::tie(ppOk, output, error) = preprocessGlsl(input); + if (!output.empty()) output += '\n'; + if (!error.empty()) error += '\n'; + + checkEqAndUpdateIfRequested(expectedOutput, output, + expectedOutputFname); + checkEqAndUpdateIfRequested(expectedError, error, + expectedErrorFname); + } + +private: + const int defaultVersion; + const EProfile defaultProfile; + const bool forceVersionProfile; + const bool isForwardCompatible; +}; + +} // namespace glslangtest + +#endif // GLSLANG_GTESTS_TEST_FIXTURE_H diff --git a/gtests/main.cpp b/gtests/main.cpp new file mode 100644 index 0000000000..b9806aa255 --- /dev/null +++ b/gtests/main.cpp @@ -0,0 +1,63 @@ +// +// Copyright (C) 2016 Google, Inc. +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include + +#include + +#include "Initializer.h" +#include "Settings.h" + +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + + std::unique_ptr initializer( + new glslangtest::GlslangInitializer); + + glslangtest::GlobalTestSettings.initializer = initializer.get(); + + for (int i = 1; i < argc; ++i) { + if (!strncmp("--update-mode", argv[i], 13)) { + glslangtest::GlobalTestSettings.updateMode = true; + break; + } + } + + const int result = RUN_ALL_TESTS(); + + glslangtest::GlobalTestSettings.initializer = nullptr; + + return result; +}