1 #ifndef _VKTSPVASMGRAPHICSSHADERTESTUTIL_HPP
2 #define _VKTSPVASMGRAPHICSSHADERTESTUTIL_HPP
3 /*-------------------------------------------------------------------------
4 * Vulkan Conformance Tests
5 * ------------------------
7 * Copyright (c) 2017 Google Inc.
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 * \brief Graphics pipeline and helper functions for SPIR-V assembly tests
24 *//*--------------------------------------------------------------------*/
26 #include "tcuCommandLine.hpp"
27 #include "tcuRGBA.hpp"
29 #include "vkPrograms.hpp"
30 #include "vktSpvAsmComputeShaderTestUtil.hpp"
31 #include "vktSpvAsmUtils.hpp"
32 #include "vktTestCaseUtil.hpp"
34 #include "deRandom.hpp"
35 #include "deSharedPtr.hpp"
44 namespace SpirVAssembly
47 typedef vk::Unique<VkBuffer> BufferHandleUp;
48 typedef de::SharedPtr<BufferHandleUp> BufferHandleSp;
49 typedef vk::Unique<vk::VkShaderModule> ModuleHandleUp;
50 typedef de::SharedPtr<ModuleHandleUp> ModuleHandleSp;
51 typedef std::pair<std::string, vk::VkShaderStageFlagBits> EntryToStage;
52 typedef std::map<std::string, std::vector<EntryToStage> > ModuleMap;
53 typedef std::map<vk::VkShaderStageFlagBits, std::vector<deInt32> > StageToSpecConstantMap;
54 typedef std::pair<vk::VkDescriptorType, BufferSp> Resource;
61 NUMBERTYPE_END32, // Marks the end of 32-bit scalar types
67 typedef enum RoundingModeFlags_e
69 ROUNDINGMODE_RTE = 0x1, // Round to nearest even
70 ROUNDINGMODE_RTZ = 0x2, // Round to zero
73 typedef bool (*GraphicsVerifyIOFunc) (const std::vector<Resource>& inputs,
74 const std::vector<AllocationSp>& outputAllocations,
75 const std::vector<Resource>& expectedOutputs,
78 // Resources used by graphics-pipeline-based tests.
79 struct GraphicsResources
81 // Resources used as inputs.
82 std::vector<Resource> inputs;
83 // Resources used as outputs. The data supplied will be used as
84 // the expected outputs for the corresponding bindings by default.
85 // If other behaviors are needed, please provide a custom verifyIO.
86 std::vector<Resource> outputs;
87 // If null, a default verification will be performed by comparing the
88 // memory pointed to by outputAllocations and the contents of
89 // expectedOutputs. Otherwise the function pointed to by verifyIO will
90 // be called. If true is returned, then the test case is assumed to
91 // have passed, if false is returned, then the test case is assumed
93 GraphicsVerifyIOFunc verifyIO;
100 // Interface data type.
103 IFDataType (deUint32 numE, NumberType elementT)
105 , elementType (elementT)
107 DE_ASSERT(numE > 0 && numE < 5);
108 DE_ASSERT(elementT != NUMBERTYPE_END32);
111 IFDataType (const IFDataType& that)
112 : numElements (that.numElements)
113 , elementType (that.elementType)
116 deUint32 getElementNumBytes (void) const;
117 deUint32 getNumBytes (void) const { return numElements * getElementNumBytes(); }
119 vk::VkFormat getVkFormat (void) const;
121 tcu::TextureFormat getTextureFormat (void) const;
123 std::string str (void) const;
125 bool elementIs32bit (void) const { return elementType < NUMBERTYPE_END32; }
126 bool isVector (void) const { return numElements > 1; }
128 deUint32 numElements;
129 NumberType elementType;
132 typedef std::pair<IFDataType, BufferSp> Interface;
134 // Interface variables used by graphics-pipeline-based tests.
135 class GraphicsInterfaces
138 GraphicsInterfaces ()
139 : rndMode (static_cast<RoundingModeFlags>(0))
142 GraphicsInterfaces (const GraphicsInterfaces& that)
143 : inputs (that.inputs)
144 , outputs (that.outputs)
145 , rndMode (that.rndMode)
148 void setInputOutput (const Interface& input, const Interface& output)
152 inputs.push_back(input);
153 outputs.push_back(output);
156 const IFDataType& getInputType (void) const
158 DE_ASSERT(inputs.size() == 1);
159 return inputs.front().first;
162 const IFDataType& getOutputType (void) const
164 DE_ASSERT(outputs.size() == 1);
165 return outputs.front().first;
168 const BufferSp& getInputBuffer (void) const
170 DE_ASSERT(inputs.size() == 1);
171 return inputs.front().second;
174 const BufferSp& getOutputBuffer (void) const
176 DE_ASSERT(outputs.size() == 1);
177 return outputs.front().second;
180 bool empty (void) const
182 return inputs.size() == 0;
185 void setRoundingMode (RoundingModeFlags flag)
189 RoundingModeFlags getRoundingMode (void) const
194 // vector<Interface> acts as a null-able Interface here. Canonically we should use
195 // std::unique_ptr, but sadly we cannot leverage C++11 in dEQP. dEQP has its own
196 // de::UniquePtr, but still cumbersome to use in InstanceContext and do copies
197 // at various places.
198 // Public methods should make sure that there are less than two elements in both
199 // members and both members have the same number of elements.
200 std::vector<Interface> inputs;
201 std::vector<Interface> outputs;
202 RoundingModeFlags rndMode;
212 PushConstants (const PushConstants& that)
216 void setPushConstant (const BufferSp& pc)
222 bool empty (void) const
227 const BufferSp& getBuffer(void) const
229 DE_ASSERT(pcs.size() == 1);
234 // Right now we only support one field in the push constant block.
235 std::vector<BufferSp> pcs;
238 // Returns the corresponding buffer usage flag bit for the given descriptor type.
239 VkBufferUsageFlagBits getMatchingBufferUsageFlagBit(VkDescriptorType dType);
241 // Context for a specific test instantiation. For example, an instantiation
242 // may test colors yellow/magenta/cyan/mauve in a tesselation shader
243 // with an entry point named 'main_to_the_main'
244 struct InstanceContext
246 // Map of modules to what entry_points we care to use from those modules.
248 tcu::RGBA inputColors[4];
249 tcu::RGBA outputColors[4];
250 // Concrete SPIR-V code to test via boilerplate specialization.
251 std::map<std::string, std::string> testCodeFragments;
252 StageToSpecConstantMap specConstants;
253 bool hasTessellation;
254 vk::VkShaderStageFlagBits requiredStages;
255 std::vector<std::string> requiredDeviceExtensions;
256 std::vector<std::string> requiredDeviceFeatures;
257 ExtensionFeatures requestedExtensionFeatures;
258 PushConstants pushConstants;
259 // Possible resources used by the graphics pipeline.
260 // If it is not empty, a single descriptor set (number 0) will be allocated
261 // to point to all resources specified. Binding numbers are allocated in
262 // accord with the resources' order in the vector; outputs are allocated
264 GraphicsResources resources;
265 // Possible interface variables use by the graphics pipeline.
266 // If it is not empty, input/output variables will be set up for shader stages
267 // in the test. Both the input and output variable will take location #2 in the
268 // pipeline for all stages, except that the output variable in the fragment
269 // stage will take location #1.
270 GraphicsInterfaces interfaces;
271 qpTestResult failResult;
272 std::string failMessageTemplate; //!< ${reason} in the template will be replaced with a detailed failure message
274 InstanceContext (const tcu::RGBA (&inputs)[4],
275 const tcu::RGBA (&outputs)[4],
276 const std::map<std::string, std::string>& testCodeFragments_,
277 const StageToSpecConstantMap& specConstants_,
278 const PushConstants& pushConsants_,
279 const GraphicsResources& resources_,
280 const GraphicsInterfaces& interfaces_,
281 const std::vector<std::string>& extensions_,
282 const std::vector<std::string>& features_,
283 ExtensionFeatures extFeatures_);
285 InstanceContext (const InstanceContext& other);
287 std::string getSpecializedFailMessage (const std::string& failureReason);
290 // A description of a shader to be used for a single stage of the graphics pipeline.
293 // The module that contains this shader entrypoint.
294 std::string moduleName;
296 // The name of the entrypoint.
297 std::string entryName;
299 // Which shader stage this entry point represents.
300 vk::VkShaderStageFlagBits stage;
302 ShaderElement (const std::string& moduleName_, const std::string& entryPoint_, vk::VkShaderStageFlagBits shaderStage_);
305 template <typename T>
306 const std::string numberToString (T number)
308 std::stringstream ss;
313 // Performs a bitwise copy of source to the destination type Dest.
314 template <typename Dest, typename Src>
315 Dest bitwiseCast(Src source)
318 DE_STATIC_ASSERT(sizeof(source) == sizeof(dest));
319 deMemcpy(&dest, &source, sizeof(dest));
323 template<typename T> T randomScalar (de::Random& rnd, T minValue, T maxValue);
324 template<> inline float randomScalar (de::Random& rnd, float minValue, float maxValue) { return rnd.getFloat(minValue, maxValue); }
325 template<> inline deInt32 randomScalar (de::Random& rnd, deInt32 minValue, deInt32 maxValue) { return rnd.getInt(minValue, maxValue); }
328 void getDefaultColors (tcu::RGBA (&colors)[4]);
330 void getHalfColorsFullAlpha (tcu::RGBA (&colors)[4]);
332 void getInvertedDefaultColors (tcu::RGBA (&colors)[4]);
334 // Creates fragments that specialize into a simple pass-through shader (of any kind).
335 std::map<std::string, std::string> passthruFragments(void);
337 void createCombinedModule(vk::SourceCollections& dst, InstanceContext);
339 // This has two shaders of each stage. The first
340 // is a passthrough, the second inverts the color.
341 void createMultipleEntries(vk::SourceCollections& dst, InstanceContext);
343 // Turns a statically sized array of ShaderElements into an instance-context
344 // by setting up the mapping of modules to their contained shaders and stages.
345 // The inputs and expected outputs are given by inputColors and outputColors
347 InstanceContext createInstanceContext (const ShaderElement (&elements)[N],
348 const tcu::RGBA (&inputColors)[4],
349 const tcu::RGBA (&outputColors)[4],
350 const std::map<std::string, std::string>& testCodeFragments,
351 const StageToSpecConstantMap& specConstants,
352 const PushConstants& pushConstants,
353 const GraphicsResources& resources,
354 const GraphicsInterfaces& interfaces,
355 const std::vector<std::string>& extensions,
356 const std::vector<std::string>& features,
357 ExtensionFeatures extensionFeatures,
358 const qpTestResult failResult = QP_TEST_RESULT_FAIL,
359 const std::string& failMessageTemplate = std::string())
361 InstanceContext ctx (inputColors, outputColors, testCodeFragments, specConstants, pushConstants, resources, interfaces, extensions, features, extensionFeatures);
362 for (size_t i = 0; i < N; ++i)
364 ctx.moduleMap[elements[i].moduleName].push_back(std::make_pair(elements[i].entryName, elements[i].stage));
365 ctx.requiredStages = static_cast<VkShaderStageFlagBits>(ctx.requiredStages | elements[i].stage);
367 ctx.failResult = failResult;
368 if (!failMessageTemplate.empty())
369 ctx.failMessageTemplate = failMessageTemplate;
373 // The same as createInstanceContext above, without extensions, spec constants, and resources.
375 inline InstanceContext createInstanceContext (const ShaderElement (&elements)[N],
376 tcu::RGBA (&inputColors)[4],
377 const tcu::RGBA (&outputColors)[4],
378 const std::map<std::string, std::string>& testCodeFragments)
380 return createInstanceContext(elements, inputColors, outputColors, testCodeFragments,
381 StageToSpecConstantMap(), PushConstants(), GraphicsResources(),
382 GraphicsInterfaces(), std::vector<std::string>(), std::vector<std::string>(),
383 ExtensionFeatures());
386 // The same as createInstanceContext above, but with default colors.
388 InstanceContext createInstanceContext (const ShaderElement (&elements)[N],
389 const std::map<std::string, std::string>& testCodeFragments)
391 tcu::RGBA defaultColors[4];
392 getDefaultColors(defaultColors);
393 return createInstanceContext(elements, defaultColors, defaultColors, testCodeFragments);
397 void createTestsForAllStages (const std::string& name,
398 const tcu::RGBA (&inputColors)[4],
399 const tcu::RGBA (&outputColors)[4],
400 const std::map<std::string, std::string>& testCodeFragments,
401 const std::vector<deInt32>& specConstants,
402 const PushConstants& pushConstants,
403 const GraphicsResources& resources,
404 const GraphicsInterfaces& interfaces,
405 const std::vector<std::string>& extensions,
406 const std::vector<std::string>& features,
407 ExtensionFeatures extensionFeatures,
408 tcu::TestCaseGroup* tests,
409 const qpTestResult failResult = QP_TEST_RESULT_FAIL,
410 const std::string& failMessageTemplate = std::string());
412 inline void createTestsForAllStages (const std::string& name,
413 const tcu::RGBA (&inputColors)[4],
414 const tcu::RGBA (&outputColors)[4],
415 const std::map<std::string, std::string>& testCodeFragments,
416 tcu::TestCaseGroup* tests,
417 const qpTestResult failResult = QP_TEST_RESULT_FAIL,
418 const std::string& failMessageTemplate = std::string())
420 std::vector<deInt32> noSpecConstants;
421 PushConstants noPushConstants;
422 GraphicsResources noResources;
423 GraphicsInterfaces noInterfaces;
424 std::vector<std::string> noExtensions;
425 std::vector<std::string> noFeatures;
427 createTestsForAllStages(
428 name, inputColors, outputColors, testCodeFragments, noSpecConstants, noPushConstants,
429 noResources, noInterfaces, noExtensions, noFeatures, ExtensionFeatures(),
430 tests, failResult, failMessageTemplate);
433 inline void createTestsForAllStages (const std::string& name,
434 const tcu::RGBA (&inputColors)[4],
435 const tcu::RGBA (&outputColors)[4],
436 const std::map<std::string, std::string>& testCodeFragments,
437 const std::vector<deInt32>& specConstants,
438 tcu::TestCaseGroup* tests,
439 const qpTestResult failResult = QP_TEST_RESULT_FAIL,
440 const std::string& failMessageTemplate = std::string())
442 PushConstants noPushConstants;
443 GraphicsResources noResources;
444 GraphicsInterfaces noInterfaces;
445 std::vector<std::string> noExtensions;
446 std::vector<std::string> noFeatures;
448 createTestsForAllStages(
449 name, inputColors, outputColors, testCodeFragments, specConstants, noPushConstants,
450 noResources, noInterfaces, noExtensions, noFeatures, ExtensionFeatures(),
451 tests, failResult, failMessageTemplate);
454 inline void createTestsForAllStages (const std::string& name,
455 const tcu::RGBA (&inputColors)[4],
456 const tcu::RGBA (&outputColors)[4],
457 const std::map<std::string, std::string>& testCodeFragments,
458 const GraphicsResources& resources,
459 const std::vector<std::string>& extensions,
460 tcu::TestCaseGroup* tests,
461 ExtensionFeatures extensionFeatures = ExtensionFeatures(),
462 const qpTestResult failResult = QP_TEST_RESULT_FAIL,
463 const std::string& failMessageTemplate = std::string())
465 std::vector<deInt32> noSpecConstants;
466 PushConstants noPushConstants;
467 GraphicsInterfaces noInterfaces;
468 std::vector<std::string> noFeatures;
470 createTestsForAllStages(
471 name, inputColors, outputColors, testCodeFragments, noSpecConstants, noPushConstants,
472 resources, noInterfaces, extensions, noFeatures, extensionFeatures,
473 tests, failResult, failMessageTemplate);
476 inline void createTestsForAllStages (const std::string& name,
477 const tcu::RGBA (&inputColors)[4],
478 const tcu::RGBA (&outputColors)[4],
479 const std::map<std::string, std::string>& testCodeFragments,
480 const GraphicsInterfaces interfaces,
481 const std::vector<std::string>& extensions,
482 tcu::TestCaseGroup* tests,
483 ExtensionFeatures extensionFeatures = ExtensionFeatures(),
484 const qpTestResult failResult = QP_TEST_RESULT_FAIL,
485 const std::string& failMessageTemplate = std::string())
487 GraphicsResources noResources;
488 std::vector<deInt32> noSpecConstants;
489 std::vector<std::string> noFeatures;
490 PushConstants noPushConstants;
492 createTestsForAllStages(
493 name, inputColors, outputColors, testCodeFragments, noSpecConstants, noPushConstants,
494 noResources, interfaces, extensions, noFeatures, extensionFeatures,
495 tests, failResult, failMessageTemplate);
498 inline void createTestsForAllStages (const std::string& name,
499 const tcu::RGBA (&inputColors)[4],
500 const tcu::RGBA (&outputColors)[4],
501 const std::map<std::string, std::string>& testCodeFragments,
502 const PushConstants& pushConstants,
503 const GraphicsResources& resources,
504 const std::vector<std::string>& extensions,
505 tcu::TestCaseGroup* tests,
506 ExtensionFeatures extensionFeatures = ExtensionFeatures(),
507 const qpTestResult failResult = QP_TEST_RESULT_FAIL,
508 const std::string& failMessageTemplate = std::string())
510 std::vector<deInt32> noSpecConstants;
511 GraphicsInterfaces noInterfaces;
512 std::vector<std::string> noFeatures;
514 createTestsForAllStages(
515 name, inputColors, outputColors, testCodeFragments, noSpecConstants, pushConstants,
516 resources, noInterfaces, extensions, noFeatures, extensionFeatures,
517 tests, failResult, failMessageTemplate);
520 // Sets up and runs a Vulkan pipeline, then spot-checks the resulting image.
521 // Feeds the pipeline a set of colored triangles, which then must occur in the
522 // rendered image. The surface is cleared before executing the pipeline, so
523 // whatever the shaders draw can be directly spot-checked.
524 tcu::TestStatus runAndVerifyDefaultPipeline (Context& context, InstanceContext instance);
526 // Adds a new test to group using custom fragments for the tessellation-control
527 // stage and passthrough fragments for all other stages. Uses default colors
528 // for input and expected output.
529 void addTessCtrlTest(tcu::TestCaseGroup* group, const char* name, const std::map<std::string, std::string>& fragments);
531 // Given the original 32-bit float value, computes the corresponding 16-bit
532 // float value under the given rounding mode flags and compares with the
533 // returned 16-bit float value. Returns true if they are considered as equal.
535 // The following equivalence criteria are respected:
536 // * Positive and negative zeros are considered equivalent.
537 // * Denormalized floats are allowed to be flushed to zeros.
538 // * Different bit patterns of NaNs are allowed.
539 // * For the rest, require exactly the same bit pattern.
540 bool compare16BitFloat (float original, deUint16 returned, RoundingModeFlags flags, tcu::TestLog& log);
542 // Compare the returned 32-bit float against its expected value.
544 // The following equivalence criteria are respected:
545 // * Denormalized floats are allowed to be flushed to zeros.
546 // * Different bit patterns of NaNs/Infs are allowed.
547 // * For the rest, use C++ float equivalence check.
548 bool compare32BitFloat (float expected, float returned, tcu::TestLog& log);
553 #endif // _VKTSPVASMGRAPHICSSHADERTESTUTIL_HPP