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 39using namespace vk; 40 41namespace vkt 42{ 43namespace SpirVAssembly 44{ 45 46enum 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 59enum BufferType 60{ 61 BUFFERTYPE_INPUT = 0, 62 BUFFERTYPE_EXPECTED, 63 64 BUFFERTYPE_LAST 65}; 66 67static 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 73typedef de::MovePtr<vk::Allocation> AllocationMp; 74typedef de::SharedPtr<vk::Allocation> AllocationSp; 75 76/*--------------------------------------------------------------------*//*! 77 * \brief Abstract class for an input/output storage buffer object 78 *//*--------------------------------------------------------------------*/ 79class BufferInterface 80{ 81public: 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 88typedef de::SharedPtr<BufferInterface> BufferSp; 89 90/*--------------------------------------------------------------------*//*! 91* \brief Concrete class for an input/output storage buffer object used for OpAtomic tests 92*//*--------------------------------------------------------------------*/ 93class OpAtomicBuffer : public BufferInterface 94{ 95public: 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 159private: 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 *//*--------------------------------------------------------------------*/ 169template<typename E> 170class Buffer : public BufferInterface 171{ 172public: 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 189private: 190 std::vector<E> m_elements; 191}; 192 193DE_STATIC_ASSERT(sizeof(tcu::Vec4) == 4 * sizeof(float)); 194 195typedef Buffer<float> Float32Buffer; 196typedef Buffer<deFloat16> Float16Buffer; 197typedef Buffer<deInt64> Int64Buffer; 198typedef Buffer<deInt32> Int32Buffer; 199typedef Buffer<deInt16> Int16Buffer; 200typedef Buffer<tcu::Vec4> Vec4Buffer; 201 202typedef bool (*ComputeVerifyIOFunc) (const std::vector<BufferSp>& inputs, 203 const std::vector<AllocationSp>& outputAllocations, 204 const std::vector<BufferSp>& expectedOutputs, 205 tcu::TestLog& log); 206 207typedef 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 *//*--------------------------------------------------------------------*/ 215struct 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 254const char* getComputeAsmShaderPreamble (void); 255std::string getComputeAsmCommonTypes (std::string blockStorageClass = "Uniform"); 256const char* getComputeAsmCommonInt64Types (void); 257 258/*--------------------------------------------------------------------*//*! 259 * Declares two uniform variables (indata, outdata) of type 260 * "struct { float[] }". Depends on type "f32arr" (for "float[]"). 261 *//*--------------------------------------------------------------------*/ 262const 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 *//*--------------------------------------------------------------------*/ 268const char* getComputeAsmInputOutputBufferTraits (void); 269 270bool 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