1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2020 Google LLC
6  * Copyright (c) 2020 The Khronos Group Inc.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Test new features in VK_KHR_shader_terminate_invocation
23  *//*--------------------------------------------------------------------*/
24 
25 #include <string>
26 #include <vector>
27 #include <amber/amber.h>
28 
29 #include "tcuDefs.hpp"
30 
31 #include "vkDefs.hpp"
32 #include "vktTestGroupUtil.hpp"
33 #include "vktAmberTestCase.hpp"
34 #include "vktSpvAsmTerminateInvocationTests.hpp"
35 #include "vktTestGroupUtil.hpp"
36 
37 namespace vkt
38 {
39 namespace SpirVAssembly
40 {
41 namespace
42 {
43 
44 struct Case
45 {
Casevkt::SpirVAssembly::__anon3d6193bc0111::Case46     Case(const char *b, bool v) : basename(b), spv1p3(v), requirements()
47     {
48     }
Casevkt::SpirVAssembly::__anon3d6193bc0111::Case49     Case(const char *b, bool v, const std::vector<std::string> &e) : basename(b), spv1p3(v), requirements(e)
50     {
51     }
52     const char *basename;
53     bool spv1p3;
54     // Additional Vulkan requirements, if any.
55     std::vector<std::string> requirements;
56 };
57 struct CaseGroup
58 {
CaseGroupvkt::SpirVAssembly::__anon3d6193bc0111::CaseGroup59     CaseGroup(const char *the_data_dir) : data_dir(the_data_dir)
60     {
61     }
addvkt::SpirVAssembly::__anon3d6193bc0111::CaseGroup62     void add(const char *basename, bool spv1p3)
63     {
64         cases.push_back(Case(basename, spv1p3));
65     }
addvkt::SpirVAssembly::__anon3d6193bc0111::CaseGroup66     void add(const char *basename, bool spv1p3, const std::vector<std::string> &requirements)
67     {
68         cases.push_back(Case(basename, spv1p3, requirements));
69     }
70 
71     const char *data_dir;
72     std::vector<Case> cases;
73 };
74 
75 #ifndef CTS_USES_VULKANSC
76 
addTestsForAmberFiles(tcu::TestCaseGroup * tests,CaseGroup group)77 void addTestsForAmberFiles(tcu::TestCaseGroup *tests, CaseGroup group)
78 {
79     tcu::TestContext &testCtx = tests->getTestContext();
80     const std::string data_dir(group.data_dir);
81     const std::string category = data_dir;
82     std::vector<Case> cases(group.cases);
83 
84     for (unsigned i = 0; i < cases.size(); ++i)
85     {
86         uint32_t vulkan_version = cases[i].spv1p3 ? VK_MAKE_API_VERSION(0, 1, 1, 0) : VK_MAKE_API_VERSION(0, 1, 0, 0);
87         vk::SpirvVersion spirv_version = cases[i].spv1p3 ? vk::SPIRV_VERSION_1_3 : vk::SPIRV_VERSION_1_0;
88         vk::SpirVAsmBuildOptions asm_options(vulkan_version, spirv_version);
89 
90         const std::string file = std::string(cases[i].basename) + ".amber";
91         cts_amber::AmberTestCase *testCase =
92             cts_amber::createAmberTestCase(testCtx, cases[i].basename, category.c_str(), file);
93         DE_ASSERT(testCase != DE_NULL);
94         testCase->addRequirement("VK_KHR_shader_terminate_invocation");
95         const std::vector<std::string> &reqmts = cases[i].requirements;
96         for (size_t r = 0; r < reqmts.size(); ++r)
97         {
98             testCase->addRequirement(reqmts[r]);
99         }
100 
101         testCase->setSpirVAsmBuildOptions(asm_options);
102         tests->addChild(testCase);
103     }
104 }
105 
106 #endif // CTS_USES_VULKANSC
107 
108 } // namespace
109 
createTerminateInvocationGroup(tcu::TestContext & testCtx)110 tcu::TestCaseGroup *createTerminateInvocationGroup(tcu::TestContext &testCtx)
111 {
112     // VK_KHR_shader_terminate_invocation tests
113     de::MovePtr<tcu::TestCaseGroup> terminateTests(new tcu::TestCaseGroup(testCtx, "terminate_invocation"));
114 
115     const char *data_data = "spirv_assembly/instruction/terminate_invocation";
116 
117     std::vector<std::string> Stores;
118     Stores.push_back("Features.fragmentStoresAndAtomics");
119 
120     std::vector<std::string> VarPtr;
121     VarPtr.push_back("VariablePointerFeatures.variablePointersStorageBuffer");
122     VarPtr.push_back("Features.fragmentStoresAndAtomics");
123 
124     std::vector<std::string> Vote;
125     Vote.push_back("SubgroupSupportedOperations.vote");
126     Vote.push_back("SubgroupSupportedStages.fragment");
127 
128     std::vector<std::string> Ballot;
129     Ballot.push_back("SubgroupSupportedOperations.ballot");
130     Ballot.push_back("SubgroupSupportedStages.fragment");
131 
132     CaseGroup group(data_data);
133     // no write to after calling terminate invocation
134     group.add("no_output_write", false);
135     // no write to output despite occurring before terminate invocation
136     group.add("no_output_write_before_terminate", false);
137     // no store to SSBO when it occurs after terminate invocation
138     group.add("no_ssbo_store", false, Stores);
139     // no atomic update to SSBO when it occurs after terminate invocation
140     group.add("no_ssbo_atomic", false, Stores);
141     // ssbo store commits when it occurs before terminate invocation
142     group.add("ssbo_store_before_terminate", false, Stores);
143     // no image write when it occurs after terminate invocation
144     group.add("no_image_store", false, Stores);
145     // no image atomic updates when it occurs after terminate invocation
146     group.add("no_image_atomic", false, Stores);
147     // null pointer should not be accessed by a load in a terminated invocation
148     group.add("no_null_pointer_load", false, VarPtr);
149     // null pointer should not be accessed by a store in a terminated invocation
150     group.add("no_null_pointer_store", false, VarPtr);
151     // out of bounds pointer should not be accessed by a load in a terminated invocation
152     group.add("no_out_of_bounds_load", false, VarPtr);
153     // out of bounds pointer should not be accessed by a store in a terminated invocation
154     group.add("no_out_of_bounds_store", false, VarPtr);
155     // out of bounds pointer should not be accessed by an atomic in a terminated invocation
156     group.add("no_out_of_bounds_atomic", false, VarPtr);
157     // "infinite" loop that calls terminate invocation
158     group.add("terminate_loop", false);
159     // checks that terminated invocations don't participate in the ballot
160     group.add("subgroup_ballot", true, Ballot);
161     // checks that a subgroup all does not include any terminated invocations
162     group.add("subgroup_vote", true, Vote);
163 #ifndef CTS_USES_VULKANSC
164     terminateTests->addChild(createTestGroup(testCtx, "terminate", addTestsForAmberFiles, group));
165 #endif // CTS_USES_VULKANSC
166 
167     return terminateTests.release();
168 }
169 
170 } // namespace SpirVAssembly
171 } // namespace vkt
172