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