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