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)63 std::string getComputeAsmShaderPreamble (const std::string& capabilities, const std::string& extensions, const std::string& exeModes)
64 {
65 return
66 std::string("OpCapability Shader\n") +
67 capabilities +
68 extensions +
69 "OpMemoryModel Logical GLSL450\n"
70 "OpEntryPoint GLCompute %main \"main\" %id\n"
71 "OpExecutionMode %main LocalSize 1 1 1\n"+
72 exeModes;
73 }
74
getComputeAsmShaderPreambleWithoutLocalSize(void)75 const char* getComputeAsmShaderPreambleWithoutLocalSize (void)
76 {
77 return
78 "OpCapability Shader\n"
79 "OpMemoryModel Logical GLSL450\n"
80 "OpEntryPoint GLCompute %main \"main\" %id\n";
81 }
82
getComputeAsmCommonTypes(std::string blockStorageClass)83 std::string getComputeAsmCommonTypes (std::string blockStorageClass)
84 {
85 return std::string(
86 "%bool = OpTypeBool\n"
87 "%void = OpTypeVoid\n"
88 "%voidf = OpTypeFunction %void\n"
89 "%u32 = OpTypeInt 32 0\n"
90 "%i32 = OpTypeInt 32 1\n"
91 "%f32 = OpTypeFloat 32\n"
92 "%uvec3 = OpTypeVector %u32 3\n"
93 "%fvec3 = OpTypeVector %f32 3\n"
94 "%uvec3ptr = OpTypePointer Input %uvec3\n") +
95 "%i32ptr = OpTypePointer " + blockStorageClass + " %i32\n"
96 "%f32ptr = OpTypePointer " + blockStorageClass + " %f32\n"
97 "%i32arr = OpTypeRuntimeArray %i32\n"
98 "%f32arr = OpTypeRuntimeArray %f32\n";
99 }
100
getComputeAsmCommonInt64Types(void)101 const char* getComputeAsmCommonInt64Types (void)
102 {
103 return
104 "%i64 = OpTypeInt 64 1\n"
105 "%i64ptr = OpTypePointer Uniform %i64\n"
106 "%i64arr = OpTypeRuntimeArray %i64\n";
107 }
108
getComputeAsmInputOutputBuffer(void)109 const char* getComputeAsmInputOutputBuffer (void)
110 {
111 return
112 "%buf = OpTypeStruct %f32arr\n"
113 "%bufptr = OpTypePointer Uniform %buf\n"
114 "%indata = OpVariable %bufptr Uniform\n"
115 "%outdata = OpVariable %bufptr Uniform\n";
116 }
117
getComputeAsmInputOutputBufferTraits(void)118 const char* getComputeAsmInputOutputBufferTraits (void)
119 {
120 return
121 "OpDecorate %buf BufferBlock\n"
122 "OpDecorate %indata DescriptorSet 0\n"
123 "OpDecorate %indata Binding 0\n"
124 "OpDecorate %outdata DescriptorSet 0\n"
125 "OpDecorate %outdata Binding 1\n"
126 "OpDecorate %f32arr ArrayStride 4\n"
127 "OpMemberDecorate %buf 0 Offset 0\n";
128 }
129
verifyOutput(const std::vector<Resource> &,const std::vector<AllocationSp> & outputAllocs,const std::vector<Resource> & expectedOutputs,tcu::TestLog & log)130 bool verifyOutput (const std::vector<Resource>&, const std::vector<AllocationSp>& outputAllocs, const std::vector<Resource>& expectedOutputs, tcu::TestLog& log)
131 {
132 const float epsilon = 0.001f;
133 return verifyOutputWithEpsilon(outputAllocs, expectedOutputs, log, epsilon);
134 }
135
136 // Creates compute-shader assembly by specializing a boilerplate StringTemplate
137 // on fragments, which must (at least) map "testfun" to an OpFunction definition
138 // for %test_code that takes and returns a %v4f32. Boilerplate IDs are prefixed
139 // with "BP_" to avoid collisions with fragments.
140 //
141 // It corresponds roughly to this GLSL:
142 //;
143 // void main (void) { test_func(vec4(gl_GlobalInvocationID)); }
makeComputeShaderAssembly(const std::map<std::string,std::string> & fragments)144 std::string makeComputeShaderAssembly(const std::map<std::string, std::string>& fragments)
145 {
146 static const char computeShaderBoilerplate[] =
147 "OpCapability Shader\n"
148
149 "${capability:opt}\n"
150 "${extension:opt}\n"
151
152 "OpMemoryModel Logical GLSL450\n"
153 "OpEntryPoint GLCompute %BP_main \"main\" %BP_id3u\n"
154 "OpExecutionMode %BP_main LocalSize 1 1 1\n"
155 "${execution_mode:opt}\n"
156 "OpSource GLSL 430\n"
157 "OpDecorate %BP_id3u BuiltIn GlobalInvocationId\n"
158
159 "${decoration:opt}\n"
160
161 SPIRV_ASSEMBLY_TYPES
162 SPIRV_ASSEMBLY_CONSTANTS
163 SPIRV_ASSEMBLY_ARRAYS
164
165 "%ip_v3u32 = OpTypePointer Input %v3u32\n"
166 "%BP_id3u = OpVariable %ip_v3u32 Input\n"
167
168 "${pre_main:opt}\n"
169
170 "%BP_main = OpFunction %void None %fun\n"
171 "%BP_label = OpLabel\n"
172 "%BP_id3ul = OpLoad %v3u32 %BP_id3u\n"
173 "%BP_id4u = OpCompositeConstruct %v4u32 %BP_id3ul %c_u32_0\n"
174 "%BP_id4f = OpConvertUToF %v4f32 %BP_id4u\n"
175 "%BP_result = OpFunctionCall %v4f32 %test_code %BP_id4f\n"
176 " OpReturn\n"
177 " OpFunctionEnd\n"
178 "\n"
179 "${testfun}\n"
180 "\n"
181
182 "%isUniqueIdZero = OpFunction %bool None %bool_function\n"
183 "%BP_getId_label = OpLabel\n"
184 "%BP_id_0_ptr = OpAccessChain %ip_u32 %BP_id3u %c_u32_0\n"
185 "%BP_id_1_ptr = OpAccessChain %ip_u32 %BP_id3u %c_u32_1\n"
186 "%BP_id_2_ptr = OpAccessChain %ip_u32 %BP_id3u %c_u32_2\n"
187 "%BP_id_0_val = OpLoad %u32 %BP_id_0_ptr\n"
188 "%BP_id_1_val = OpLoad %u32 %BP_id_1_ptr\n"
189 "%BP_id_2_val = OpLoad %u32 %BP_id_2_ptr\n"
190 "%BP_id_uni_0 = OpBitwiseOr %u32 %BP_id_0_val %BP_id_1_val\n"
191 " %BP_id_uni = OpBitwiseOr %u32 %BP_id_2_val %BP_id_uni_0\n"
192 " %is_id_zero = OpIEqual %bool %BP_id_uni %c_u32_0\n"
193 " OpReturnValue %is_id_zero\n"
194 " OpFunctionEnd\n";
195
196 return tcu::StringTemplate(computeShaderBoilerplate).specialize(fragments);
197 }
198
199 } // SpirVAssembly
200 } // vkt
201