Home | History | Annotate | Download | only in spirv_assembly
      1 #ifndef _VKTSPVASMCOMPUTESHADERTESTUTIL_HPP
      2 #define _VKTSPVASMCOMPUTESHADERTESTUTIL_HPP
      3 /*-------------------------------------------------------------------------
      4  * Vulkan Conformance Tests
      5  * ------------------------
      6  *
      7  * Copyright (c) 2015 Google Inc.
      8  *
      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
     12  *
     13  *      http://www.apache.org/licenses/LICENSE-2.0
     14  *
     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.
     20  *
     21  *//*!
     22  * \file
     23  * \brief Compute Shader Based Test Case Utility Structs/Functions
     24  *//*--------------------------------------------------------------------*/
     25 
     26 #include "deDefs.h"
     27 #include "deFloat16.h"
     28 #include "deRandom.hpp"
     29 #include "deSharedPtr.hpp"
     30 #include "tcuTestLog.hpp"
     31 #include "tcuVector.hpp"
     32 #include "vkMemUtil.hpp"
     33 #include "vktSpvAsmUtils.hpp"
     34 
     35 #include <string>
     36 #include <vector>
     37 #include <map>
     38 
     39 using namespace vk;
     40 
     41 namespace vkt
     42 {
     43 namespace SpirVAssembly
     44 {
     45 
     46 enum OpAtomicType
     47 {
     48 	OPATOMIC_IADD = 0,
     49 	OPATOMIC_ISUB,
     50 	OPATOMIC_IINC,
     51 	OPATOMIC_IDEC,
     52 	OPATOMIC_LOAD,
     53 	OPATOMIC_STORE,
     54 	OPATOMIC_COMPEX,
     55 
     56 	OPATOMIC_LAST
     57 };
     58 
     59 enum BufferType
     60 {
     61 	BUFFERTYPE_INPUT = 0,
     62 	BUFFERTYPE_EXPECTED,
     63 
     64 	BUFFERTYPE_LAST
     65 };
     66 
     67 static void fillRandomScalars (de::Random& rnd, deInt32 minValue, deInt32 maxValue, deInt32* dst, deInt32 numValues)
     68 {
     69 	for (int i = 0; i < numValues; i++)
     70 		dst[i] = rnd.getInt(minValue, maxValue);
     71 }
     72 
     73 typedef de::MovePtr<vk::Allocation>			AllocationMp;
     74 typedef de::SharedPtr<vk::Allocation>		AllocationSp;
     75 
     76 /*--------------------------------------------------------------------*//*!
     77  * \brief Abstract class for an input/output storage buffer object
     78  *//*--------------------------------------------------------------------*/
     79 class BufferInterface
     80 {
     81 public:
     82 	virtual				~BufferInterface	(void)				{}
     83 
     84 	virtual void		getBytes			(std::vector<deUint8>& bytes) const = 0;
     85 	virtual size_t		getByteSize			(void) const = 0;
     86 };
     87 
     88 typedef de::SharedPtr<BufferInterface>		BufferSp;
     89 
     90 /*--------------------------------------------------------------------*//*!
     91 * \brief Concrete class for an input/output storage buffer object used for OpAtomic tests
     92 *//*--------------------------------------------------------------------*/
     93 class OpAtomicBuffer : public BufferInterface
     94 {
     95 public:
     96 						OpAtomicBuffer		(const deUint32 numInputElements, const deUint32 numOuptutElements, const OpAtomicType opAtomic, const BufferType type)
     97 							: m_numInputElements	(numInputElements)
     98 							, m_numOutputElements	(numOuptutElements)
     99 							, m_opAtomic			(opAtomic)
    100 							, m_type				(type)
    101 						{}
    102 
    103 	void getBytes (std::vector<deUint8>& bytes) const
    104 	{
    105 		std::vector<deInt32>	inputInts	(m_numInputElements, 0);
    106 		de::Random				rnd			(m_opAtomic);
    107 
    108 		fillRandomScalars(rnd, 1, 100, &inputInts.front(), m_numInputElements);
    109 
    110 		// Return input values as is
    111 		if (m_type == BUFFERTYPE_INPUT)
    112 		{
    113 			size_t					inputSize	= m_numInputElements * sizeof(deInt32);
    114 
    115 			bytes.resize(inputSize);
    116 			deMemcpy(&bytes.front(), &inputInts.front(), inputSize);
    117 		}
    118 		// Calculate expected output values
    119 		else if (m_type == BUFFERTYPE_EXPECTED)
    120 		{
    121 			size_t					outputSize	= m_numOutputElements * sizeof(deInt32);
    122 			bytes.resize(outputSize, 0xffu);
    123 
    124 			for (size_t ndx = 0; ndx < m_numInputElements; ndx++)
    125 			{
    126 				deInt32* const bytesAsInt = reinterpret_cast<deInt32* const>(&bytes.front());
    127 
    128 				switch (m_opAtomic)
    129 				{
    130 					case OPATOMIC_IADD:		bytesAsInt[0] += inputInts[ndx];						break;
    131 					case OPATOMIC_ISUB:		bytesAsInt[0] -= inputInts[ndx];						break;
    132 					case OPATOMIC_IINC:		bytesAsInt[0]++;										break;
    133 					case OPATOMIC_IDEC:		bytesAsInt[0]--;										break;
    134 					case OPATOMIC_LOAD:		bytesAsInt[ndx] = inputInts[ndx];						break;
    135 					case OPATOMIC_STORE:	bytesAsInt[ndx] = inputInts[ndx];						break;
    136 					case OPATOMIC_COMPEX:	bytesAsInt[ndx] = (inputInts[ndx] % 2) == 0 ? -1 : 1;	break;
    137 					default:				DE_FATAL("Unknown OpAtomic type");
    138 				}
    139 			}
    140 		}
    141 		else
    142 			DE_FATAL("Unknown buffer type");
    143 	}
    144 
    145 	size_t getByteSize (void) const
    146 	{
    147 		switch (m_type)
    148 		{
    149 			case BUFFERTYPE_INPUT:
    150 				return m_numInputElements * sizeof(deInt32);
    151 			case BUFFERTYPE_EXPECTED:
    152 				return m_numOutputElements * sizeof(deInt32);
    153 			default:
    154 				DE_FATAL("Unknown buffer type");
    155 				return 0;
    156 		}
    157 	}
    158 
    159 private:
    160 	const deUint32		m_numInputElements;
    161 	const deUint32		m_numOutputElements;
    162 	const OpAtomicType	m_opAtomic;
    163 	const BufferType	m_type;
    164 };
    165 
    166 /*--------------------------------------------------------------------*//*!
    167  * \brief Concrete class for an input/output storage buffer object
    168  *//*--------------------------------------------------------------------*/
    169 template<typename E>
    170 class Buffer : public BufferInterface
    171 {
    172 public:
    173 						Buffer				(const std::vector<E>& elements)
    174 							: m_elements(elements)
    175 						{}
    176 
    177 	void getBytes (std::vector<deUint8>& bytes) const
    178 	{
    179 		const size_t size = m_elements.size() * sizeof(E);
    180 		bytes.resize(size);
    181 		deMemcpy(&bytes.front(), &m_elements.front(), size);
    182 	}
    183 
    184 	size_t getByteSize (void) const
    185 	{
    186 		return m_elements.size() * sizeof(E);
    187 	}
    188 
    189 private:
    190 	std::vector<E>		m_elements;
    191 };
    192 
    193 DE_STATIC_ASSERT(sizeof(tcu::Vec4) == 4 * sizeof(float));
    194 
    195 typedef Buffer<float>		Float32Buffer;
    196 typedef Buffer<deFloat16>	Float16Buffer;
    197 typedef Buffer<deInt64>		Int64Buffer;
    198 typedef Buffer<deInt32>		Int32Buffer;
    199 typedef Buffer<deInt16>		Int16Buffer;
    200 typedef Buffer<tcu::Vec4>	Vec4Buffer;
    201 
    202 typedef bool (*ComputeVerifyIOFunc) (const std::vector<BufferSp>&		inputs,
    203 									 const std::vector<AllocationSp>&	outputAllocations,
    204 									 const std::vector<BufferSp>&		expectedOutputs,
    205 									 tcu::TestLog&						log);
    206 
    207 typedef bool (*ComputeVerifyBinaryFunc) (const ProgramBinary&	binary);
    208 
    209 /*--------------------------------------------------------------------*//*!
    210  * \brief Specification for a compute shader.
    211  *
    212  * This struct bundles SPIR-V assembly code, input and expected output
    213  * together.
    214  *//*--------------------------------------------------------------------*/
    215 struct ComputeShaderSpec
    216 {
    217 	std::string								assembly;
    218 	std::string								entryPoint;
    219 	std::vector<BufferSp>					inputs;
    220 	// Mapping from input index (in the inputs field) to the descriptor type.
    221 	std::map<deUint32, VkDescriptorType>	inputTypes;
    222 	std::vector<BufferSp>					outputs;
    223 	tcu::IVec3								numWorkGroups;
    224 	std::vector<deUint32>					specConstants;
    225 	BufferSp								pushConstants;
    226 	std::vector<std::string>				extensions;
    227 	VulkanFeatures							requestedVulkanFeatures;
    228 	qpTestResult							failResult;
    229 	std::string								failMessage;
    230 	// If null, a default verification will be performed by comparing the memory pointed to by outputAllocations
    231 	// and the contents of expectedOutputs. Otherwise the function pointed to by verifyIO will be called.
    232 	// If true is returned, then the test case is assumed to have passed, if false is returned, then the test
    233 	// case is assumed to have failed. Exact meaning of failure can be customized with failResult.
    234 	ComputeVerifyIOFunc						verifyIO;
    235 	ComputeVerifyBinaryFunc					verifyBinary;
    236 	SpirvVersion							spirvVersion;
    237 
    238 											ComputeShaderSpec (void)
    239 												: entryPoint					("main")
    240 												, pushConstants					(DE_NULL)
    241 												, requestedVulkanFeatures		()
    242 												, failResult					(QP_TEST_RESULT_FAIL)
    243 												, failMessage					("Output doesn't match with expected")
    244 												, verifyIO						(DE_NULL)
    245 												, verifyBinary					(DE_NULL)
    246 												, spirvVersion					(SPIRV_VERSION_1_0)
    247 											{}
    248 };
    249 
    250 /*--------------------------------------------------------------------*//*!
    251  * \brief Helper functions for SPIR-V assembly shared by various tests
    252  *//*--------------------------------------------------------------------*/
    253 
    254 const char* getComputeAsmShaderPreamble				(void);
    255 std::string getComputeAsmCommonTypes				(std::string blockStorageClass = "Uniform");
    256 const char*	getComputeAsmCommonInt64Types			(void);
    257 
    258 /*--------------------------------------------------------------------*//*!
    259  * Declares two uniform variables (indata, outdata) of type
    260  * "struct { float[] }". Depends on type "f32arr" (for "float[]").
    261  *//*--------------------------------------------------------------------*/
    262 const char* getComputeAsmInputOutputBuffer			(void);
    263 /*--------------------------------------------------------------------*//*!
    264  * Declares buffer type and layout for uniform variables indata and
    265  * outdata. Both of them are SSBO bounded to descriptor set 0.
    266  * indata is at binding point 0, while outdata is at 1.
    267  *//*--------------------------------------------------------------------*/
    268 const char* getComputeAsmInputOutputBufferTraits	(void);
    269 
    270 bool verifyOutput									(const std::vector<BufferSp>&,
    271 													const std::vector<AllocationSp>& outputAllocs,
    272 													const std::vector<BufferSp>&		expectedOutputs,
    273 													tcu::TestLog&						log);
    274 
    275 } // SpirVAssembly
    276 } // vkt
    277 
    278 #endif // _VKTSPVASMCOMPUTESHADERTESTUTIL_HPP
    279