1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2019 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 Float Control SPIR-V tokens test
22 *//*--------------------------------------------------------------------*/
23
24 #include "vkApiVersion.hpp"
25
26 #include "vktSpvAsmFloatControlsExtensionlessTests.hpp"
27 #include "vktTestCase.hpp"
28 #include "vktSpvAsmComputeShaderCase.hpp"
29
30 #include "deRandom.hpp"
31 #include "deStringUtil.hpp"
32 #include "tcuCommandLine.hpp"
33 #include "vkQueryUtil.hpp"
34
35 namespace vkt
36 {
37 namespace SpirVAssembly
38 {
39
40 static const char* TEST_FEATURE_DENORM_PRESERVE = "DenormPreserve";
41 static const char* TEST_FEATURE_DENORM_FLUSH_TO_ZERO = "DenormFlushToZero";
42 static const char* TEST_FEATURE_SIGNED_ZERO_INF_NAN_PRESERVE = "SignedZeroInfNanPreserve";
43 static const char* TEST_FEATURE_ROUNDING_MODE_RTE = "RoundingModeRTE";
44 static const char* TEST_FEATURE_ROUNDING_MODE_RTZ = "RoundingModeRTZ";
45
46 using namespace vk;
47 using std::map;
48 using std::string;
49 using std::vector;
50
getComputeSourceCode(std::string & computeSourceCode,const std::string & featureName,const int fpWideness)51 static void getComputeSourceCode (std::string& computeSourceCode, const std::string& featureName, const int fpWideness)
52 {
53 const std::string capability = "OpCapability " + featureName + "\n";
54 const std::string exeModes = "OpExecutionMode %main " + featureName + " " + de::toString(fpWideness) + "\n";
55
56 computeSourceCode =
57 string(getComputeAsmShaderPreamble(capability, "", exeModes, "", "%indata %outdata")) +
58
59 "OpSource GLSL 430\n"
60 "OpName %main \"main\"\n"
61 "OpName %id \"gl_GlobalInvocationID\"\n"
62
63 "OpDecorate %id BuiltIn GlobalInvocationId\n"
64
65 + getComputeAsmInputOutputBufferTraits("Block") + getComputeAsmCommonTypes("StorageBuffer") + getComputeAsmInputOutputBuffer("StorageBuffer") +
66
67 "%id = OpVariable %uvec3ptr Input\n"
68 "%zero = OpConstant %i32 0\n"
69
70 "%main = OpFunction %void None %voidf\n"
71 "%label = OpLabel\n"
72 "%idval = OpLoad %uvec3 %id\n"
73 "%x = OpCompositeExtract %u32 %idval 0\n"
74
75 " OpNop\n" // Inside a function body
76
77 "%inloc = OpAccessChain %f32ptr %indata %zero %x\n"
78 "%inval = OpLoad %f32 %inloc\n"
79 "%neg = OpFNegate %f32 %inval\n"
80 "%outloc = OpAccessChain %f32ptr %outdata %zero %x\n"
81 " OpStore %outloc %neg\n"
82 " OpReturn\n"
83 " OpFunctionEnd\n";
84 }
85
getComputeShaderSpec(Context & ctx,const std::string & testCaseName)86 static ComputeShaderSpec getComputeShaderSpec (Context& ctx, const std::string& testCaseName)
87 {
88 const deUint32 baseSeed = deStringHash(testCaseName.c_str()) + static_cast<deUint32>(ctx.getTestContext().getCommandLine().getBaseSeed());
89 de::Random rnd (baseSeed);
90 const int numElements = 64;
91 vector<float> inputFloats (numElements, 0);
92 vector<float> outputFloats (numElements, 0);
93 ComputeShaderSpec spec;
94
95 for (size_t ndx = 0; ndx < numElements; ++ndx)
96 inputFloats[ndx] = rnd.getFloat(1.0f, 100.0f);
97
98 for (size_t ndx = 0; ndx < numElements; ++ndx)
99 outputFloats[ndx] = -inputFloats[ndx];
100
101 // Shader source code can be retrieved to complete definition of ComputeShaderSpec, though it is not required at this stage
102 // getComputeSourceCode (spec.assembly);
103
104 spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
105 spec.outputs.push_back(BufferSp(new Float32Buffer(outputFloats)));
106
107 spec.numWorkGroups = tcu::IVec3(numElements, 1, 1);
108 spec.verifyIO = &verifyOutput;
109
110 return spec;
111 }
112
getFloatControlsProperty(Context & context,const int fpWideness,const std::string & featureName)113 VkBool32 getFloatControlsProperty(Context& context, const int fpWideness, const std::string& featureName)
114 {
115 VkPhysicalDeviceFloatControlsProperties floatControlsProperties;
116 deMemset(&floatControlsProperties, 0, sizeof(floatControlsProperties));
117 floatControlsProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES;
118
119 VkPhysicalDeviceProperties2 properties;
120 deMemset(&properties, 0, sizeof(properties));
121 properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
122 properties.pNext = &floatControlsProperties;
123
124 context.getInstanceInterface().getPhysicalDeviceProperties2(context.getPhysicalDevice(), &properties);
125
126 if (fpWideness == 16)
127 {
128 if (featureName == TEST_FEATURE_DENORM_PRESERVE ) return floatControlsProperties.shaderDenormPreserveFloat16;
129 if (featureName == TEST_FEATURE_DENORM_FLUSH_TO_ZERO ) return floatControlsProperties.shaderDenormFlushToZeroFloat16;
130 if (featureName == TEST_FEATURE_SIGNED_ZERO_INF_NAN_PRESERVE) return floatControlsProperties.shaderSignedZeroInfNanPreserveFloat16;
131 if (featureName == TEST_FEATURE_ROUNDING_MODE_RTE ) return floatControlsProperties.shaderRoundingModeRTEFloat16;
132 if (featureName == TEST_FEATURE_ROUNDING_MODE_RTZ ) return floatControlsProperties.shaderRoundingModeRTZFloat16;
133 }
134
135 if (fpWideness == 32)
136 {
137 if (featureName == TEST_FEATURE_DENORM_PRESERVE ) return floatControlsProperties.shaderDenormPreserveFloat32;
138 if (featureName == TEST_FEATURE_DENORM_FLUSH_TO_ZERO ) return floatControlsProperties.shaderDenormFlushToZeroFloat32;
139 if (featureName == TEST_FEATURE_SIGNED_ZERO_INF_NAN_PRESERVE) return floatControlsProperties.shaderSignedZeroInfNanPreserveFloat32;
140 if (featureName == TEST_FEATURE_ROUNDING_MODE_RTE ) return floatControlsProperties.shaderRoundingModeRTEFloat32;
141 if (featureName == TEST_FEATURE_ROUNDING_MODE_RTZ ) return floatControlsProperties.shaderRoundingModeRTZFloat32;
142 }
143
144 if (fpWideness == 64)
145 {
146 if (featureName == TEST_FEATURE_DENORM_PRESERVE ) return floatControlsProperties.shaderDenormPreserveFloat64;
147 if (featureName == TEST_FEATURE_DENORM_FLUSH_TO_ZERO ) return floatControlsProperties.shaderDenormFlushToZeroFloat64;
148 if (featureName == TEST_FEATURE_SIGNED_ZERO_INF_NAN_PRESERVE) return floatControlsProperties.shaderSignedZeroInfNanPreserveFloat64;
149 if (featureName == TEST_FEATURE_ROUNDING_MODE_RTE ) return floatControlsProperties.shaderRoundingModeRTEFloat64;
150 if (featureName == TEST_FEATURE_ROUNDING_MODE_RTZ ) return floatControlsProperties.shaderRoundingModeRTZFloat64;
151 }
152
153 TCU_THROW(InternalError, "Unknown property requested");
154 }
155
156 class SpvAsmFloatControlsExtensionlessInstance : public ComputeShaderSpec, public SpvAsmComputeShaderInstance
157 {
158 public:
159 SpvAsmFloatControlsExtensionlessInstance (Context& ctx, const std::string& testCaseName);
160 };
161
SpvAsmFloatControlsExtensionlessInstance(Context & ctx,const std::string & testCaseName)162 SpvAsmFloatControlsExtensionlessInstance::SpvAsmFloatControlsExtensionlessInstance (Context& ctx, const std::string& testCaseName)
163 : ComputeShaderSpec(getComputeShaderSpec(ctx, testCaseName))
164 , SpvAsmComputeShaderInstance(ctx, *this)
165 {
166 }
167
SpvAsmFloatControlsExtensionlessCase(tcu::TestContext & testCtx,const char * name,const char * description,const char * featureName,const int fpWideness,const bool spirv14)168 SpvAsmFloatControlsExtensionlessCase::SpvAsmFloatControlsExtensionlessCase (tcu::TestContext& testCtx, const char* name, const char* description, const char* featureName, const int fpWideness, const bool spirv14)
169 : TestCase (testCtx, name, description)
170 , m_featureName (featureName)
171 , m_fpWideness (fpWideness)
172 , m_spirv14 (spirv14)
173 {
174 }
175
initPrograms(SourceCollections & programCollection) const176 void SpvAsmFloatControlsExtensionlessCase::initPrograms (SourceCollections& programCollection) const
177 {
178 const bool allowSpirv14 = true;
179 std::string comp;
180
181 getComputeSourceCode(comp, m_featureName, m_fpWideness);
182
183 programCollection.spirvAsmSources.add("compute") << SpirVAsmBuildOptions(programCollection.usedVulkanVersion, SPIRV_VERSION_1_4, allowSpirv14) << comp;
184 }
185
checkSupport(Context & context) const186 void SpvAsmFloatControlsExtensionlessCase::checkSupport (Context& context) const
187 {
188 if (m_spirv14)
189 {
190 context.requireDeviceFunctionality("VK_KHR_spirv_1_4");
191 }
192 else
193 {
194 if (!context.contextSupports(vk::ApiVersion(0, 1, 2, 0)))
195 TCU_THROW(NotSupportedError, "Test requires Vulkan 1.2");
196 }
197
198 if (m_fpWideness == 16)
199 {
200 context.requireDeviceFunctionality("VK_KHR_shader_float16_int8");
201 const VkPhysicalDeviceShaderFloat16Int8Features& extensionFeatures = context.getShaderFloat16Int8Features();
202 if (!extensionFeatures.shaderFloat16)
203 TCU_THROW(NotSupportedError, "Floating point number of width 16 bit are not supported");
204 }
205
206 if (m_fpWideness == 64)
207 {
208 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SHADER_FLOAT64);
209 }
210
211 if (!getFloatControlsProperty(context, m_fpWideness, m_featureName))
212 TCU_THROW(NotSupportedError, "Property is not supported");
213 }
214
createInstance(Context & context) const215 TestInstance* SpvAsmFloatControlsExtensionlessCase::createInstance (Context& context) const
216 {
217 return new SpvAsmFloatControlsExtensionlessInstance(context, getName());
218 }
219
createFloatControlsExtensionlessGroup(tcu::TestContext & testCtx)220 tcu::TestCaseGroup* createFloatControlsExtensionlessGroup (tcu::TestContext& testCtx)
221 {
222 const char* spirVersions[] = { "spirv1p4", "vulkan1_2" };
223 const int floatingPointWideness[] = { 16, 32, 64 };
224 const struct FpFeatures
225 {
226 const char* testName;
227 const char* featureName;
228 }
229 fpFeatures[] =
230 {
231 { "denorm_preserve", TEST_FEATURE_DENORM_PRESERVE },
232 { "denorm_flush_to_zero", TEST_FEATURE_DENORM_FLUSH_TO_ZERO },
233 { "signed_zero_inf_nan_preserve", TEST_FEATURE_SIGNED_ZERO_INF_NAN_PRESERVE },
234 { "rounding_mode_rte", TEST_FEATURE_ROUNDING_MODE_RTE },
235 { "rounding_mode_rtz", TEST_FEATURE_ROUNDING_MODE_RTZ },
236 };
237 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "float_controls_extensionless", "Tests float controls without extension"));
238
239 for (int spirVersionsNdx = 0; spirVersionsNdx < DE_LENGTH_OF_ARRAY(spirVersions); ++spirVersionsNdx)
240 {
241 const bool spirv14 = (spirVersionsNdx == 0);
242 de::MovePtr<tcu::TestCaseGroup> spirVersionGroup (new tcu::TestCaseGroup(testCtx, spirVersions[spirVersionsNdx], ""));
243
244 for (int fpWidenessNdx = 0; fpWidenessNdx < DE_LENGTH_OF_ARRAY(floatingPointWideness); ++fpWidenessNdx)
245 for (int execModeNdx = 0; execModeNdx < DE_LENGTH_OF_ARRAY(fpFeatures); ++execModeNdx)
246 {
247 const int fpWideness = floatingPointWideness[fpWidenessNdx];
248 const std::string testName = fpFeatures[execModeNdx].testName;
249 const char* featureName = fpFeatures[execModeNdx].featureName;
250 const std::string fullTestName = "fp" + de::toString(fpWideness) + "_" + testName;
251
252 spirVersionGroup->addChild(new SpvAsmFloatControlsExtensionlessCase(testCtx, fullTestName.c_str(), "", featureName, fpWideness, spirv14));
253 }
254
255 group->addChild(spirVersionGroup.release());
256 }
257
258 return group.release();
259 }
260
261
262 } // SpirVAssembly
263 } // vkt
264