c2c6e2e5edd52de7792b773b767bc35719637ca7
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / spirv_assembly / vktSpvAsmLoopDepInfTests.cpp
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 DependencyInfinite qualifier tests
22  *//*--------------------------------------------------------------------*/
23
24 #include "vkApiVersion.hpp"
25
26 #include "vktSpvAsmLoopDepInfTests.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 < n; ++i)
58 //     c[i] = float(i) * input_data.elements[x];
59 //
60 //   output_data.elements[x] = 0.0f;
61 //   for (uint i = 0; i < n; ++i)
62 //     output_data.elements[x] += c[i];
63 // }
64 static void getComputeSourceCode (std::string& computeSourceCode)
65 {
66         computeSourceCode =
67                 string(getComputeAsmShaderPreamble()) +
68
69                 "OpSource GLSL 430\n"
70                 "OpName %main \"main\"\n"
71                 "OpName %id \"gl_GlobalInvocationID\"\n"
72
73                 "OpDecorate %id BuiltIn GlobalInvocationId\n"
74
75                 + string(getComputeAsmInputOutputBufferTraits()) + string(getComputeAsmCommonTypes()) + string(getComputeAsmInputOutputBuffer()) +
76
77                 "%u32ptr        = OpTypePointer Function %u32\n"
78
79                 "%id            = OpVariable %uvec3ptr Input\n"
80                 "%zero          = OpConstant %i32 0\n"
81                 "%uzero         = OpConstant %u32 0\n"
82                 "%fzero         = OpConstant %f32 0\n"
83                 "%one           = OpConstant %i32 1\n"
84                 "%twelve        = OpConstant %u32 12\n"
85                 "%f32arr12_t    = OpTypeArray %f32 %twelve\n"
86                 "%f32arr12ptr_t = OpTypePointer Function %f32arr12_t\n"
87                 "%f32funcptr    = OpTypePointer Function %f32\n"
88                 "%main          = OpFunction %void None %voidf\n"
89                 "%entry         = OpLabel\n"
90
91                 "%f32arr12      = OpVariable %f32arr12ptr_t Function\n"
92
93                 "%i1            = OpVariable %u32ptr Function\n"
94                 "                 OpStore %i1 %uzero\n"
95                 "%i2            = OpVariable %u32ptr Function\n"
96                 "                 OpStore %i2 %uzero\n"
97
98                 "%idval         = OpLoad %uvec3 %id\n"
99                 "%x             = OpCompositeExtract %u32 %idval 0\n"
100                 "%inloc         = OpAccessChain %f32ptr %indata %zero %x\n"
101                 "%inval         = OpLoad %f32 %inloc\n"
102
103                 // for (uint i = 0; i < 12; ++i) c[i] = float(i) * input_data.elements[x];
104                 "                 OpBranch %loop1_entry\n"
105                 "%loop1_entry   = OpLabel\n"
106                 "%i1_val        = OpLoad %u32 %i1\n"
107                 "%cmp1_lt       = OpULessThan %bool %i1_val %twelve\n"
108                 "                 OpLoopMerge %loop1_merge %loop1_body DependencyInfinite\n"
109                 "                 OpBranchConditional %cmp1_lt %loop1_body %loop1_merge\n"
110                 "%loop1_body    = OpLabel\n"
111                 "%i1_valf32     = OpConvertUToF %f32 %i1_val\n"
112                 "%mulf1         = OpFMul %f32 %i1_valf32 %inval\n"
113                 "%outloc1       = OpAccessChain %f32funcptr %f32arr12 %i1_val\n"
114                 "                 OpStore %outloc1 %mulf1\n"
115                 "%new1_i        = OpIAdd %u32 %i1_val %one\n"
116                 "                 OpStore %i1 %new1_i\n"
117                 "                 OpBranch %loop1_entry\n"
118                 "%loop1_merge   = OpLabel\n"
119
120                 //   output_data.elements[x] = 0.0f;
121                 "%outloc        = OpAccessChain %f32ptr %outdata %zero %x\n"
122                 "                 OpStore %outloc %fzero\n"
123                 "                 OpBranch %loop2_entry\n"
124
125                 //   for (uint i = 0; i < n; ++i) output_data.elements[x] += c[i];
126                 "%loop2_entry   = OpLabel\n"
127                 "%i2_val        = OpLoad %u32 %i2\n"
128                 "%cmp2_lt       = OpULessThan %bool %i2_val %twelve\n"
129                 "                 OpLoopMerge %loop2_merge %loop2_body None\n"
130                 "                 OpBranchConditional %cmp2_lt %loop2_body %loop2_merge\n"
131                 "%loop2_body    = OpLabel\n"
132                 "%arr1_i2loc    = OpAccessChain %f32funcptr %f32arr12 %i2_val\n"
133                 "%arr1_i2val    = OpLoad %f32 %arr1_i2loc\n"
134                 "%outval        = OpLoad %f32 %outloc\n"
135                 "%addf1         = OpFAdd %f32 %outval %arr1_i2val\n"
136                 "                 OpStore %outloc %addf1\n"
137                 "%new_i2        = OpIAdd %u32 %i2_val %one\n"
138                 "                 OpStore %i2 %new_i2\n"
139                 "                 OpBranch %loop2_entry\n"
140                 "%loop2_merge   = OpLabel\n"
141
142                 "                 OpReturn\n"
143                 "                 OpFunctionEnd\n";
144 }
145
146 static ComputeShaderSpec getComputeShaderSpec ()
147 {
148         de::Random                      rnd                             (0xABC);
149         const int                       numElements             = 100;
150         vector<float>           inputFloats             (numElements, 0);
151         vector<float>           outputFloats    (numElements, 0);
152         ComputeShaderSpec       spec;
153
154         for (size_t ndx = 0; ndx < numElements; ++ndx)
155                 inputFloats[ndx] = rnd.getFloat(1.0f, 100.0f);
156
157         for (size_t ndx = 0; ndx < numElements; ++ndx)
158         {
159                 const deUint32 n = 12;
160                 float c[n];
161                 float result = 0.0f;
162
163                 for (deUint32 i = 0; i < n; ++i)
164                         c[i] = float(i) * inputFloats[ndx];
165
166                 for (deUint32 i = 0; i < n; ++i)
167                         result += c[i];
168
169                 outputFloats[ndx] = result;
170         }
171
172         // Shader source code can be retrieved to complete definition of ComputeShaderSpec, though it is not required at this stage
173         // getComputeSourceCode (spec.assembly);
174
175         spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
176         spec.outputs.push_back(BufferSp(new Float32Buffer(outputFloats)));
177         spec.numWorkGroups = tcu::IVec3(numElements, 1, 1);
178
179         return spec;
180 }
181
182
183 class SpvAsmLoopControlDependencyInfiniteInstance : public ComputeShaderSpec, public SpvAsmComputeShaderInstance
184 {
185 public:
186         SpvAsmLoopControlDependencyInfiniteInstance     (Context& ctx);
187 };
188
189 SpvAsmLoopControlDependencyInfiniteInstance::SpvAsmLoopControlDependencyInfiniteInstance (Context& ctx)
190         : ComputeShaderSpec(getComputeShaderSpec())
191         , SpvAsmComputeShaderInstance(ctx, *this, COMPUTE_TEST_USES_NONE)
192 {
193 }
194
195 SpvAsmLoopControlDependencyInfiniteCase::SpvAsmLoopControlDependencyInfiniteCase (tcu::TestContext& testCtx, const char* name, const char* description)
196         : TestCase                      (testCtx, name, description)
197 {
198 }
199
200 void SpvAsmLoopControlDependencyInfiniteCase::initPrograms (SourceCollections& programCollection) const
201 {
202         std::string comp;
203
204         getComputeSourceCode(comp);
205
206         programCollection.spirvAsmSources.add("compute") << SpirVAsmBuildOptions(SPIRV_VERSION_1_3) << comp;
207 }
208
209 TestInstance* SpvAsmLoopControlDependencyInfiniteCase::createInstance (Context& context) const
210 {
211         if (context.getUsedApiVersion() < VK_API_VERSION_1_1)
212                 TCU_THROW(NotSupportedError, "SPIR-V higher than 1.3 is required for this test to run");
213
214         return new SpvAsmLoopControlDependencyInfiniteInstance(context);
215 }
216
217 } // SpirVAssembly
218 } // vkt