1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2017 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief SPIR-V Loop Control for DependencyLength qualifier tests
22 *//*--------------------------------------------------------------------*/
23
24 #include "vkApiVersion.hpp"
25
26 #include "vktSpvAsmLoopDepLenTests.hpp"
27 #include "vktTestCase.hpp"
28 #include "vktSpvAsmComputeShaderCase.hpp"
29
30 #include "deRandom.hpp"
31
32 namespace vkt
33 {
34 namespace SpirVAssembly
35 {
36
37 using namespace vk;
38 using std::map;
39 using std::string;
40 using std::vector;
41
42 // Assembly code used for testing loop control with dependencies is based on GLSL source code:
43 // #version 430
44 //
45 // layout(std140, set = 0, binding = 0) readonly buffer Input {
46 // float elements[];
47 // } input_data;
48 // layout(std140, set = 0, binding = 1) writeonly buffer Output {
49 // float elements[];
50 // } output_data;
51 //
52 // void main() {
53 // const uint n = 12;
54 // float c[n];
55 // uint x = gl_GlobalInvocationID.x;
56 //
57 // for (uint i = 0; i < 6; ++i)
58 // c[i] = float(i) * input_data.elements[x];
59 //
60 // for (uint i = 6; i < n; ++i)
61 // c[i] = c[i - 4] + c[i - 5] + c[i - 6];
62 //
63 // output_data.elements[x] = c[n - 1];
64 // }
getComputeSourceCode(std::string & computeSourceCode)65 static void getComputeSourceCode (std::string& computeSourceCode)
66 {
67 computeSourceCode =
68 string(getComputeAsmShaderPreamble()) +
69
70 "OpSource GLSL 430\n"
71 "OpName %main \"main\"\n"
72 "OpName %id \"gl_GlobalInvocationID\"\n"
73
74 "OpDecorate %id BuiltIn GlobalInvocationId\n"
75
76 + string(getComputeAsmInputOutputBufferTraits()) + string(getComputeAsmCommonTypes()) + string(getComputeAsmInputOutputBuffer()) +
77
78 "%u32ptr = OpTypePointer Function %u32\n"
79
80 "%id = OpVariable %uvec3ptr Input\n"
81 "%zero = OpConstant %i32 0\n"
82 "%uzero = OpConstant %u32 0\n"
83 "%one = OpConstant %i32 1\n"
84
85 "%four = OpConstant %u32 4\n"
86 "%five = OpConstant %u32 5\n"
87 "%six = OpConstant %u32 6\n"
88 "%elleven = OpConstant %u32 11\n"
89 "%twelve = OpConstant %u32 12\n"
90
91 "%f32arr12_t = OpTypeArray %f32 %twelve\n"
92 "%f32arr12ptr_t = OpTypePointer Function %f32arr12_t\n"
93 "%f32funcptr = OpTypePointer Function %f32\n"
94
95 "%main = OpFunction %void None %voidf\n"
96 "%entry = OpLabel\n"
97
98 "%f32arr12 = OpVariable %f32arr12ptr_t Function\n"
99
100 "%i1 = OpVariable %u32ptr Function\n"
101 "%i2 = OpVariable %u32ptr Function\n"
102 " OpStore %i1 %uzero\n"
103 " OpStore %i2 %six\n"
104
105 "%idval = OpLoad %uvec3 %id\n"
106 "%x = OpCompositeExtract %u32 %idval 0\n"
107 "%inloc = OpAccessChain %f32ptr %indata %zero %x\n"
108 "%inval = OpLoad %f32 %inloc\n"
109
110 // for (uint i = 0; i < 6; ++i) c[i] = float(i) * input_data.elements[x];
111 " OpBranch %loop1_entry\n"
112 "%loop1_entry = OpLabel\n"
113 "%i1_val = OpLoad %u32 %i1\n"
114 "%cmp1_lt = OpULessThan %bool %i1_val %six\n"
115 " OpLoopMerge %loop1_merge %loop1_body None\n"
116 " OpBranchConditional %cmp1_lt %loop1_body %loop1_merge\n"
117 "%loop1_body = OpLabel\n"
118 "%i1_valf32 = OpConvertUToF %f32 %i1_val\n"
119 "%mulf1 = OpFMul %f32 %i1_valf32 %inval\n"
120 "%outloc1 = OpAccessChain %f32funcptr %f32arr12 %i1_val\n"
121 " OpStore %outloc1 %mulf1\n"
122 "%new1_i = OpIAdd %u32 %i1_val %one\n"
123 " OpStore %i1 %new1_i\n"
124 " OpBranch %loop1_entry\n"
125 "%loop1_merge = OpLabel\n"
126
127 // for (uint i = 6; i < n; ++i) c[i] = c[i - 4] + c[i - 5] + c[i - 6];
128 " OpBranch %loop2_entry\n"
129 "%loop2_entry = OpLabel\n"
130 "%i2_val = OpLoad %u32 %i2\n"
131 "%cmp2_lt = OpULessThan %bool %i2_val %twelve\n"
132 " OpLoopMerge %loop2_merge %loop2_body DependencyLength 3\n"
133 " OpBranchConditional %cmp2_lt %loop2_body %loop2_merge\n"
134 "%loop2_body = OpLabel\n"
135 "%i2_m4 = OpISub %u32 %i2_val %four\n"
136 "%arr1_i2m4loc = OpAccessChain %f32funcptr %f32arr12 %i2_m4\n"
137 "%arr1_i2m4val = OpLoad %f32 %arr1_i2m4loc\n"
138 "%i2_m5 = OpISub %u32 %i2_val %five\n"
139 "%arr1_i2m5loc = OpAccessChain %f32funcptr %f32arr12 %i2_m5\n"
140 "%arr1_i2m5val = OpLoad %f32 %arr1_i2m5loc\n"
141 "%f32add1 = OpFAdd %f32 %arr1_i2m4val %arr1_i2m5val\n"
142 "%i2_m6 = OpISub %u32 %i2_val %six\n"
143 "%arr1_i2m6loc = OpAccessChain %f32funcptr %f32arr12 %i2_m6\n"
144 "%arr1_i2m6val = OpLoad %f32 %arr1_i2m6loc\n"
145 "%f32add2 = OpFAdd %f32 %f32add1 %arr1_i2m6val\n"
146 "%outloc2 = OpAccessChain %f32funcptr %f32arr12 %i2_val\n"
147 " OpStore %outloc2 %f32add2\n"
148 "%new_i2 = OpIAdd %u32 %i2_val %one\n"
149 " OpStore %i2 %new_i2\n"
150 " OpBranch %loop2_entry\n"
151 "%loop2_merge = OpLabel\n"
152
153 // output_data.elements[x] = c[n - 1];
154 "%arr1locq = OpAccessChain %f32funcptr %f32arr12 %elleven\n"
155 "%arr1valq = OpLoad %f32 %arr1locq\n"
156 "%outlocq = OpAccessChain %f32ptr %outdata %zero %x\n"
157 " OpStore %outlocq %arr1valq\n"
158 " OpReturn\n"
159 " OpFunctionEnd\n";
160 }
161
getComputeShaderSpec()162 static ComputeShaderSpec getComputeShaderSpec ()
163 {
164 de::Random rnd (0xABC);
165 const int numElements = 100;
166 vector<float> inputFloats (numElements, 0);
167 vector<float> outputFloats (numElements, 0);
168 ComputeShaderSpec spec;
169
170 for (size_t ndx = 0; ndx < numElements; ++ndx)
171 inputFloats[ndx] = rnd.getFloat(1.0f, 100.0f);
172
173 for (size_t ndx = 0; ndx < numElements; ++ndx)
174 {
175 const deUint32 n = 12;
176 float c[n];
177
178 for (deUint32 i = 0; i < 6; ++i)
179 c[i] = float(i) * inputFloats[ndx];
180
181 for (deUint32 i = 6; i < n; ++i)
182 c[i] = c[i - 4] + c[i - 5] + c[i - 6];
183
184 outputFloats[ndx] = c[n - 1];
185 }
186
187 // Shader source code can be retrieved to complete definition of ComputeShaderSpec, though it is not required at this stage
188 // getComputeSourceCode (spec.assembly);
189
190 spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
191 spec.outputs.push_back(BufferSp(new Float32Buffer(outputFloats)));
192 spec.numWorkGroups = tcu::IVec3(numElements, 1, 1);
193 spec.verifyIO = &verifyOutput;
194
195 return spec;
196 }
197
198
199 class SpvAsmLoopControlDependencyLengthInstance : public ComputeShaderSpec, public SpvAsmComputeShaderInstance
200 {
201 public:
202 SpvAsmLoopControlDependencyLengthInstance (Context& ctx);
203 };
204
SpvAsmLoopControlDependencyLengthInstance(Context & ctx)205 SpvAsmLoopControlDependencyLengthInstance::SpvAsmLoopControlDependencyLengthInstance (Context& ctx)
206 : ComputeShaderSpec(getComputeShaderSpec())
207 , SpvAsmComputeShaderInstance(ctx, *this)
208 {
209 }
210
SpvAsmLoopControlDependencyLengthCase(tcu::TestContext & testCtx,const char * name,const char * description)211 SpvAsmLoopControlDependencyLengthCase::SpvAsmLoopControlDependencyLengthCase (tcu::TestContext& testCtx, const char* name, const char* description)
212 : TestCase (testCtx, name, description)
213 {
214 }
215
initPrograms(SourceCollections & programCollection) const216 void SpvAsmLoopControlDependencyLengthCase::initPrograms (SourceCollections& programCollection) const
217 {
218 std::string comp;
219
220 getComputeSourceCode(comp);
221
222 programCollection.spirvAsmSources.add("compute") << SpirVAsmBuildOptions(programCollection.usedVulkanVersion, SPIRV_VERSION_1_3) << comp;
223 }
224
createInstance(Context & context) const225 TestInstance* SpvAsmLoopControlDependencyLengthCase::createInstance (Context& context) const
226 {
227 if (!context.contextSupports(vk::ApiVersion(1, 1, 0)))
228 TCU_THROW(NotSupportedError, "SPIR-V higher than 1.3 is required for this test to run");
229
230 return new SpvAsmLoopControlDependencyLengthInstance(context);
231 }
232
233 } // SpirVAssembly
234 } // vkt
235