yum-mirror/glslang
git clone https://git.yummers.dev/yum-mirror/glslang
fa2e5029
main
1// Copyright (C) 2026 The Khronos Group Inc. 2// 3// All rights reserved. 4// 5// Redistribution and use in source and binary forms, with or without 6// modification, are permitted provided that the following conditions 7// are met: 8// 9// Redistributions of source code must retain the above copyright 10// notice, this list of conditions and the following disclaimer. 11// 12// Redistributions in binary form must reproduce the above 13// copyright notice, this list of conditions and the following 14// disclaimer in the documentation and/or other materials provided 15// with the distribution. 16// 17// Neither the name of The Khronos Group Inc. nor the names of its 18// contributors may be used to endorse or promote products derived 19// from this software without specific prior written permission. 20// 21// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32// POSSIBILITY OF SUCH DAMAGE. 33 34#include "TestFixture.h" 35#include "glslang/Public/ResourceLimits.h" 36#include "glslang/Public/ShaderLang.h" 37#include "SPIRV/GlslangToSpv.h" 38#include "SPIRV/disassemble.h" 39#include <gtest/gtest.h> 40#include <sstream> 41#include <string> 42#include <vector> 43 44namespace glslangtest { 45 46class InvertYTest :public ::testing::Test { 47protected : 48struct CompileResult { 49bool success ; 50 std::string spirvText ; 51 std::string infoLog ; 52 }; 53 54CompileResult compileGlsl (const std::string & source ,EShLanguage stage ,bool invertY ) 55 { 56 glslang::TShader shader (stage ); 57 glslang::TProgram program ; 58 59const char * src = source .c_str (); 60shader .setStrings (& src ,1 ); 61shader .setEnvInput (glslang::EShSourceGlsl ,stage , glslang::EShClientVulkan ,100 ); 62shader .setEnvClient (glslang::EShClientVulkan , glslang::EShTargetVulkan_1_0 ); 63shader .setEnvTarget (glslang::EShTargetSpv , glslang::EShTargetSpv_1_0 ); 64shader .setInvertY (invertY ); 65 66EShMessages msgs = static_cast < EShMessages > (EShMsgSpvRules |EShMsgVulkanRules ); 67if (!shader .parse (GetDefaultResources (),450 , false,msgs )) { 68return {false,"" ,shader .getInfoLog ()}; 69 } 70 71program .addShader (& shader ); 72if (!program .link (msgs )) { 73return {false,"" ,program .getInfoLog ()}; 74 } 75 76 std::vector < uint32_t > spirv ; 77 glslang::GlslangToSpv (* program .getIntermediate (stage ),spirv ); 78 79 std::ostringstream dis ; 80 spv::Disassemble (dis ,spirv ); 81return {true,dis .str (),"" }; 82 } 83 84// Helper function to check if the given SPIR-V string contains a specific pattern. 85bool containsPattern (const std::string & spirvText ,const std::string & pattern ) 86 { 87return spirvText .find (pattern )!= std::string::npos ; 88 } 89 90// Helper function to check if the given SPIR-V string contains a FNegate instruction. 91bool containsFNegate (const std::string & spirvText ) {return containsPattern (spirvText ,"FNegate" ); } 92}; 93 94// A minimal vertex shader that writes gl_Position. 95static const char * kSimpleVert = R"glsl( 96#version 450 97layout ( location = 0 ) in vec3 pos ; 98void main () { 99gl_Position = vec4 ( pos , 1.0 ); 100} 101)glsl" ; 102 103// A vertex shader that writes gl_Position multiple times to exercise all 104// assignment sites (braces ensure each branch is a sequence node). 105static const char * kMultiAssignVert = R"glsl( 106#version 450 107layout ( location = 0 ) in vec3 pos ; 108layout ( location = 1 ) in float w ; 109void main () { 110if ( w > 0.0 ) { 111gl_Position = vec4 ( pos , w ); 112} else { 113gl_Position = vec4 ( - pos , - w ); 114} 115} 116)glsl" ; 117 118// A geometry shader (takes triangles, emits a single vertex). 119static const char * kSimpleGeom = R"glsl( 120#version 450 121layout ( triangles ) in ; 122layout ( triangle_strip , max_vertices = 3 ) out ; 123void main () { 124gl_Position = gl_in [ 0 ]. gl_Position ; 125EmitVertex (); 126} 127)glsl" ; 128 129// A tessellation evaluation shader. 130static const char * kSimpleTese = R"glsl( 131#version 450 132layout ( triangles , equal_spacing , ccw ) in ; 133void main () { 134gl_Position = gl_in [ 0 ]. gl_Position ; 135} 136)glsl" ; 137 138// --- Vertex stage --- 139 140TEST_F (InvertYTest ,VertexWithInvertYContainsFNegate ) 141{ 142auto r = compileGlsl (kSimpleVert ,EShLangVertex , true); 143ASSERT_TRUE (r .success ) <<r .infoLog ; 144EXPECT_TRUE (containsFNegate (r .spirvText )) 145 <<"Expected OpFNegate in SPIR-V when setInvertY(true) is used.\n" 146 <<r .spirvText ; 147} 148 149TEST_F (InvertYTest ,VertexWithoutInvertYNoFNegate ) 150{ 151auto r = compileGlsl (kSimpleVert ,EShLangVertex , false); 152ASSERT_TRUE (r .success ) <<r .infoLog ; 153EXPECT_FALSE (containsFNegate (r .spirvText )) 154 <<"Expected no OpFNegate in SPIR-V when setInvertY(false) is used.\n" 155 <<r .spirvText ; 156} 157 158TEST_F (InvertYTest ,VertexMultipleAssignmentsAllInverted ) 159{ 160auto r = compileGlsl (kMultiAssignVert ,EShLangVertex , true); 161ASSERT_TRUE (r .success ) <<r .infoLog ; 162EXPECT_TRUE (containsFNegate (r .spirvText )) 163 <<"Expected OpFNegate in SPIR-V for shader with multiple gl_Position assignments.\n" 164 <<r .spirvText ; 165} 166 167// --- Geometry stage --- 168 169TEST_F (InvertYTest ,GeometryWithInvertYContainsFNegate ) 170{ 171auto r = compileGlsl (kSimpleGeom ,EShLangGeometry , true); 172ASSERT_TRUE (r .success ) <<r .infoLog ; 173EXPECT_TRUE (containsFNegate (r .spirvText )) 174 <<"Expected OpFNegate in geometry shader SPIR-V when setInvertY(true).\n" 175 <<r .spirvText ; 176} 177 178TEST_F (InvertYTest ,GeometryWithoutInvertYNoFNegate ) 179{ 180auto r = compileGlsl (kSimpleGeom ,EShLangGeometry , false); 181ASSERT_TRUE (r .success ) <<r .infoLog ; 182EXPECT_FALSE (containsFNegate (r .spirvText )) 183 <<"Expected no OpFNegate in geometry shader SPIR-V when setInvertY(false).\n" 184 <<r .spirvText ; 185} 186 187// --- Tessellation evaluation stage --- 188 189TEST_F (InvertYTest ,TessEvalWithInvertYContainsFNegate ) 190{ 191auto r = compileGlsl (kSimpleTese ,EShLangTessEvaluation , true); 192ASSERT_TRUE (r .success ) <<r .infoLog ; 193EXPECT_TRUE (containsFNegate (r .spirvText )) 194 <<"Expected OpFNegate in tessellation evaluation shader SPIR-V when setInvertY(true).\n" 195 <<r .spirvText ; 196} 197 198TEST_F (InvertYTest ,TessEvalWithoutInvertYNoFNegate ) 199{ 200auto r = compileGlsl (kSimpleTese ,EShLangTessEvaluation , false); 201ASSERT_TRUE (r .success ) <<r .infoLog ; 202EXPECT_FALSE (containsFNegate (r .spirvText )) 203 <<"Expected no OpFNegate in tessellation evaluation shader SPIR-V when setInvertY(false).\n" 204 <<r .spirvText ; 205} 206 207// --- Compute stage should not be affected --- 208 209TEST_F (InvertYTest ,ComputeWithInvertYFlagNoFNegate ) 210{ 211// Compute shaders have no gl_Position; the flag must be a no-op. 212const char * src = R"glsl( 213#version 450 214layout ( local_size_x = 1 ) in ; 215layout ( binding = 0 ) buffer Out { float val ; }; 216void main () { val = 1.0 ; } 217)glsl" ; 218auto r = compileGlsl (src ,EShLangCompute , true); 219ASSERT_TRUE (r .success ) <<r .infoLog ; 220EXPECT_FALSE (containsFNegate (r .spirvText )) 221 <<"OpFNegate should not appear in a compute shader even with setInvertY(true).\n" 222 <<r .spirvText ; 223} 224 225}// namespace glslangtest