1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2015 Google 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 Compute Shader Based Test Case Utility Structs/Functions
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktSpvAsmComputeShaderTestUtil.hpp"
25 #include "tcuStringTemplate.hpp"
26 
27 namespace vkt
28 {
29 namespace SpirVAssembly
30 {
31 namespace
32 {
verifyOutputWithEpsilon(const std::vector<AllocationSp> & outputAllocs,const std::vector<Resource> & expectedOutputs,tcu::TestLog & log,const float epsilon)33 bool verifyOutputWithEpsilon (const std::vector<AllocationSp>& outputAllocs, const std::vector<Resource>& expectedOutputs, tcu::TestLog& log, const float epsilon)
34 {
35 	DE_ASSERT(outputAllocs.size() != 0);
36 	DE_ASSERT(outputAllocs.size() == expectedOutputs.size());
37 
38 	for (size_t outputNdx = 0; outputNdx < outputAllocs.size(); ++outputNdx)
39 	{
40 		std::vector<deUint8>	expectedBytes;
41 		expectedOutputs[outputNdx].getBytes(expectedBytes);
42 
43 		std::vector<float>	expectedFloats	(expectedBytes.size() / sizeof (float));
44 		std::vector<float>	actualFloats	(expectedBytes.size() / sizeof (float));
45 
46 		memcpy(&expectedFloats[0], &expectedBytes.front(), expectedBytes.size());
47 		memcpy(&actualFloats[0], outputAllocs[outputNdx]->getHostPtr(), expectedBytes.size());
48 		for (size_t floatNdx = 0; floatNdx < actualFloats.size(); ++floatNdx)
49 		{
50 			// Use custom epsilon because of the float->string conversion
51 			if (fabs(expectedFloats[floatNdx] - actualFloats[floatNdx]) > epsilon)
52 			{
53 				log << tcu::TestLog::Message << "Error: The actual and expected values not matching."
54 					<< " Expected: " << expectedFloats[floatNdx] << " Actual: " << actualFloats[floatNdx] << " Epsilon: " << epsilon << tcu::TestLog::EndMessage;
55 				return false;
56 			}
57 		}
58 	}
59 	return true;
60 }
61 }
62 
getComputeAsmShaderPreamble(const std::string & capabilities,const std::string & extensions,const std::string & exeModes,const std::string & extraEntryPoints,const std::string & extraEntryPointsArguments)63 std::string getComputeAsmShaderPreamble (const std::string& capabilities,
64 										 const std::string& extensions,
65 										 const std::string& exeModes,
66 										 const std::string& extraEntryPoints,
67 										 const std::string& extraEntryPointsArguments)
68 {
69 	return
70 		std::string("OpCapability Shader\n") +
71 		capabilities +
72 		extensions +
73 		"OpMemoryModel Logical GLSL450\n"
74 		"OpEntryPoint GLCompute %main \"main\" %id " + extraEntryPointsArguments + "\n" +
75 		extraEntryPoints +
76 		"OpExecutionMode %main LocalSize 1 1 1\n" +
77 		exeModes;
78 }
79 
getComputeAsmShaderPreambleWithoutLocalSize(void)80 const char* getComputeAsmShaderPreambleWithoutLocalSize (void)
81 {
82 	return
83 		"OpCapability Shader\n"
84 		"OpMemoryModel Logical GLSL450\n"
85 		"OpEntryPoint GLCompute %main \"main\" %id\n";
86 }
87 
getComputeAsmCommonTypes(std::string blockStorageClass)88 std::string getComputeAsmCommonTypes (std::string blockStorageClass)
89 {
90 	return std::string(
91 		"%bool      = OpTypeBool\n"
92 		"%void      = OpTypeVoid\n"
93 		"%voidf     = OpTypeFunction %void\n"
94 		"%u32       = OpTypeInt 32 0\n"
95 		"%i32       = OpTypeInt 32 1\n"
96 		"%f32       = OpTypeFloat 32\n"
97 		"%uvec3     = OpTypeVector %u32 3\n"
98 		"%fvec3     = OpTypeVector %f32 3\n"
99 		"%uvec3ptr  = OpTypePointer Input %uvec3\n") +
100 		"%i32ptr    = OpTypePointer " + blockStorageClass + " %i32\n"
101 		"%f32ptr    = OpTypePointer " + blockStorageClass + " %f32\n"
102 		"%i32arr    = OpTypeRuntimeArray %i32\n"
103 		"%f32arr    = OpTypeRuntimeArray %f32\n";
104 }
105 
getComputeAsmCommonInt64Types(void)106 const char* getComputeAsmCommonInt64Types (void)
107 {
108 	return
109 		"%i64       = OpTypeInt 64 1\n"
110 		"%i64ptr    = OpTypePointer Uniform %i64\n"
111 		"%i64arr    = OpTypeRuntimeArray %i64\n";
112 }
113 
getComputeAsmInputOutputBuffer(std::string blockStorageClass)114 std::string getComputeAsmInputOutputBuffer (std::string blockStorageClass)
115 {	// Uniform | StorageBuffer
116 	return std::string() +
117 		"%buf     = OpTypeStruct %f32arr\n"
118 		"%bufptr  = OpTypePointer " + blockStorageClass + " %buf\n"
119 		"%indata    = OpVariable %bufptr " + blockStorageClass + "\n"
120 		"%outdata   = OpVariable %bufptr " + blockStorageClass + "\n";
121 }
122 
getComputeAsmInputOutputBufferTraits(std::string blockStorageClass)123 std::string getComputeAsmInputOutputBufferTraits (std::string blockStorageClass)
124 {	// BufferBlock | Block
125 	return std::string() +
126 		"OpDecorate %buf " + blockStorageClass + "\n"
127 		"OpDecorate %indata DescriptorSet 0\n"
128 		"OpDecorate %indata Binding 0\n"
129 		"OpDecorate %outdata DescriptorSet 0\n"
130 		"OpDecorate %outdata Binding 1\n"
131 		"OpDecorate %f32arr ArrayStride 4\n"
132 		"OpMemberDecorate %buf 0 Offset 0\n";
133 }
134 
verifyOutput(const std::vector<Resource> &,const std::vector<AllocationSp> & outputAllocs,const std::vector<Resource> & expectedOutputs,tcu::TestLog & log)135 bool verifyOutput (const std::vector<Resource>&, const std::vector<AllocationSp>& outputAllocs, const std::vector<Resource>& expectedOutputs, tcu::TestLog& log)
136 {
137 	const float	epsilon	= 0.001f;
138 	return verifyOutputWithEpsilon(outputAllocs, expectedOutputs, log, epsilon);
139 }
140 
141 // Creates compute-shader assembly by specializing a boilerplate StringTemplate
142 // on fragments, which must (at least) map "testfun" to an OpFunction definition
143 // for %test_code that takes and returns a %v4f32.  Boilerplate IDs are prefixed
144 // with "BP_" to avoid collisions with fragments.
145 //
146 // It corresponds roughly to this GLSL:
147 //;
148 // void main (void) { test_func(vec4(gl_GlobalInvocationID)); }
makeComputeShaderAssembly(const std::map<std::string,std::string> & fragments)149 std::string makeComputeShaderAssembly(const std::map<std::string, std::string>& fragments)
150 {
151 	static const char computeShaderBoilerplate[] =
152 		"OpCapability Shader\n"
153 
154 		"${capability:opt}\n"
155 		"${extension:opt}\n"
156 
157 		"OpMemoryModel Logical GLSL450\n"
158 		"OpEntryPoint GLCompute %BP_main \"main\" %BP_id3u\n"
159 		"OpExecutionMode %BP_main LocalSize 1 1 1\n"
160 		"${execution_mode:opt}\n"
161 		"OpSource GLSL 430\n"
162 		"OpDecorate %BP_id3u BuiltIn GlobalInvocationId\n"
163 
164 		"${decoration:opt}\n"
165 
166 		SPIRV_ASSEMBLY_TYPES
167 		SPIRV_ASSEMBLY_CONSTANTS
168 		SPIRV_ASSEMBLY_ARRAYS
169 
170 		"%ip_v3u32  = OpTypePointer Input %v3u32\n"
171 		"%BP_id3u   = OpVariable %ip_v3u32 Input\n"
172 
173 		"${pre_main:opt}\n"
174 
175 		"%BP_main   = OpFunction %void None %voidf\n"
176 		"%BP_label  = OpLabel\n"
177 		"%BP_id3ul  = OpLoad %v3u32 %BP_id3u\n"
178 		"%BP_id4u   = OpCompositeConstruct %v4u32 %BP_id3ul %c_u32_0\n"
179 		"%BP_id4f   = OpConvertUToF %v4f32 %BP_id4u\n"
180 		"%BP_result = OpFunctionCall %v4f32 %test_code %BP_id4f\n"
181 		"             OpReturn\n"
182 		"             OpFunctionEnd\n"
183 		"\n"
184 		"${testfun}\n"
185 		"\n"
186 
187 		"%isUniqueIdZero = OpFunction %bool None %bool_function\n"
188 		"%BP_getId_label = OpLabel\n"
189 		"%BP_id_0_ptr = OpAccessChain %ip_u32 %BP_id3u %c_u32_0\n"
190 		"%BP_id_1_ptr = OpAccessChain %ip_u32 %BP_id3u %c_u32_1\n"
191 		"%BP_id_2_ptr = OpAccessChain %ip_u32 %BP_id3u %c_u32_2\n"
192 		"%BP_id_0_val = OpLoad %u32 %BP_id_0_ptr\n"
193 		"%BP_id_1_val = OpLoad %u32 %BP_id_1_ptr\n"
194 		"%BP_id_2_val = OpLoad %u32 %BP_id_2_ptr\n"
195 		"%BP_id_uni_0 = OpBitwiseOr %u32 %BP_id_0_val %BP_id_1_val\n"
196 		"  %BP_id_uni = OpBitwiseOr %u32 %BP_id_2_val %BP_id_uni_0\n"
197 		" %is_id_zero = OpIEqual %bool %BP_id_uni %c_u32_0\n"
198 		"               OpReturnValue %is_id_zero\n"
199 		"               OpFunctionEnd\n";
200 
201 	return tcu::StringTemplate(computeShaderBoilerplate).specialize(fragments);
202 }
203 
204 } // SpirVAssembly
205 } // vkt
206