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 vk::Unique<VkImage> ImageHandleUp;
49 typedef vk::Unique<VkImageView> ImageViewHandleUp;
50 typedef vk::Unique<VkSampler> SamplerHandleUp;
51 typedef de::SharedPtr<BufferHandleUp> BufferHandleSp;
52 typedef de::SharedPtr<ImageHandleUp> ImageHandleSp;
53 typedef de::SharedPtr<ImageViewHandleUp> ImageViewHandleSp;
54 typedef de::SharedPtr<SamplerHandleUp> SamplerHandleSp;
55 typedef vk::Unique<vk::VkShaderModule> ModuleHandleUp;
56 typedef de::SharedPtr<ModuleHandleUp> ModuleHandleSp;
57 typedef std::pair<std::string, vk::VkShaderStageFlagBits> EntryToStage;
58 typedef std::map<std::string, std::vector<EntryToStage> > ModuleMap;
59 typedef std::map<vk::VkShaderStageFlagBits, std::vector<deInt32> > StageToSpecConstantMap;
60 typedef std::pair<vk::VkDescriptorType, BufferSp> Resource;
67 NUMBERTYPE_END32, // Marks the end of 32-bit scalar types
73 typedef enum RoundingModeFlags_e
75 ROUNDINGMODE_RTE = 0x1, // Round to nearest even
76 ROUNDINGMODE_RTZ = 0x2, // Round to zero
79 typedef bool (*GraphicsVerifyIOFunc) (const std::vector<Resource>& inputs,
80 const std::vector<AllocationSp>& outputAllocations,
81 const std::vector<Resource>& expectedOutputs,
84 typedef bool (*GraphicsVerifyBinaryFunc) (const ProgramBinary& binary);
86 // Resources used by graphics-pipeline-based tests.
87 struct GraphicsResources
89 // Resources used as inputs.
90 std::vector<Resource> inputs;
91 // Resources used as outputs. The data supplied will be used as
92 // the expected outputs for the corresponding bindings by default.
93 // If other behaviors are needed, please provide a custom verifyIO.
94 std::vector<Resource> outputs;
95 // If null, a default verification will be performed by comparing the
96 // memory pointed to by outputAllocations and the contents of
97 // expectedOutputs. Otherwise the function pointed to by verifyIO will
98 // be called. If true is returned, then the test case is assumed to
99 // have passed, if false is returned, then the test case is assumed
101 GraphicsVerifyIOFunc verifyIO;
102 GraphicsVerifyBinaryFunc verifyBinary;
103 SpirvVersion spirvVersion;
107 , verifyBinary (DE_NULL)
108 , spirvVersion (SPIRV_VERSION_1_0)
112 // Interface data type.
115 IFDataType (deUint32 numE, NumberType elementT)
117 , elementType (elementT)
119 DE_ASSERT(numE > 0 && numE < 5);
120 DE_ASSERT(elementT != NUMBERTYPE_END32);
123 IFDataType (const IFDataType& that)
124 : numElements (that.numElements)
125 , elementType (that.elementType)
128 deUint32 getElementNumBytes (void) const;
129 deUint32 getNumBytes (void) const { return numElements * getElementNumBytes(); }
131 vk::VkFormat getVkFormat (void) const;
133 tcu::TextureFormat getTextureFormat (void) const;
135 std::string str (void) const;
137 bool elementIs32bit (void) const { return elementType < NUMBERTYPE_END32; }
138 bool isVector (void) const { return numElements > 1; }
140 deUint32 numElements;
141 NumberType elementType;
144 typedef std::pair<IFDataType, BufferSp> Interface;
146 // Interface variables used by graphics-pipeline-based tests.
147 class GraphicsInterfaces
150 GraphicsInterfaces ()
151 : rndMode (static_cast<RoundingModeFlags>(0))
154 GraphicsInterfaces (const GraphicsInterfaces& that)
155 : inputs (that.inputs)
156 , outputs (that.outputs)
157 , rndMode (that.rndMode)
160 void setInputOutput (const Interface& input, const Interface& output)
164 inputs.push_back(input);
165 outputs.push_back(output);
168 const IFDataType& getInputType (void) const
170 DE_ASSERT(inputs.size() == 1);
171 return inputs.front().first;
174 const IFDataType& getOutputType (void) const
176 DE_ASSERT(outputs.size() == 1);
177 return outputs.front().first;
180 const BufferSp& getInputBuffer (void) const
182 DE_ASSERT(inputs.size() == 1);
183 return inputs.front().second;
186 const BufferSp& getOutputBuffer (void) const
188 DE_ASSERT(outputs.size() == 1);
189 return outputs.front().second;
192 bool empty (void) const
194 return inputs.size() == 0;
197 void setRoundingMode (RoundingModeFlags flag)
201 RoundingModeFlags getRoundingMode (void) const
206 // vector<Interface> acts as a null-able Interface here. Canonically we should use
207 // std::unique_ptr, but sadly we cannot leverage C++11 in dEQP. dEQP has its own
208 // de::UniquePtr, but still cumbersome to use in InstanceContext and do copies
209 // at various places.
210 // Public methods should make sure that there are less than two elements in both
211 // members and both members have the same number of elements.
212 std::vector<Interface> inputs;
213 std::vector<Interface> outputs;
214 RoundingModeFlags rndMode;
224 PushConstants (const PushConstants& that)
228 void setPushConstant (const BufferSp& pc)
234 bool empty (void) const
239 const BufferSp& getBuffer(void) const
241 DE_ASSERT(pcs.size() == 1);
246 // Right now we only support one field in the push constant block.
247 std::vector<BufferSp> pcs;
250 // Returns the corresponding buffer usage flag bit for the given descriptor type.
251 VkBufferUsageFlagBits getMatchingBufferUsageFlagBit(VkDescriptorType dType);
253 // Context for a specific test instantiation. For example, an instantiation
254 // may test colors yellow/magenta/cyan/mauve in a tesselation shader
255 // with an entry point named 'main_to_the_main'
256 struct InstanceContext
258 // Map of modules to what entry_points we care to use from those modules.
260 tcu::RGBA inputColors[4];
261 tcu::RGBA outputColors[4];
262 // Concrete SPIR-V code to test via boilerplate specialization.
263 std::map<std::string, std::string> testCodeFragments;
264 StageToSpecConstantMap specConstants;
265 bool hasTessellation;
266 vk::VkShaderStageFlagBits requiredStages;
267 std::vector<std::string> requiredDeviceExtensions;
268 std::vector<std::string> requiredDeviceFeatures;
269 VulkanFeatures requestedFeatures;
270 PushConstants pushConstants;
271 // Specifies the (one or more) stages that use a customized shader code.
272 VkShaderStageFlags customizedStages;
273 // Possible resources used by the graphics pipeline.
274 // If it is not empty, a single descriptor set (number 0) will be allocated
275 // to point to all resources specified. Binding numbers are allocated in
276 // accord with the resources' order in the vector; outputs are allocated
278 GraphicsResources resources;
279 // Possible interface variables use by the graphics pipeline.
280 // If it is not empty, input/output variables will be set up for shader stages
281 // in the test. Both the input and output variable will take location #2 in the
282 // pipeline for all stages, except that the output variable in the fragment
283 // stage will take location #1.
284 GraphicsInterfaces interfaces;
285 qpTestResult failResult;
286 std::string failMessageTemplate; //!< ${reason} in the template will be replaced with a detailed failure message
288 InstanceContext (const tcu::RGBA (&inputs)[4],
289 const tcu::RGBA (&outputs)[4],
290 const std::map<std::string, std::string>& testCodeFragments_,
291 const StageToSpecConstantMap& specConstants_,
292 const PushConstants& pushConsants_,
293 const GraphicsResources& resources_,
294 const GraphicsInterfaces& interfaces_,
295 const std::vector<std::string>& extensions_,
296 const std::vector<std::string>& features_,
297 VulkanFeatures vulkanFeatures_,
298 VkShaderStageFlags customizedStages_);
300 InstanceContext (const InstanceContext& other);
302 std::string getSpecializedFailMessage (const std::string& failureReason);
305 // A description of a shader to be used for a single stage of the graphics pipeline.
308 // The module that contains this shader entrypoint.
309 std::string moduleName;
311 // The name of the entrypoint.
312 std::string entryName;
314 // Which shader stage this entry point represents.
315 vk::VkShaderStageFlagBits stage;
317 ShaderElement (const std::string& moduleName_, const std::string& entryPoint_, vk::VkShaderStageFlagBits shaderStage_);
320 template <typename T>
321 const std::string numberToString (T number)
323 std::stringstream ss;
328 // Performs a bitwise copy of source to the destination type Dest.
329 template <typename Dest, typename Src>
330 Dest bitwiseCast(Src source)
333 DE_STATIC_ASSERT(sizeof(source) == sizeof(dest));
334 deMemcpy(&dest, &source, sizeof(dest));
338 template<typename T> T randomScalar (de::Random& rnd, T minValue, T maxValue);
339 template<> inline float randomScalar (de::Random& rnd, float minValue, float maxValue) { return rnd.getFloat(minValue, maxValue); }
340 template<> inline deInt32 randomScalar (de::Random& rnd, deInt32 minValue, deInt32 maxValue) { return rnd.getInt(minValue, maxValue); }
343 void getDefaultColors (tcu::RGBA (&colors)[4]);
345 void getHalfColorsFullAlpha (tcu::RGBA (&colors)[4]);
347 void getInvertedDefaultColors (tcu::RGBA (&colors)[4]);
349 // Creates fragments that specialize into a simple pass-through shader (of any kind).
350 std::map<std::string, std::string> passthruFragments(void);
352 void createCombinedModule(vk::SourceCollections& dst, InstanceContext);
354 // This has two shaders of each stage. The first
355 // is a passthrough, the second inverts the color.
356 void createMultipleEntries(vk::SourceCollections& dst, InstanceContext);
358 // Turns a statically sized array of ShaderElements into an instance-context
359 // by setting up the mapping of modules to their contained shaders and stages.
360 // The inputs and expected outputs are given by inputColors and outputColors
362 InstanceContext createInstanceContext (const ShaderElement (&elements)[N],
363 const tcu::RGBA (&inputColors)[4],
364 const tcu::RGBA (&outputColors)[4],
365 const std::map<std::string, std::string>& testCodeFragments,
366 const StageToSpecConstantMap& specConstants,
367 const PushConstants& pushConstants,
368 const GraphicsResources& resources,
369 const GraphicsInterfaces& interfaces,
370 const std::vector<std::string>& extensions,
371 const std::vector<std::string>& features,
372 VulkanFeatures vulkanFeatures,
373 VkShaderStageFlags customizedStages,
374 const qpTestResult failResult = QP_TEST_RESULT_FAIL,
375 const std::string& failMessageTemplate = std::string())
377 InstanceContext ctx (inputColors, outputColors, testCodeFragments, specConstants, pushConstants, resources, interfaces, extensions, features, vulkanFeatures, customizedStages);
378 for (size_t i = 0; i < N; ++i)
380 ctx.moduleMap[elements[i].moduleName].push_back(std::make_pair(elements[i].entryName, elements[i].stage));
381 ctx.requiredStages = static_cast<VkShaderStageFlagBits>(ctx.requiredStages | elements[i].stage);
383 ctx.failResult = failResult;
384 if (!failMessageTemplate.empty())
385 ctx.failMessageTemplate = failMessageTemplate;
389 // The same as createInstanceContext above, without extensions, spec constants, and resources.
391 inline InstanceContext createInstanceContext (const ShaderElement (&elements)[N],
392 tcu::RGBA (&inputColors)[4],
393 const tcu::RGBA (&outputColors)[4],
394 const std::map<std::string, std::string>& testCodeFragments)
396 return createInstanceContext(elements, inputColors, outputColors, testCodeFragments,
397 StageToSpecConstantMap(), PushConstants(), GraphicsResources(),
398 GraphicsInterfaces(), std::vector<std::string>(), std::vector<std::string>(),
399 VulkanFeatures(), vk::VK_SHADER_STAGE_ALL);
402 // The same as createInstanceContext above, but with default colors.
404 InstanceContext createInstanceContext (const ShaderElement (&elements)[N],
405 const std::map<std::string, std::string>& testCodeFragments)
407 tcu::RGBA defaultColors[4];
408 getDefaultColors(defaultColors);
409 return createInstanceContext(elements, defaultColors, defaultColors, testCodeFragments);
412 void addShaderCodeCustomVertex(vk::SourceCollections& dst, InstanceContext& context, const SpirVAsmBuildOptions* spirVAsmBuildOptions);
413 void addShaderCodeCustomTessControl(vk::SourceCollections& dst, InstanceContext& context, const SpirVAsmBuildOptions* spirVAsmBuildOptions);
414 void addShaderCodeCustomTessEval(vk::SourceCollections& dst, InstanceContext& context, const SpirVAsmBuildOptions* spirVAsmBuildOptions);
415 void addShaderCodeCustomGeometry(vk::SourceCollections& dst, InstanceContext& context, const SpirVAsmBuildOptions* spirVAsmBuildOptions);
416 void addShaderCodeCustomFragment(vk::SourceCollections& dst, InstanceContext& context, const SpirVAsmBuildOptions* spirVAsmBuildOptions);
418 void createTestForStage(vk::VkShaderStageFlagBits stage,
419 const std::string& name,
420 const tcu::RGBA (&inputColors)[4],
421 const tcu::RGBA (&outputColors)[4],
422 const std::map<std::string, std::string>& testCodeFragments,
423 const std::vector<deInt32>& specConstants,
424 const PushConstants& pushConstants,
425 const GraphicsResources& resources,
426 const GraphicsInterfaces& interfaces,
427 const std::vector<std::string>& extensions,
428 const std::vector<std::string>& features,
429 VulkanFeatures vulkanFeatures,
430 tcu::TestCaseGroup* tests,
431 const qpTestResult failResult = QP_TEST_RESULT_FAIL,
432 const std::string& failMessageTemplate = std::string());
434 void createTestsForAllStages (const std::string& name,
435 const tcu::RGBA (&inputColors)[4],
436 const tcu::RGBA (&outputColors)[4],
437 const std::map<std::string, std::string>& testCodeFragments,
438 const std::vector<deInt32>& specConstants,
439 const PushConstants& pushConstants,
440 const GraphicsResources& resources,
441 const GraphicsInterfaces& interfaces,
442 const std::vector<std::string>& extensions,
443 const std::vector<std::string>& features,
444 VulkanFeatures vulkanFeatures,
445 tcu::TestCaseGroup* tests,
446 const qpTestResult failResult = QP_TEST_RESULT_FAIL,
447 const std::string& failMessageTemplate = std::string());
449 inline void createTestsForAllStages (const std::string& name,
450 const tcu::RGBA (&inputColors)[4],
451 const tcu::RGBA (&outputColors)[4],
452 const std::map<std::string, std::string>& testCodeFragments,
453 tcu::TestCaseGroup* tests,
454 const qpTestResult failResult = QP_TEST_RESULT_FAIL,
455 const std::string& failMessageTemplate = std::string())
457 std::vector<deInt32> noSpecConstants;
458 PushConstants noPushConstants;
459 GraphicsResources noResources;
460 GraphicsInterfaces noInterfaces;
461 std::vector<std::string> noExtensions;
462 std::vector<std::string> noFeatures;
464 createTestsForAllStages(
465 name, inputColors, outputColors, testCodeFragments, noSpecConstants, noPushConstants,
466 noResources, noInterfaces, noExtensions, noFeatures, VulkanFeatures(),
467 tests, failResult, failMessageTemplate);
470 inline void createTestsForAllStages (const std::string& name,
471 const tcu::RGBA (&inputColors)[4],
472 const tcu::RGBA (&outputColors)[4],
473 const std::map<std::string, std::string>& testCodeFragments,
474 const std::vector<deInt32>& specConstants,
475 tcu::TestCaseGroup* tests,
476 const qpTestResult failResult = QP_TEST_RESULT_FAIL,
477 const std::string& failMessageTemplate = std::string())
479 PushConstants noPushConstants;
480 GraphicsResources noResources;
481 GraphicsInterfaces noInterfaces;
482 std::vector<std::string> noExtensions;
483 std::vector<std::string> noFeatures;
485 createTestsForAllStages(
486 name, inputColors, outputColors, testCodeFragments, specConstants, noPushConstants,
487 noResources, noInterfaces, noExtensions, noFeatures, VulkanFeatures(),
488 tests, failResult, failMessageTemplate);
491 inline void createTestsForAllStages (const std::string& name,
492 const tcu::RGBA (&inputColors)[4],
493 const tcu::RGBA (&outputColors)[4],
494 const std::map<std::string, std::string>& testCodeFragments,
495 const GraphicsResources& resources,
496 const std::vector<std::string>& extensions,
497 tcu::TestCaseGroup* tests,
498 VulkanFeatures vulkanFeatures = VulkanFeatures(),
499 const qpTestResult failResult = QP_TEST_RESULT_FAIL,
500 const std::string& failMessageTemplate = std::string())
502 std::vector<deInt32> noSpecConstants;
503 PushConstants noPushConstants;
504 GraphicsInterfaces noInterfaces;
505 std::vector<std::string> noFeatures;
507 createTestsForAllStages(
508 name, inputColors, outputColors, testCodeFragments, noSpecConstants, noPushConstants,
509 resources, noInterfaces, extensions, noFeatures, vulkanFeatures,
510 tests, failResult, failMessageTemplate);
513 inline void createTestsForAllStages (const std::string& name,
514 const tcu::RGBA (&inputColors)[4],
515 const tcu::RGBA (&outputColors)[4],
516 const std::map<std::string, std::string>& testCodeFragments,
517 const GraphicsResources& resources,
518 const std::vector<std::string>& extensions,
519 const std::vector<std::string>& features,
520 tcu::TestCaseGroup* tests,
521 VulkanFeatures vulkanFeatures = VulkanFeatures(),
522 const qpTestResult failResult = QP_TEST_RESULT_FAIL,
523 const std::string& failMessageTemplate = std::string())
525 std::vector<deInt32> noSpecConstants;
526 PushConstants noPushConstants;
527 GraphicsInterfaces noInterfaces;
529 createTestsForAllStages(
530 name, inputColors, outputColors, testCodeFragments, noSpecConstants, noPushConstants,
531 resources, noInterfaces, extensions, features, vulkanFeatures,
532 tests, failResult, failMessageTemplate);
535 inline void createTestsForAllStages (const std::string& name,
536 const tcu::RGBA (&inputColors)[4],
537 const tcu::RGBA (&outputColors)[4],
538 const std::map<std::string, std::string>& testCodeFragments,
539 const GraphicsInterfaces interfaces,
540 const std::vector<std::string>& extensions,
541 tcu::TestCaseGroup* tests,
542 VulkanFeatures vulkanFeatures = VulkanFeatures(),
543 const qpTestResult failResult = QP_TEST_RESULT_FAIL,
544 const std::string& failMessageTemplate = std::string())
546 GraphicsResources noResources;
547 std::vector<deInt32> noSpecConstants;
548 std::vector<std::string> noFeatures;
549 PushConstants noPushConstants;
551 createTestsForAllStages(
552 name, inputColors, outputColors, testCodeFragments, noSpecConstants, noPushConstants,
553 noResources, interfaces, extensions, noFeatures, vulkanFeatures,
554 tests, failResult, failMessageTemplate);
557 inline void createTestsForAllStages (const std::string& name,
558 const tcu::RGBA (&inputColors)[4],
559 const tcu::RGBA (&outputColors)[4],
560 const std::map<std::string, std::string>& testCodeFragments,
561 const PushConstants& pushConstants,
562 const GraphicsResources& resources,
563 const std::vector<std::string>& extensions,
564 tcu::TestCaseGroup* tests,
565 VulkanFeatures vulkanFeatures = VulkanFeatures(),
566 const qpTestResult failResult = QP_TEST_RESULT_FAIL,
567 const std::string& failMessageTemplate = std::string())
569 std::vector<deInt32> noSpecConstants;
570 GraphicsInterfaces noInterfaces;
571 std::vector<std::string> noFeatures;
573 createTestsForAllStages(
574 name, inputColors, outputColors, testCodeFragments, noSpecConstants, pushConstants,
575 resources, noInterfaces, extensions, noFeatures, vulkanFeatures,
576 tests, failResult, failMessageTemplate);
579 // Sets up and runs a Vulkan pipeline, then spot-checks the resulting image.
580 // Feeds the pipeline a set of colored triangles, which then must occur in the
581 // rendered image. The surface is cleared before executing the pipeline, so
582 // whatever the shaders draw can be directly spot-checked.
583 tcu::TestStatus runAndVerifyDefaultPipeline (Context& context, InstanceContext instance);
585 // Adds a new test to group using custom fragments for the tessellation-control
586 // stage and passthrough fragments for all other stages. Uses default colors
587 // for input and expected output.
588 void addTessCtrlTest(tcu::TestCaseGroup* group, const char* name, const std::map<std::string, std::string>& fragments);
590 // Given the original 32-bit float value, computes the corresponding 16-bit
591 // float value under the given rounding mode flags and compares with the
592 // returned 16-bit float value. Returns true if they are considered as equal.
594 // The following equivalence criteria are respected:
595 // * Positive and negative zeros are considered equivalent.
596 // * Denormalized floats are allowed to be flushed to zeros, including
597 // * Inputted 32bit denormalized float
598 // * Generated 16bit denormalized float
599 // * Different bit patterns of NaNs are allowed.
600 // * For the rest, require exactly the same bit pattern.
601 bool compare16BitFloat (float original, deUint16 returned, RoundingModeFlags flags, tcu::TestLog& log);
602 bool compare16BitFloat (deFloat16 returned, float original, RoundingModeFlags flags, tcu::TestLog& log);
604 // Compare the returned 32-bit float against its expected value.
606 // The following equivalence criteria are respected:
607 // * Denormalized floats are allowed to be flushed to zeros, including
608 // * The expected value itself is a denormalized float
609 // * The expected value is a denormalized float if converted to 16bit
610 // * Different bit patterns of NaNs/Infs are allowed.
611 // * For the rest, use C++ float equivalence check.
612 bool compare32BitFloat (float expected, float returned, tcu::TestLog& log);
617 #endif // _VKTSPVASMGRAPHICSSHADERTESTUTIL_HPP