yum-mirror/glslang

git clone https://git.yummers.dev/yum-mirror/glslang

Valentin SarthouAdd --discard-is-terminate option (#4081)c8ec3690

main
6.1 KiB153 linesraw
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/ShaderLang.h"
36#include "SPIRV/GlslangToSpv.h"
37#include "SPIRV/disassemble.h"
38#include <gtest/gtest.h>
39#include <sstream>
40#include <string>
41#include <vector>
42
43namespace glslangtest {
44
45class DiscardTest : public ::testing::Test {
46protected:
47    struct CompileResult {
48        bool success;
49        std::string spirvText;
50        std::string infoLog;
51    };
52
53    CompileResult compileGlsl(const std::string& source, glslang::EShTargetLanguageVersion spvVersion,
54                              bool discardIsTerminate)
55    {
56        const char* const src = source.c_str();
57
58        glslang::TShader shader(EShLangFragment);
59        shader.setStrings(&src, 1);
60        shader.setEnvInput(glslang::EShSourceGlsl, EShLangFragment, glslang::EShClientVulkan, 100);
61        shader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_4);
62        shader.setEnvTarget(glslang::EShTargetSpv, spvVersion);
63        shader.setAutoMapBindings(true);
64        shader.setAutoMapLocations(true);
65        shader.setDiscardIsTerminate(discardIsTerminate);
66
67        const EShMessages msgs = static_cast<EShMessages>(EShMsgSpvRules | EShMsgVulkanRules);
68        if (!shader.parse(GetDefaultResources(), 450, false, msgs)) {
69            return {false, "", shader.getInfoLog()};
70        }
71
72        glslang::TProgram program;
73        program.addShader(&shader);
74        if (!program.link(msgs)) {
75            return {false, "", program.getInfoLog()};
76        }
77
78        std::vector<uint32_t> spirv;
79        glslang::GlslangToSpv(*program.getIntermediate(EShLangFragment), spirv);
80
81        std::ostringstream dis;
82        spv::Disassemble(dis, spirv);
83        return {true, dis.str(), ""};
84    }
85
86    // Helper function to check if the given SPIR-V string contains a specific pattern.
87    static bool containsPattern(const std::string& spirvText, const std::string& pattern)
88    {
89        return spirvText.find(pattern) != std::string::npos;
90    }
91};
92
93static const char kSimpleFrag[] = R"glsl(
94#version 450
95uniform sampler2D tex;
96in vec2 texCoord;
97out vec4 outColor;
98void main() {
99    outColor = texture(tex, texCoord);
100    if (outColor.a == 0.0)
101        discard;
102}
103)glsl";
104
105TEST_F(DiscardTest, DiscardMappedToOpKill)
106{
107    const bool discardIsTerminate = false;
108    auto const r = compileGlsl(kSimpleFrag, glslang::EShTargetSpv_1_4, discardIsTerminate);
109    ASSERT_TRUE(r.success) << r.infoLog;
110    EXPECT_TRUE(containsPattern(r.spirvText, "Kill"))
111        << "Expected OpKill in SPIR-V when SPIR-V version < 1.6 is used.\n"
112        << r.spirvText;
113    EXPECT_FALSE(containsPattern(r.spirvText, "DemoteToHelperInvocation"))
114        << "Did not expect OpDemoteToHelperInvocation in SPIR-V when SPIR-V version < 1.6 is used.\n"
115        << r.spirvText;
116    EXPECT_FALSE(containsPattern(r.spirvText, "TerminateInvocation"))
117        << "Did not expect OpTerminateInvocation in SPIR-V when SPIR-V version < 1.6 is used.\n"
118        << r.spirvText;
119}
120
121TEST_F(DiscardTest, DiscardMappedToOpDemoteToHelperInvocation)
122{
123    const bool discardIsTerminate = false;
124    auto const r = compileGlsl(kSimpleFrag, glslang::EShTargetSpv_1_6, discardIsTerminate);
125    ASSERT_TRUE(r.success) << r.infoLog;
126    EXPECT_FALSE(containsPattern(r.spirvText, "Kill"))
127        << "Did not expect OpKill in SPIR-V when SPIR-V version >= 1.6 is used.\n"
128        << r.spirvText;
129    EXPECT_TRUE(containsPattern(r.spirvText, "DemoteToHelperInvocation"))
130        << "Expected OpDemoteToHelperInvocation in SPIR-V when setDiscardIsTerminate(false) is used.\n"
131        << r.spirvText;
132    EXPECT_FALSE(containsPattern(r.spirvText, "TerminateInvocation"))
133        << "Did not expect OpTerminateInvocation in SPIR-V when setDiscardIsTerminate(false) is used.\n"
134        << r.spirvText;
135}
136
137TEST_F(DiscardTest, DiscardMappedToOpTerminateInvocation)
138{
139    const bool discardIsTerminate = true;
140    auto const r = compileGlsl(kSimpleFrag, glslang::EShTargetSpv_1_6, discardIsTerminate);
141    ASSERT_TRUE(r.success) << r.infoLog;
142    EXPECT_FALSE(containsPattern(r.spirvText, "Kill"))
143        << "Did not expect OpKill in SPIR-V when SPIR-V version >= 1.6 is used.\n"
144        << r.spirvText;
145    EXPECT_FALSE(containsPattern(r.spirvText, "DemoteToHelperInvocation"))
146        << "Did not expect OpDemoteToHelperInvocation in SPIR-V when setDiscardIsTerminate(true) is used.\n"
147        << r.spirvText;
148    EXPECT_TRUE(containsPattern(r.spirvText, "TerminateInvocation"))
149        << "Expected OpTerminateInvocation in SPIR-V when setDiscardIsTerminate(true) is used.\n"
150        << r.spirvText;
151}
152
153} // namespace glslangtest