Path: blob/main/libshaderc_util/src/compiler_test.cc
1560 views
// Copyright 2015 The Shaderc Authors. All rights reserved.1//2// Licensed under the Apache License, Version 2.0 (the "License");3// you may not use this file except in compliance with the License.4// You may obtain a copy of the License at5//6// http://www.apache.org/licenses/LICENSE-2.07//8// Unless required by applicable law or agreed to in writing, software9// distributed under the License is distributed on an "AS IS" BASIS,10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.11// See the License for the specific language governing permissions and12// limitations under the License.1314#include "libshaderc_util/compiler.h"1516#include <sstream>1718#include <gmock/gmock.h>1920#include "death_test.h"21#include "libshaderc_util/counting_includer.h"22#include "libshaderc_util/spirv_tools_wrapper.h"2324namespace {2526using shaderc_util::Compiler;27using shaderc_util::GlslangClientInfo;28using ::testing::Eq;29using ::testing::HasSubstr;30using ::testing::Not;3132// A trivial vertex shader33const char kVertexShader[] =34"#version 140\n"35"void main() {}";3637// A shader that parses under OpenGL compatibility profile rules.38// It does not compile because Glslang does not support SPIR-V39// code generation for OpenGL compatibility profile.40const char kOpenGLCompatibilityFragShader[] =41R"(#version 14042uniform highp sampler2D tex;43void main() {44gl_FragColor = texture2D(tex, vec2(0.0,0.0));45})";4647// A shader that compiles under OpenGL core profile rules.48const char kOpenGLVertexShader[] =49R"(#version 33050void main() { int t = gl_VertexID; })";5152// A shader that compiles under OpenGL core profile rules, even when53// deducing the stage.54const char kOpenGLVertexShaderDeducibleStage[] =55R"(#version 33056#pragma shader_stage(vertex)57void main() { int t = gl_VertexID; })";5859// A shader that compiles under Vulkan rules.60// See the GL_KHR_vuklan_glsl extension to GLSL.61const char kVulkanVertexShader[] =62R"(#version 310 es63void main() { int t = gl_VertexIndex; })";6465// A shader that needs valueless macro predefinition E, to be compiled66// successfully.67const std::string kValuelessPredefinitionShader =68"#version 140\n"69"#ifdef E\n"70"void main(){}\n"71"#else\n"72"#error\n"73"#endif";7475// An HLSL vertex shader.76const char kHlslVertexShader[] =77R"(float4 EntryPoint(uint index : SV_VERTEXID) : SV_POSITION78{ return float4(1.0, 2.0, 3.0, 4.0); })";7980// A GLSL fragment shader without bindings for its uniforms.81// This also can be compiled as a vertex or compute shader.82const char kGlslFragShaderNoExplicitBinding[] =83R"(#version 45084#extension GL_ARB_sparse_texture2: enable85uniform texture2D my_tex;86uniform sampler my_sam;87layout(rgba32f) uniform image2D my_img;88layout(rgba32f) uniform imageBuffer my_imbuf;89uniform block { float x; float y; } my_ubo;90void main() {91texture(sampler2D(my_tex,my_sam),vec2(1.0));92vec4 t = vec4(1.0);93sparseImageLoadARB(my_img,ivec2(0),t);94imageLoad(my_imbuf,2);95float x = my_ubo.x;96})";9798// A GLSL vertex shader with the location defined for its non-opaque uniform99// variable.100const char kGlslVertShaderExplicitLocation[] =101R"(#version 450102layout(location = 10) uniform mat4 my_mat;103layout(location = 0) in vec4 my_vec;104void main(void) {105gl_Position = my_mat * my_vec;106})";107108// A GLSL fragment shader with the location defined for its non-opaque uniform109// variable.110const char kGlslFragShaderOpaqueUniforms[] =111R"(#version 320 es112precision lowp float;113114layout(location = 0) out vec4 oColor;115layout(location = 0) uniform float a;116void main(void) {117oColor = vec4(1.0, 0.0, 0.0, a);118})";119120// A GLSL vertex shader without the location defined for its non-opaque uniform121// variable.122const char kGlslVertShaderNoExplicitLocation[] =123R"(#version 450124uniform mat4 my_mat;125layout(location = 0) in vec4 my_vec;126void main(void) {127gl_Position = my_mat * my_vec;128})";129130// A GLSL vertex shader with a weirdly packed block.131const char kGlslShaderWeirdPacking[] =132R"(#version 450133layout(set = 0, binding = 0)134buffer B { float x; vec3 foo; } my_ssbo;135void main() { my_ssbo.x = 1.0; })";136137const char kHlslShaderForLegalizationTest[] = R"(138struct CombinedTextureSampler {139Texture2D tex;140SamplerState sampl;141};142143float4 sampleTexture(CombinedTextureSampler c, float2 loc) {144return c.tex.Sample(c.sampl, loc);145};146147[[vk::binding(0,0)]]148Texture2D gTex;149[[vk::binding(0,1)]]150SamplerState gSampler;151152float4 main(float2 loc: A) : SV_Target {153CombinedTextureSampler cts;154cts.tex = gTex;155cts.sampl = gSampler;156157return sampleTexture(cts, loc);158})";159160const char kHlslShaderWithCounterBuffer[] = R"(161[[vk::binding(0,0)]]162RWStructuredBuffer<float4> Ainc;163float4 main() : SV_Target0 {164return float4(Ainc.IncrementCounter(), 0, 0, 0);165}166)";167168const char kGlslShaderWithClamp[] = R"(#version 450169layout(location=0) in vec4 i;170layout(location=0) out vec4 o;171void main() { o = clamp(i, vec4(0.5), vec4(1.0)); }172)";173174// Returns the disassembly of the given SPIR-V binary, as a string.175// Assumes the disassembly will be successful when targeting Vulkan.176std::string Disassemble(const std::vector<uint32_t> binary) {177std::string result;178shaderc_util::SpirvToolsDisassemble(Compiler::TargetEnv::Vulkan,179Compiler::TargetEnvVersion::Vulkan_1_3,180binary, &result);181return result;182}183184// A CountingIncluder that never returns valid content for a requested185// file inclusion.186class DummyCountingIncluder : public shaderc_util::CountingIncluder {187private:188// Returns a pair of empty strings.189virtual glslang::TShader::Includer::IncludeResult* include_delegate(190const char*, const char*, IncludeType, size_t) override {191return nullptr;192}193virtual void release_delegate(194glslang::TShader::Includer::IncludeResult*) override {}195};196197// A test fixture for compiling GLSL shaders.198class CompilerTest : public testing::Test {199public:200// Returns true if the given compiler successfully compiles the given shader201// source for the given shader stage to the specified output type. No202// includes are permitted, and shader stage deduction falls back to an invalid203// shader stage.204bool SimpleCompilationSucceedsForOutputType(205std::string source, EShLanguage stage, Compiler::OutputType output_type) {206shaderc_util::GlslangInitializer initializer;207std::stringstream errors;208size_t total_warnings = 0;209size_t total_errors = 0;210bool result = false;211DummyCountingIncluder dummy_includer;212std::tie(result, std::ignore, std::ignore) = compiler_.Compile(213source, stage, "shader", "main", dummy_stage_callback_, dummy_includer,214Compiler::OutputType::SpirvBinary, &errors, &total_warnings,215&total_errors);216errors_ = errors.str();217return result;218}219220// Returns the result of SimpleCompilationSucceedsForOutputType, where221// the output type is a SPIR-V binary module.222bool SimpleCompilationSucceeds(std::string source, EShLanguage stage) {223return SimpleCompilationSucceedsForOutputType(224source, stage, Compiler::OutputType::SpirvBinary);225}226227// Returns the SPIR-V binary for a successful compilation of a shader.228std::vector<uint32_t> SimpleCompilationBinary(std::string source,229EShLanguage stage) {230shaderc_util::GlslangInitializer initializer;231std::stringstream errors;232size_t total_warnings = 0;233size_t total_errors = 0;234bool result = false;235DummyCountingIncluder dummy_includer;236std::vector<uint32_t> words;237std::tie(result, words, std::ignore) = compiler_.Compile(238source, stage, "shader", "main", dummy_stage_callback_, dummy_includer,239Compiler::OutputType::SpirvBinary, &errors, &total_warnings,240&total_errors);241errors_ = errors.str();242EXPECT_TRUE(result) << errors_;243return words;244}245246protected:247Compiler compiler_;248// The error string from the most recent compilation.249std::string errors_;250std::function<EShLanguage(std::ostream*, const shaderc_util::string_piece&)>251dummy_stage_callback_ =252[](std::ostream*, const shaderc_util::string_piece&) {253return EShLangCount;254};255};256257TEST_F(CompilerTest, SimpleVertexShaderCompilesSuccessfullyToBinary) {258EXPECT_TRUE(SimpleCompilationSucceeds(kVertexShader, EShLangVertex));259}260261TEST_F(CompilerTest, SimpleVertexShaderCompilesSuccessfullyToAssembly) {262EXPECT_TRUE(SimpleCompilationSucceedsForOutputType(263kVertexShader, EShLangVertex, Compiler::OutputType::SpirvAssemblyText));264}265266TEST_F(CompilerTest, SimpleVertexShaderPreprocessesSuccessfully) {267EXPECT_TRUE(SimpleCompilationSucceedsForOutputType(268kVertexShader, EShLangVertex, Compiler::OutputType::PreprocessedText));269}270271TEST_F(CompilerTest, BadVertexShaderFailsCompilation) {272EXPECT_FALSE(SimpleCompilationSucceeds(" bogus ", EShLangVertex));273}274275TEST_F(CompilerTest, SimpleVulkanShaderCompilesWithDefaultCompilerSettings) {276EXPECT_TRUE(SimpleCompilationSucceeds(kVulkanVertexShader, EShLangVertex));277}278279TEST_F(CompilerTest, OpenGLCompatibilityProfileNotSupported) {280const EShLanguage stage = EShLangVertex;281282compiler_.SetTargetEnv(Compiler::TargetEnv::OpenGLCompat);283EXPECT_FALSE(SimpleCompilationSucceeds(kOpenGLVertexShader, stage));284EXPECT_EQ(errors_, "error: OpenGL compatibility profile is not supported");285}286287TEST_F(CompilerTest, RespectTargetEnvOnOpenGLShaderForOpenGLShader) {288const EShLanguage stage = EShLangVertex;289290compiler_.SetTargetEnv(Compiler::TargetEnv::OpenGL);291EXPECT_TRUE(SimpleCompilationSucceeds(kOpenGLVertexShader, stage));292}293294TEST_F(CompilerTest, RespectTargetEnvOnOpenGLShaderWhenDeducingStage) {295const EShLanguage stage = EShLangVertex;296compiler_.SetTargetEnv(Compiler::TargetEnv::OpenGL);297EXPECT_TRUE(298SimpleCompilationSucceeds(kOpenGLVertexShaderDeducibleStage, stage));299}300301TEST_F(CompilerTest, RespectTargetEnvOnVulkanShader) {302compiler_.SetTargetEnv(Compiler::TargetEnv::Vulkan);303EXPECT_TRUE(SimpleCompilationSucceeds(kVulkanVertexShader, EShLangVertex));304}305306TEST_F(CompilerTest, VulkanSpecificShaderFailsUnderOpenGLCompatibilityRules) {307compiler_.SetTargetEnv(Compiler::TargetEnv::OpenGLCompat);308EXPECT_FALSE(SimpleCompilationSucceeds(kVulkanVertexShader, EShLangVertex));309}310311TEST_F(CompilerTest, VulkanSpecificShaderFailsUnderOpenGLRules) {312compiler_.SetTargetEnv(Compiler::TargetEnv::OpenGL);313EXPECT_FALSE(SimpleCompilationSucceeds(kVulkanVertexShader, EShLangVertex));314}315316TEST_F(CompilerTest, OpenGLSpecificShaderFailsUnderDefaultRules) {317EXPECT_FALSE(SimpleCompilationSucceeds(kOpenGLVertexShader, EShLangVertex));318}319320TEST_F(CompilerTest,321OpenGLCompatibilitySpecificShaderFailsUnderOpenGLCompatibilityRules) {322// OpenGLCompat mode now errors out. It's been deprecated for a long time.323compiler_.SetTargetEnv(Compiler::TargetEnv::OpenGLCompat);324EXPECT_FALSE(SimpleCompilationSucceeds(kOpenGLCompatibilityFragShader,325EShLangFragment));326}327328TEST_F(CompilerTest, OpenGLCompatibilitySpecificShaderFailsUnderOpenGLRules) {329compiler_.SetTargetEnv(Compiler::TargetEnv::OpenGL);330EXPECT_FALSE(SimpleCompilationSucceeds(kOpenGLCompatibilityFragShader,331EShLangFragment));332}333334TEST_F(CompilerTest, OpenGLCompatibilitySpecificShaderFailsUnderVulkanRules) {335compiler_.SetTargetEnv(Compiler::TargetEnv::Vulkan);336EXPECT_FALSE(SimpleCompilationSucceeds(kOpenGLCompatibilityFragShader,337EShLangFragment));338}339340TEST_F(CompilerTest, OpenGLSpecificShaderFailsUnderVulkanRules) {341compiler_.SetTargetEnv(Compiler::TargetEnv::Vulkan);342EXPECT_FALSE(SimpleCompilationSucceeds(kOpenGLVertexShader, EShLangVertex));343}344345TEST_F(CompilerTest, BadTargetEnvFails) {346compiler_.SetTargetEnv(static_cast<Compiler::TargetEnv>(32767));347EXPECT_FALSE(SimpleCompilationSucceeds(kVulkanVertexShader, EShLangVertex));348EXPECT_THAT(errors_, HasSubstr("Invalid target client environment 32767"));349}350351TEST_F(CompilerTest, BadTargetEnvVulkanVersionFails) {352compiler_.SetTargetEnv(Compiler::TargetEnv::Vulkan,353static_cast<Compiler::TargetEnvVersion>(123));354EXPECT_FALSE(SimpleCompilationSucceeds(kVulkanVertexShader, EShLangVertex));355EXPECT_THAT(errors_,356HasSubstr("Invalid target client version 123 for Vulkan environment 0"));357}358359TEST_F(CompilerTest, BadTargetEnvOpenGLVersionFails) {360compiler_.SetTargetEnv(Compiler::TargetEnv::OpenGL,361static_cast<Compiler::TargetEnvVersion>(123));362EXPECT_FALSE(SimpleCompilationSucceeds(kVulkanVertexShader, EShLangVertex));363EXPECT_THAT(errors_,364HasSubstr("Invalid target client version 123 for OpenGL environment 1"));365}366367TEST_F(CompilerTest, SpirvTargetVersion1_0Succeeds) {368compiler_.SetTargetSpirv(Compiler::SpirvVersion::v1_0);369EXPECT_TRUE(SimpleCompilationSucceeds(kVulkanVertexShader, EShLangVertex));370EXPECT_THAT(errors_, Eq(""));371}372373TEST_F(CompilerTest, SpirvTargetVersion1_1Succeeds) {374compiler_.SetTargetSpirv(Compiler::SpirvVersion::v1_1);375EXPECT_TRUE(SimpleCompilationSucceeds(kVulkanVertexShader, EShLangVertex));376EXPECT_THAT(errors_, Eq(""));377}378379TEST_F(CompilerTest, SpirvTargetVersion1_2Succeeds) {380compiler_.SetTargetSpirv(Compiler::SpirvVersion::v1_2);381EXPECT_TRUE(SimpleCompilationSucceeds(kVulkanVertexShader, EShLangVertex));382EXPECT_THAT(errors_, Eq(""));383}384385TEST_F(CompilerTest, SpirvTargetVersion1_3Succeeds) {386compiler_.SetTargetSpirv(Compiler::SpirvVersion::v1_3);387EXPECT_TRUE(SimpleCompilationSucceeds(kVulkanVertexShader, EShLangVertex));388EXPECT_THAT(errors_, Eq(""));389}390391TEST_F(CompilerTest, SpirvTargetVersion1_4Succeeds) {392compiler_.SetTargetSpirv(Compiler::SpirvVersion::v1_4);393EXPECT_TRUE(SimpleCompilationSucceeds(kVulkanVertexShader, EShLangVertex));394EXPECT_THAT(errors_, Eq(""));395}396397TEST_F(CompilerTest, SpirvTargetVersion1_5Succeeds) {398compiler_.SetTargetSpirv(Compiler::SpirvVersion::v1_5);399EXPECT_TRUE(SimpleCompilationSucceeds(kVulkanVertexShader, EShLangVertex));400EXPECT_THAT(errors_, Eq(""));401}402403TEST_F(CompilerTest, SpirvTargetVersion1_6Succeeds) {404compiler_.SetTargetSpirv(Compiler::SpirvVersion::v1_6);405EXPECT_TRUE(SimpleCompilationSucceeds(kVulkanVertexShader, EShLangVertex));406EXPECT_THAT(errors_, Eq(""));407}408409TEST_F(CompilerTest, SpirvTargetBadVersionFails) {410compiler_.SetTargetSpirv(static_cast<Compiler::SpirvVersion>(0x090900));411EXPECT_FALSE(SimpleCompilationSucceeds(kVulkanVertexShader, EShLangVertex));412EXPECT_THAT(errors_, HasSubstr(": Unknown SPIR-V version 90900"));413}414415TEST_F(CompilerTest, AddMacroDefinition) {416const std::string kMinimalExpandedShader = "#version 140\nvoid E(){}";417compiler_.AddMacroDefinition("E", 1u, "main", 4u);418EXPECT_TRUE(SimpleCompilationSucceeds(kMinimalExpandedShader, EShLangVertex));419}420421TEST_F(CompilerTest, AddValuelessMacroDefinitionNullPointer) {422compiler_.AddMacroDefinition("E", 1u, nullptr, 100u);423EXPECT_TRUE(424SimpleCompilationSucceeds(kValuelessPredefinitionShader, EShLangVertex));425}426427TEST_F(CompilerTest, AddValuelessMacroDefinitionZeroLength) {428compiler_.AddMacroDefinition("E", 1u, "something", 0u);429EXPECT_TRUE(430SimpleCompilationSucceeds(kValuelessPredefinitionShader, EShLangVertex));431}432433TEST_F(CompilerTest, AddMacroDefinitionNotNullTerminated) {434const std::string kMinimalExpandedShader = "#version 140\nvoid E(){}";435compiler_.AddMacroDefinition("EFGH", 1u, "mainnnnnn", 4u);436EXPECT_TRUE(SimpleCompilationSucceeds(kMinimalExpandedShader, EShLangVertex));437}438439// A convert-string-to-vector test case consists of 1) an input string; 2) an440// expected vector after the conversion.441struct ConvertStringToVectorTestCase {442std::string input_str;443std::vector<uint32_t> expected_output_vec;444};445446// Test the shaderc_util::ConvertStringToVector() function. The content of the447// input string, including the null terminator, should be packed into uint32_t448// cells and stored in the returned vector of uint32_t. In case extra bytes are449// required to complete the ending uint32_t element, bytes with value 0x00450// should be used to fill the space.451using ConvertStringToVectorTestFixture =452testing::TestWithParam<ConvertStringToVectorTestCase>;453454TEST_P(ConvertStringToVectorTestFixture, VariousStringSize) {455const ConvertStringToVectorTestCase& test_case = GetParam();456EXPECT_EQ(test_case.expected_output_vec,457shaderc_util::ConvertStringToVector(test_case.input_str))458<< "test_case.input_str: " << test_case.input_str << std::endl;459}460461INSTANTIATE_TEST_SUITE_P(462ConvertStringToVectorTest, ConvertStringToVectorTestFixture,463testing::ValuesIn(std::vector<ConvertStringToVectorTestCase>{464{"", {0x00000000}},465{"1", {0x00000031}},466{"12", {0x00003231}},467{"123", {0x00333231}},468{"1234", {0x34333231, 0x00000000}},469{"12345", {0x34333231, 0x00000035}},470{"123456", {0x34333231, 0x00003635}},471{"1234567", {0x34333231, 0x00373635}},472{"12345678", {0x34333231, 0x38373635, 0x00000000}},473{"123456789", {0x34333231, 0x38373635, 0x00000039}},474}));475476TEST_F(CompilerTest, SetSourceLanguageToGLSLSucceeds) {477compiler_.SetSourceLanguage(Compiler::SourceLanguage::GLSL);478EXPECT_TRUE(SimpleCompilationSucceeds(kVulkanVertexShader, EShLangVertex));479}480481TEST_F(CompilerTest, SetSourceLanguageToGLSLFailsOnHLSL) {482compiler_.SetSourceLanguage(Compiler::SourceLanguage::GLSL);483EXPECT_FALSE(SimpleCompilationSucceeds(kHlslVertexShader, EShLangVertex));484}485486TEST_F(CompilerTest, SetSourceLanguageToHLSLSucceeds) {487compiler_.SetSourceLanguage(Compiler::SourceLanguage::HLSL);488EXPECT_TRUE(SimpleCompilationSucceeds(kHlslVertexShader, EShLangVertex))489<< errors_;490}491492TEST_F(CompilerTest, SetSourceLanguageToHLSLFailsOnGLSL) {493compiler_.SetSourceLanguage(Compiler::SourceLanguage::HLSL);494EXPECT_FALSE(SimpleCompilationSucceeds(kVulkanVertexShader, EShLangVertex));495}496497TEST_F(CompilerTest, EntryPointParameterTakesEffectForHLSL) {498compiler_.SetSourceLanguage(Compiler::SourceLanguage::HLSL);499std::stringstream errors;500size_t total_warnings = 0;501size_t total_errors = 0;502shaderc_util::GlslangInitializer initializer;503bool result = false;504DummyCountingIncluder dummy_includer;505std::vector<uint32_t> words;506std::tie(result, words, std::ignore) =507compiler_.Compile(kHlslVertexShader, EShLangVertex, "shader",508"EntryPoint", dummy_stage_callback_, dummy_includer,509Compiler::OutputType::SpirvAssemblyText, &errors,510&total_warnings, &total_errors);511EXPECT_TRUE(result);512std::string assembly(reinterpret_cast<char*>(words.data()));513EXPECT_THAT(assembly,514HasSubstr("OpEntryPoint Vertex %EntryPoint \"EntryPoint\""))515<< assembly;516}517518// A test case for setting resource limits.519struct SetLimitCase {520Compiler::Limit limit;521int default_value;522int value;523};524525using LimitTest = testing::TestWithParam<SetLimitCase>;526527TEST_P(LimitTest, Sample) {528Compiler compiler;529EXPECT_THAT(compiler.GetLimit(GetParam().limit),530Eq(GetParam().default_value));531compiler.SetLimit(GetParam().limit, GetParam().value);532EXPECT_THAT(compiler.GetLimit(GetParam().limit), Eq(GetParam().value));533}534535#define CASE(LIMIT, DEFAULT, NEW) \536{ Compiler::Limit::LIMIT, DEFAULT, NEW }537INSTANTIATE_TEST_SUITE_P(538CompilerTest, LimitTest,539// See resources.cc for the defaults.540testing::ValuesIn(std::vector<SetLimitCase>{541// clang-format off542// This is just a sampling of the possible values.543CASE(MaxLights, 8, 99),544CASE(MaxClipPlanes, 6, 10929),545CASE(MaxTessControlAtomicCounters, 0, 72),546CASE(MaxSamples, 4, 8),547// clang-format on548}));549#undef CASE550551// Returns a fragment shader accessing a texture with the given552// offset.553std::string ShaderWithTexOffset(int offset) {554std::ostringstream oss;555oss << "#version 450\n"556"layout (binding=0) uniform sampler1D tex;\n"557"void main() { vec4 x = textureOffset(tex, 1.0, "558<< offset << "); }\n";559return oss.str();560}561562// Ensure compilation is sensitive to limit setting. Sample just563// two particular limits. The default minimum texel offset is -8,564// and the default maximum texel offset is 7.565TEST_F(CompilerTest, TexelOffsetDefaults) {566const EShLanguage stage = EShLangFragment;567EXPECT_FALSE(SimpleCompilationSucceeds(ShaderWithTexOffset(-9), stage));568EXPECT_TRUE(SimpleCompilationSucceeds(ShaderWithTexOffset(-8), stage));569EXPECT_TRUE(SimpleCompilationSucceeds(ShaderWithTexOffset(7), stage));570EXPECT_FALSE(SimpleCompilationSucceeds(ShaderWithTexOffset(8), stage));571}572573TEST_F(CompilerTest, TexelOffsetLowerTheMinimum) {574const EShLanguage stage = EShLangFragment;575compiler_.SetLimit(Compiler::Limit::MinProgramTexelOffset, -99);576EXPECT_FALSE(SimpleCompilationSucceeds(ShaderWithTexOffset(-100), stage));577EXPECT_TRUE(SimpleCompilationSucceeds(ShaderWithTexOffset(-99), stage));578}579580TEST_F(CompilerTest, TexelOffsetRaiseTheMaximum) {581const EShLanguage stage = EShLangFragment;582compiler_.SetLimit(Compiler::Limit::MaxProgramTexelOffset, 100);583EXPECT_TRUE(SimpleCompilationSucceeds(ShaderWithTexOffset(100), stage));584EXPECT_FALSE(SimpleCompilationSucceeds(ShaderWithTexOffset(101), stage));585}586587TEST_F(CompilerTest, GeneratorWordIsShadercOverGlslang) {588const auto words = SimpleCompilationBinary(kVertexShader, EShLangVertex);589const uint32_t shaderc_over_glslang = 13; // From SPIR-V XML Registry590const uint32_t generator_word_index = 2; // From SPIR-V binary layout591EXPECT_EQ(shaderc_over_glslang, words[generator_word_index] >> 16u);592}593594TEST_F(CompilerTest, NoBindingsAndNoAutoMapBindingsFailsCompile) {595compiler_.SetAutoBindUniforms(false);596EXPECT_FALSE(SimpleCompilationSucceeds(kGlslFragShaderNoExplicitBinding,597EShLangFragment));598EXPECT_THAT(errors_,599HasSubstr("sampler/texture/image requires layout(binding=X)"));600}601602TEST_F(CompilerTest, AutoMapBindingsSetsBindings) {603compiler_.SetAutoBindUniforms(true);604const auto words = SimpleCompilationBinary(kGlslFragShaderNoExplicitBinding,605EShLangFragment);606const auto disassembly = Disassemble(words);607EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_tex Binding 0"))608<< disassembly;609EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_sam Binding 1"));610EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_img Binding 2"));611EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_imbuf Binding 3"));612EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_ubo Binding 4"));613}614615TEST_F(CompilerTest, SetBindingBaseForTextureAdjustsTextureBindingsOnly) {616compiler_.SetAutoBindUniforms(true);617compiler_.SetAutoBindingBase(Compiler::UniformKind::Texture, 42);618const auto words = SimpleCompilationBinary(kGlslFragShaderNoExplicitBinding,619EShLangFragment);620const auto disassembly = Disassemble(words);621EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_tex Binding 42"))622<< disassembly;623EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_sam Binding 0"));624EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_img Binding 1"));625EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_imbuf Binding 2"));626EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_ubo Binding 3"));627}628629TEST_F(CompilerTest, SetBindingBaseForSamplersAdjustsSamplerBindingsOnly) {630compiler_.SetAutoBindUniforms(true);631compiler_.SetAutoBindingBase(Compiler::UniformKind::Sampler, 42);632const auto words = SimpleCompilationBinary(kGlslFragShaderNoExplicitBinding,633EShLangFragment);634const auto disassembly = Disassemble(words);635EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_tex Binding 0"))636<< disassembly;637EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_sam Binding 42"));638EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_img Binding 1"));639EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_imbuf Binding 2"));640EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_ubo Binding 3"));641}642643TEST_F(CompilerTest, SetBindingBaseForImagesAdjustsImageBindingsOnly) {644compiler_.SetAutoBindUniforms(true);645compiler_.SetAutoBindingBase(Compiler::UniformKind::Image, 42);646const auto words = SimpleCompilationBinary(kGlslFragShaderNoExplicitBinding,647EShLangFragment);648const auto disassembly = Disassemble(words);649EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_tex Binding 0"))650<< disassembly;651EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_sam Binding 1"));652EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_img Binding 42"));653EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_imbuf Binding 43"));654EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_ubo Binding 2"));655}656657TEST_F(CompilerTest, SetBindingBaseForBufferAdjustsBufferBindingsOnly) {658compiler_.SetAutoBindUniforms(true);659compiler_.SetAutoBindingBase(Compiler::UniformKind::Buffer, 42);660const auto words = SimpleCompilationBinary(kGlslFragShaderNoExplicitBinding,661EShLangFragment);662const auto disassembly = Disassemble(words);663EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_tex Binding 0"))664<< disassembly;665EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_sam Binding 1"));666EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_img Binding 2"));667EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_imbuf Binding 3"));668EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_ubo Binding 42"));669}670671TEST_F(CompilerTest,672AutoMapBindingsSetsBindingsSetFragTextureBindingBaseCompiledAsFrag) {673compiler_.SetAutoBindUniforms(true);674compiler_.SetAutoBindingBaseForStage(Compiler::Stage::Fragment,675Compiler::UniformKind::Texture, 100);676const auto words = SimpleCompilationBinary(kGlslFragShaderNoExplicitBinding,677EShLangFragment);678const auto disassembly = Disassemble(words);679EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_tex Binding 100"))680<< disassembly;681EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_sam Binding 0"));682EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_img Binding 1"));683EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_imbuf Binding 2"));684EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_ubo Binding 3"));685}686687TEST_F(CompilerTest,688AutoMapBindingsSetsBindingsSetFragImageBindingBaseCompiledAsVert) {689compiler_.SetAutoBindUniforms(true);690// This is ignored because we're compiling the shader as a vertex shader, not691// as a fragment shader.692compiler_.SetAutoBindingBaseForStage(Compiler::Stage::Fragment,693Compiler::UniformKind::Image, 100);694const auto words =695SimpleCompilationBinary(kGlslFragShaderNoExplicitBinding, EShLangVertex);696const auto disassembly = Disassemble(words);697EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_tex Binding 0"))698<< disassembly;699EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_sam Binding 1"));700EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_img Binding 2"));701EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_imbuf Binding 3"));702EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_ubo Binding 4"));703}704705TEST_F(CompilerTest, NoAutoMapLocationsFailsCompilationOnOpenGLShader) {706compiler_.SetTargetEnv(Compiler::TargetEnv::OpenGL);707compiler_.SetAutoMapLocations(false);708709const auto words =710SimpleCompilationBinary(kGlslVertShaderExplicitLocation, EShLangVertex);711const auto disassembly = Disassemble(words);712EXPECT_THAT(disassembly, HasSubstr("OpDecorate %my_mat Location 10"))713<< disassembly;714715EXPECT_FALSE(SimpleCompilationSucceeds(kGlslVertShaderNoExplicitLocation,716EShLangVertex));717}718719TEST_F(CompilerTest, AutoMapLocationsSetsLocationsOnOpenGLShader) {720compiler_.SetTargetEnv(Compiler::TargetEnv::OpenGL);721compiler_.SetAutoMapLocations(true);722723const auto words_no_auto =724SimpleCompilationBinary(kGlslVertShaderExplicitLocation, EShLangVertex);725const auto disassembly_no_auto = Disassemble(words_no_auto);726EXPECT_THAT(disassembly_no_auto, HasSubstr("OpDecorate %my_mat Location 10"))727<< disassembly_no_auto;728729const auto words_auto =730SimpleCompilationBinary(kGlslVertShaderNoExplicitLocation, EShLangVertex);731const auto disassembly_auto = Disassemble(words_auto);732EXPECT_THAT(disassembly_auto, HasSubstr("OpDecorate %my_mat Location 0"))733<< disassembly_auto;734}735736TEST_F(CompilerTest, EmitMessageTextOnlyOnce) {737// Emit a warning by compiling a shader without a default entry point name.738// The warning should only be emitted once even though we do parsing, linking,739// and IO mapping.740Compiler c;741std::stringstream errors;742size_t total_warnings = 0;743size_t total_errors = 0;744shaderc_util::GlslangInitializer initializer;745bool result = false;746DummyCountingIncluder dummy_includer;747std::tie(result, std::ignore, std::ignore) = c.Compile(748"#version 150\nvoid MyEntryPoint(){}", EShLangVertex, "shader", "",749dummy_stage_callback_, dummy_includer, Compiler::OutputType::SpirvBinary,750&errors, &total_warnings, &total_errors);751const std::string errs = errors.str();752EXPECT_THAT(errs, Eq("shader: error: Linking vertex stage: Missing entry "753"point: Each stage requires one entry point\n"))754<< errs;755}756757TEST_F(CompilerTest, GlslDefaultPackingUsed) {758const auto words =759SimpleCompilationBinary(kGlslShaderWeirdPacking, EShLangVertex);760const auto disassembly = Disassemble(words);761EXPECT_THAT(disassembly, HasSubstr("OpMemberDecorate %B 1 Offset 16"))762<< disassembly;763}764765TEST_F(CompilerTest, HlslOffsetsOptionDisableRespected) {766compiler_.SetHlslOffsets(false);767const auto words =768SimpleCompilationBinary(kGlslShaderWeirdPacking, EShLangVertex);769const auto disassembly = Disassemble(words);770EXPECT_THAT(disassembly, HasSubstr("OpMemberDecorate %B 1 Offset 16"))771<< disassembly;772}773774TEST_F(CompilerTest, HlslOffsetsOptionEnableRespected) {775compiler_.SetHlslOffsets(true);776const auto words =777SimpleCompilationBinary(kGlslShaderWeirdPacking, EShLangVertex);778const auto disassembly = Disassemble(words);779EXPECT_THAT(disassembly, HasSubstr("OpMemberDecorate %B 1 Offset 4"))780<< disassembly;781}782783TEST_F(CompilerTest, HlslLegalizationEnabledNoSizeOpt) {784compiler_.SetSourceLanguage(Compiler::SourceLanguage::HLSL);785const auto words =786SimpleCompilationBinary(kHlslShaderForLegalizationTest, EShLangFragment);787const auto disassembly = Disassemble(words);788EXPECT_THAT(disassembly, Not(HasSubstr("OpFunctionCall"))) << disassembly;789EXPECT_THAT(disassembly, HasSubstr("OpName")) << disassembly;790}791792TEST_F(CompilerTest, HlslLegalizationEnabledWithSizeOpt) {793compiler_.SetSourceLanguage(Compiler::SourceLanguage::HLSL);794compiler_.SetOptimizationLevel(Compiler::OptimizationLevel::Size);795const auto words =796SimpleCompilationBinary(kHlslShaderForLegalizationTest, EShLangFragment);797const auto disassembly = Disassemble(words);798EXPECT_THAT(disassembly, Not(HasSubstr("OpFunctionCall"))) << disassembly;799EXPECT_THAT(disassembly, Not(HasSubstr("OpName"))) << disassembly;800}801802TEST_F(CompilerTest, HlslLegalizationDisabled) {803compiler_.SetSourceLanguage(Compiler::SourceLanguage::HLSL);804compiler_.EnableHlslLegalization(false);805const auto words =806SimpleCompilationBinary(kHlslShaderForLegalizationTest, EShLangFragment);807const auto disassembly = Disassemble(words);808EXPECT_THAT(disassembly, HasSubstr("OpFunctionCall")) << disassembly;809}810811TEST_F(CompilerTest, HlslFunctionality1Enabled) {812compiler_.SetSourceLanguage(Compiler::SourceLanguage::HLSL);813compiler_.EnableHlslFunctionality1(true);814compiler_.SetAutoBindUniforms(true); // Counter variable needs a binding.815const auto words =816SimpleCompilationBinary(kHlslShaderWithCounterBuffer, EShLangFragment);817const auto disassembly = Disassemble(words);818EXPECT_THAT(disassembly,819HasSubstr("OpExtension \"SPV_GOOGLE_hlsl_functionality1\""))820<< disassembly;821EXPECT_THAT(disassembly,822HasSubstr("OpDecorateString %_entryPointOutput "823"UserSemantic \"SV_TARGET0\""))824<< disassembly;825}826827TEST_F(CompilerTest, RelaxedVulkanRulesEnabled) {828compiler_.SetSourceLanguage(Compiler::SourceLanguage::GLSL);829compiler_.SetAutoBindUniforms(true); // Uniform variable needs a binding830compiler_.SetVulkanRulesRelaxed(true);831const auto words =832SimpleCompilationBinary(kGlslFragShaderOpaqueUniforms, EShLangFragment);833const auto disassembly = Disassemble(words);834EXPECT_THAT(disassembly,835HasSubstr("OpMemberName %gl_DefaultUniformBlock 0 \"a\""))836<< disassembly;837}838839TEST_F(CompilerTest, ClampMapsToFClampByDefault) {840const auto words =841SimpleCompilationBinary(kGlslShaderWithClamp, EShLangFragment);842const auto disassembly = Disassemble(words);843EXPECT_THAT(disassembly, HasSubstr("OpExtInst %v4float %1 FClamp"))844<< disassembly;845}846847TEST_F(CompilerTest, ClampMapsToFClampWithNanClamp) {848compiler_.SetNanClamp(true);849const auto words =850SimpleCompilationBinary(kGlslShaderWithClamp, EShLangFragment);851const auto disassembly = Disassemble(words);852EXPECT_THAT(disassembly, HasSubstr("OpExtInst %v4float %1 NClamp"))853<< disassembly;854}855856// A test coase for Glslang857// expected vector after the conversion.858struct GetGlslangClientInfoCase {859std::string prefix;860Compiler::TargetEnv env;861Compiler::TargetEnvVersion env_version;862Compiler::SpirvVersion spv_version;863bool spv_forced;864// Expected results. The error field is matched as a substring.865GlslangClientInfo expected;866};867868// Test the shaderc_util::GetGlslangClientInfo function.869using GetGlslangClientInfoTest =870testing::TestWithParam<GetGlslangClientInfoCase>;871872TEST_P(GetGlslangClientInfoTest, Sample) {873const auto& c = GetParam();874const auto& expected = c.expected;875auto result = shaderc_util::GetGlslangClientInfo(876c.prefix, c.env, c.env_version, c.spv_version, c.spv_forced);877878EXPECT_THAT(result.error.empty(), Eq(expected.error.empty()));879if (result.error.empty()) {880EXPECT_THAT(result.client, Eq(expected.client));881EXPECT_THAT(result.client_version, Eq(expected.client_version));882EXPECT_THAT(result.target_language, Eq(expected.target_language));883EXPECT_THAT(result.target_language_version,884Eq(expected.target_language_version));885} else {886EXPECT_THAT(result.error, HasSubstr(expected.error));887}888}889890#define CASE_VK(VKVER, SPVVER) \891"", Compiler::TargetEnv::Vulkan, Compiler::TargetEnvVersion::Vulkan_##VKVER, \892Compiler::SpirvVersion::v##SPVVER893894#define BADCASE_VK(STR, VKVER, SPVVER) \895STR, Compiler::TargetEnv::Vulkan, \896static_cast<Compiler::TargetEnvVersion>(VKVER), \897static_cast<Compiler::SpirvVersion>(SPVVER)898899#define CASE_GL(GLVER, SPVVER) \900"", Compiler::TargetEnv::OpenGL, Compiler::TargetEnvVersion::OpenGL_##GLVER, \901Compiler::SpirvVersion::v##SPVVER902903#define BADCASE_GL(STR, GLVER, SPVVER) \904STR, Compiler::TargetEnv::OpenGL, \905static_cast<Compiler::TargetEnvVersion>(GLVER), \906static_cast<Compiler::SpirvVersion>(SPVVER)907908#define GCASE_VK(STR, VKVER, SPVVER) \909shaderc_util::GlslangClientInfo { \910std::string(STR), glslang::EShClientVulkan, \911glslang::EShTargetVulkan_##VKVER, glslang::EShTargetSpv, \912glslang::EShTargetSpv_##SPVVER \913}914915#define GCASE_GL(STR, GLVER, SPVVER) \916shaderc_util::GlslangClientInfo { \917std::string(STR), glslang::EShClientOpenGL, \918glslang::EShTargetOpenGL_##GLVER, glslang::EShTargetSpv, \919glslang::EShTargetSpv_##SPVVER \920}921922INSTANTIATE_TEST_SUITE_P(923UnforcedSpirvSuccess, GetGlslangClientInfoTest,924testing::ValuesIn(std::vector<GetGlslangClientInfoCase>{925// Unforced SPIR-V version. Success cases.926{CASE_VK(1_0, 1_4), false, GCASE_VK("", 1_0, 1_0)},927{CASE_VK(1_1, 1_4), false, GCASE_VK("", 1_1, 1_3)},928{CASE_GL(4_5, 1_4), false, GCASE_GL("", 450, 1_0)},929}));930931INSTANTIATE_TEST_SUITE_P(932ForcedSpirvSuccess, GetGlslangClientInfoTest,933testing::ValuesIn(std::vector<GetGlslangClientInfoCase>{934// Forced SPIR-V version. Success cases.935{CASE_VK(1_0, 1_0), true, GCASE_VK("", 1_0, 1_0)},936{CASE_VK(1_0, 1_1), true, GCASE_VK("", 1_0, 1_1)},937{CASE_VK(1_0, 1_2), true, GCASE_VK("", 1_0, 1_2)},938{CASE_VK(1_0, 1_3), true, GCASE_VK("", 1_0, 1_3)},939{CASE_VK(1_1, 1_0), true, GCASE_VK("", 1_1, 1_0)},940{CASE_VK(1_1, 1_1), true, GCASE_VK("", 1_1, 1_1)},941{CASE_VK(1_1, 1_2), true, GCASE_VK("", 1_1, 1_2)},942{CASE_VK(1_1, 1_3), true, GCASE_VK("", 1_1, 1_3)},943{CASE_GL(4_5, 1_0), true, GCASE_GL("", 450, 1_0)},944{CASE_GL(4_5, 1_1), true, GCASE_GL("", 450, 1_1)},945{CASE_GL(4_5, 1_2), true, GCASE_GL("", 450, 1_2)},946}));947948INSTANTIATE_TEST_SUITE_P(949Failure, GetGlslangClientInfoTest,950testing::ValuesIn(std::vector<GetGlslangClientInfoCase>{951// Failure cases.952{BADCASE_VK("foo", 999, Compiler::SpirvVersion::v1_0), false,953GCASE_VK("error:foo: Invalid target client version 999 for Vulkan "954"environment 0",9551_0, 1_0)},956{BADCASE_GL("foo", 999, Compiler::SpirvVersion::v1_0), false,957GCASE_GL("error:foo: Invalid target client version 999 for OpenGL "958"environment 1",959450, 1_0)},960// For bad SPIR-V versions, have to force=true to make it pay attention.961{BADCASE_VK("foo", Compiler::TargetEnvVersion::Vulkan_1_0, 999), true,962GCASE_VK("error:foo: Unknown SPIR-V version 3e7", 1_0, 1_0)},963{BADCASE_GL("foo", Compiler::TargetEnvVersion::OpenGL_4_5, 999), true,964GCASE_GL("error:foo: Unknown SPIR-V version 3e7", 450, 1_0)},965}));966967#undef CASE_VK968#undef CASE_GL969#undef BADCASE_VK970#undef BADCASE_GL971#undef GCASE_VK972#undef GCASE_GL973} // anonymous namespace974975976