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 = string(getComputeAsmShaderPreamble(capability, "", exeModes, "", "%indata %outdata")) +
57
58 "OpSource GLSL 430\n"
59 "OpName %main \"main\"\n"
60 "OpName %id \"gl_GlobalInvocationID\"\n"
61
62 "OpDecorate %id BuiltIn GlobalInvocationId\n"
63
64 + getComputeAsmInputOutputBufferTraits("Block") + getComputeAsmCommonTypes("StorageBuffer") +
65 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 uint32_t baseSeed =
89 deStringHash(testCaseName.c_str()) + static_cast<uint32_t>(ctx.getTestContext().getCommandLine().getBaseSeed());
90 de::Random rnd(baseSeed);
91 const int numElements = 64;
92 vector<float> inputFloats(numElements, 0);
93 vector<float> outputFloats(numElements, 0);
94 ComputeShaderSpec spec;
95
96 for (size_t ndx = 0; ndx < numElements; ++ndx)
97 inputFloats[ndx] = rnd.getFloat(1.0f, 100.0f);
98
99 for (size_t ndx = 0; ndx < numElements; ++ndx)
100 outputFloats[ndx] = -inputFloats[ndx];
101
102 // Shader source code can be retrieved to complete definition of ComputeShaderSpec, though it is not required at this stage
103 // getComputeSourceCode (spec.assembly);
104
105 spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
106 spec.outputs.push_back(BufferSp(new Float32Buffer(outputFloats)));
107
108 spec.numWorkGroups = tcu::IVec3(numElements, 1, 1);
109 spec.verifyIO = &verifyOutput;
110
111 return spec;
112 }
113
getFloatControlsProperty(Context & context,const int fpWideness,const std::string & featureName)114 VkBool32 getFloatControlsProperty(Context &context, const int fpWideness, const std::string &featureName)
115 {
116 VkPhysicalDeviceFloatControlsProperties floatControlsProperties;
117 deMemset(&floatControlsProperties, 0, sizeof(floatControlsProperties));
118 floatControlsProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES;
119
120 VkPhysicalDeviceProperties2 properties;
121 deMemset(&properties, 0, sizeof(properties));
122 properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
123 properties.pNext = &floatControlsProperties;
124
125 context.getInstanceInterface().getPhysicalDeviceProperties2(context.getPhysicalDevice(), &properties);
126
127 if (fpWideness == 16)
128 {
129 if (featureName == TEST_FEATURE_DENORM_PRESERVE)
130 return floatControlsProperties.shaderDenormPreserveFloat16;
131 if (featureName == TEST_FEATURE_DENORM_FLUSH_TO_ZERO)
132 return floatControlsProperties.shaderDenormFlushToZeroFloat16;
133 if (featureName == TEST_FEATURE_SIGNED_ZERO_INF_NAN_PRESERVE)
134 return floatControlsProperties.shaderSignedZeroInfNanPreserveFloat16;
135 if (featureName == TEST_FEATURE_ROUNDING_MODE_RTE)
136 return floatControlsProperties.shaderRoundingModeRTEFloat16;
137 if (featureName == TEST_FEATURE_ROUNDING_MODE_RTZ)
138 return floatControlsProperties.shaderRoundingModeRTZFloat16;
139 }
140
141 if (fpWideness == 32)
142 {
143 if (featureName == TEST_FEATURE_DENORM_PRESERVE)
144 return floatControlsProperties.shaderDenormPreserveFloat32;
145 if (featureName == TEST_FEATURE_DENORM_FLUSH_TO_ZERO)
146 return floatControlsProperties.shaderDenormFlushToZeroFloat32;
147 if (featureName == TEST_FEATURE_SIGNED_ZERO_INF_NAN_PRESERVE)
148 return floatControlsProperties.shaderSignedZeroInfNanPreserveFloat32;
149 if (featureName == TEST_FEATURE_ROUNDING_MODE_RTE)
150 return floatControlsProperties.shaderRoundingModeRTEFloat32;
151 if (featureName == TEST_FEATURE_ROUNDING_MODE_RTZ)
152 return floatControlsProperties.shaderRoundingModeRTZFloat32;
153 }
154
155 if (fpWideness == 64)
156 {
157 if (featureName == TEST_FEATURE_DENORM_PRESERVE)
158 return floatControlsProperties.shaderDenormPreserveFloat64;
159 if (featureName == TEST_FEATURE_DENORM_FLUSH_TO_ZERO)
160 return floatControlsProperties.shaderDenormFlushToZeroFloat64;
161 if (featureName == TEST_FEATURE_SIGNED_ZERO_INF_NAN_PRESERVE)
162 return floatControlsProperties.shaderSignedZeroInfNanPreserveFloat64;
163 if (featureName == TEST_FEATURE_ROUNDING_MODE_RTE)
164 return floatControlsProperties.shaderRoundingModeRTEFloat64;
165 if (featureName == TEST_FEATURE_ROUNDING_MODE_RTZ)
166 return floatControlsProperties.shaderRoundingModeRTZFloat64;
167 }
168
169 TCU_THROW(InternalError, "Unknown property requested");
170 }
171
172 class SpvAsmFloatControlsExtensionlessInstance : public ComputeShaderSpec, public SpvAsmComputeShaderInstance
173 {
174 public:
175 SpvAsmFloatControlsExtensionlessInstance(Context &ctx, const std::string &testCaseName);
176 };
177
SpvAsmFloatControlsExtensionlessInstance(Context & ctx,const std::string & testCaseName)178 SpvAsmFloatControlsExtensionlessInstance::SpvAsmFloatControlsExtensionlessInstance(Context &ctx,
179 const std::string &testCaseName)
180 : ComputeShaderSpec(getComputeShaderSpec(ctx, testCaseName))
181 , SpvAsmComputeShaderInstance(ctx, *this)
182 {
183 }
184
SpvAsmFloatControlsExtensionlessCase(tcu::TestContext & testCtx,const char * name,const char * featureName,const int fpWideness,const bool spirv14)185 SpvAsmFloatControlsExtensionlessCase::SpvAsmFloatControlsExtensionlessCase(tcu::TestContext &testCtx, const char *name,
186 const char *featureName,
187 const int fpWideness, const bool spirv14)
188 : TestCase(testCtx, name)
189 , m_featureName(featureName)
190 , m_fpWideness(fpWideness)
191 , m_spirv14(spirv14)
192 {
193 }
194
initPrograms(SourceCollections & programCollection) const195 void SpvAsmFloatControlsExtensionlessCase::initPrograms(SourceCollections &programCollection) const
196 {
197 const bool allowSpirv14 = true;
198 std::string comp;
199
200 getComputeSourceCode(comp, m_featureName, m_fpWideness);
201
202 programCollection.spirvAsmSources.add("compute")
203 << SpirVAsmBuildOptions(programCollection.usedVulkanVersion, SPIRV_VERSION_1_4, allowSpirv14) << comp;
204 }
205
checkSupport(Context & context) const206 void SpvAsmFloatControlsExtensionlessCase::checkSupport(Context &context) const
207 {
208 if (m_spirv14)
209 {
210 context.requireDeviceFunctionality("VK_KHR_spirv_1_4");
211 }
212 else
213 {
214 if (!context.contextSupports(vk::ApiVersion(0, 1, 2, 0)))
215 TCU_THROW(NotSupportedError, "Test requires Vulkan 1.2");
216 }
217
218 if (m_fpWideness == 16)
219 {
220 context.requireDeviceFunctionality("VK_KHR_shader_float16_int8");
221 const VkPhysicalDeviceShaderFloat16Int8Features &extensionFeatures = context.getShaderFloat16Int8Features();
222 if (!extensionFeatures.shaderFloat16)
223 TCU_THROW(NotSupportedError, "Floating point number of width 16 bit are not supported");
224 }
225
226 if (m_fpWideness == 64)
227 {
228 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SHADER_FLOAT64);
229 }
230
231 if (!getFloatControlsProperty(context, m_fpWideness, m_featureName))
232 TCU_THROW(NotSupportedError, "Property is not supported");
233 }
234
createInstance(Context & context) const235 TestInstance *SpvAsmFloatControlsExtensionlessCase::createInstance(Context &context) const
236 {
237 return new SpvAsmFloatControlsExtensionlessInstance(context, getName());
238 }
239
createFloatControlsExtensionlessGroup(tcu::TestContext & testCtx)240 tcu::TestCaseGroup *createFloatControlsExtensionlessGroup(tcu::TestContext &testCtx)
241 {
242 const char *spirVersions[] = {"spirv1p4", "vulkan1_2"};
243 const int floatingPointWideness[] = {16, 32, 64};
244 const struct FpFeatures
245 {
246 const char *testName;
247 const char *featureName;
248 } fpFeatures[] = {
249 {"denorm_preserve", TEST_FEATURE_DENORM_PRESERVE},
250 {"denorm_flush_to_zero", TEST_FEATURE_DENORM_FLUSH_TO_ZERO},
251 {"signed_zero_inf_nan_preserve", TEST_FEATURE_SIGNED_ZERO_INF_NAN_PRESERVE},
252 {"rounding_mode_rte", TEST_FEATURE_ROUNDING_MODE_RTE},
253 {"rounding_mode_rtz", TEST_FEATURE_ROUNDING_MODE_RTZ},
254 };
255 // Tests float controls without extension
256 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "float_controls_extensionless"));
257
258 for (int spirVersionsNdx = 0; spirVersionsNdx < DE_LENGTH_OF_ARRAY(spirVersions); ++spirVersionsNdx)
259 {
260 const bool spirv14 = (spirVersionsNdx == 0);
261 de::MovePtr<tcu::TestCaseGroup> spirVersionGroup(
262 new tcu::TestCaseGroup(testCtx, spirVersions[spirVersionsNdx]));
263
264 for (int fpWidenessNdx = 0; fpWidenessNdx < DE_LENGTH_OF_ARRAY(floatingPointWideness); ++fpWidenessNdx)
265 for (int execModeNdx = 0; execModeNdx < DE_LENGTH_OF_ARRAY(fpFeatures); ++execModeNdx)
266 {
267 const int fpWideness = floatingPointWideness[fpWidenessNdx];
268 const std::string testName = fpFeatures[execModeNdx].testName;
269 const char *featureName = fpFeatures[execModeNdx].featureName;
270 const std::string fullTestName = "fp" + de::toString(fpWideness) + "_" + testName;
271
272 spirVersionGroup->addChild(new SpvAsmFloatControlsExtensionlessCase(testCtx, fullTestName.c_str(),
273 featureName, fpWideness, spirv14));
274 }
275
276 group->addChild(spirVersionGroup.release());
277 }
278
279 return group.release();
280 }
281
282 } // namespace SpirVAssembly
283 } // namespace vkt
284