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