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