1 #ifndef _VKTUNIFORMBLOCKCASE_HPP 2 #define _VKTUNIFORMBLOCKCASE_HPP 3 /*------------------------------------------------------------------------ 4 * Vulkan Conformance Tests 5 * ------------------------ 6 * 7 * Copyright (c) 2015 The Khronos Group Inc. 8 * Copyright (c) 2015 Samsung Electronics Co., Ltd. 9 * 10 * Licensed under the Apache License, Version 2.0 (the "License"); 11 * you may not use this file except in compliance with the License. 12 * You may obtain a copy of the License at 13 * 14 * http://www.apache.org/licenses/LICENSE-2.0 15 * 16 * Unless required by applicable law or agreed to in writing, software 17 * distributed under the License is distributed on an "AS IS" BASIS, 18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 * See the License for the specific language governing permissions and 20 * limitations under the License. 21 * 22 *//*! 23 * \file 24 * \brief Uniform block tests. 25 *//*--------------------------------------------------------------------*/ 26 27 #include "deSharedPtr.hpp" 28 #include "vktTestCase.hpp" 29 #include "tcuDefs.hpp" 30 #include "gluShaderUtil.hpp" 31 32 #include <map> 33 34 namespace vkt 35 { 36 namespace ubo 37 { 38 39 // Uniform block details. 40 41 enum UniformFlags 42 { 43 PRECISION_LOW = (1 << 0), 44 PRECISION_MEDIUM = (1 << 1), 45 PRECISION_HIGH = (1 << 2), 46 PRECISION_MASK = PRECISION_LOW | PRECISION_MEDIUM | PRECISION_HIGH, 47 48 LAYOUT_SHARED = (1 << 3), 49 LAYOUT_PACKED = (1 << 4), 50 LAYOUT_STD140 = (1 << 5), 51 LAYOUT_ROW_MAJOR = (1 << 6), 52 LAYOUT_COLUMN_MAJOR = (1 << 7), //!< \note Lack of both flags means column-major matrix. 53 LAYOUT_OFFSET = (1 << 8), 54 LAYOUT_STD430 = (1 << 9), 55 LAYOUT_SCALAR = (1 << 10), 56 LAYOUT_MASK = LAYOUT_SHARED | LAYOUT_PACKED | LAYOUT_STD140 | LAYOUT_STD430 | LAYOUT_SCALAR | LAYOUT_ROW_MAJOR | 57 LAYOUT_COLUMN_MAJOR | LAYOUT_OFFSET, 58 59 DECLARE_VERTEX = (1 << 11), 60 DECLARE_FRAGMENT = (1 << 12), 61 DECLARE_BOTH = DECLARE_VERTEX | DECLARE_FRAGMENT, 62 63 UNUSED_VERTEX = (1 << 13), //!< Uniform or struct member is not read in vertex shader. 64 UNUSED_FRAGMENT = (1 << 14), //!< Uniform or struct member is not read in fragment shader. 65 UNUSED_BOTH = UNUSED_VERTEX | UNUSED_FRAGMENT, 66 67 LAYOUT_16BIT_STORAGE = (1 << 15), //!< Support VK_KHR_16bit_storage extension 68 LAYOUT_8BIT_STORAGE = (1 << 16), //!< Support VK_KHR_8bit_storage extension 69 70 LAYOUT_DESCRIPTOR_INDEXING = (1 << 17), //!< Support VK_KHR_descriptor_indexing extension 71 }; 72 73 enum MatrixLoadFlags 74 { 75 LOAD_FULL_MATRIX = 0, 76 LOAD_MATRIX_COMPONENTS = 1, 77 }; 78 79 class StructType; 80 81 class VarType 82 { 83 public: 84 VarType(void); 85 VarType(const VarType &other); 86 VarType(glu::DataType basicType, uint32_t flags); 87 VarType(const VarType &elementType, int arraySize); 88 explicit VarType(const StructType *structPtr, uint32_t flags = 0u); 89 ~VarType(void); 90 isBasicType(void) const91 bool isBasicType(void) const 92 { 93 return m_type == TYPE_BASIC; 94 } isArrayType(void) const95 bool isArrayType(void) const 96 { 97 return m_type == TYPE_ARRAY; 98 } isStructType(void) const99 bool isStructType(void) const 100 { 101 return m_type == TYPE_STRUCT; 102 } 103 getFlags(void) const104 uint32_t getFlags(void) const 105 { 106 return m_flags; 107 } getBasicType(void) const108 glu::DataType getBasicType(void) const 109 { 110 return m_data.basicType; 111 } 112 getElementType(void) const113 const VarType &getElementType(void) const 114 { 115 return *m_data.array.elementType; 116 } getArraySize(void) const117 int getArraySize(void) const 118 { 119 return m_data.array.size; 120 } 121 getStruct(void) const122 const StructType &getStruct(void) const 123 { 124 return *m_data.structPtr; 125 } getStructPtr(void) const126 const StructType *getStructPtr(void) const 127 { 128 DE_ASSERT(isStructType()); 129 return m_data.structPtr; 130 } 131 132 VarType &operator=(const VarType &other); 133 134 private: 135 enum Type 136 { 137 TYPE_BASIC, 138 TYPE_ARRAY, 139 TYPE_STRUCT, 140 141 TYPE_LAST 142 }; 143 144 Type m_type; 145 uint32_t m_flags; 146 union Data 147 { 148 glu::DataType basicType; 149 struct 150 { 151 VarType *elementType; 152 int size; 153 } array; 154 const StructType *structPtr; 155 Data(void)156 Data(void) 157 { 158 array.elementType = DE_NULL; 159 array.size = 0; 160 } 161 } m_data; 162 }; 163 164 class StructMember 165 { 166 public: StructMember(const std::string & name,const VarType & type,uint32_t flags)167 StructMember(const std::string &name, const VarType &type, uint32_t flags) 168 : m_name(name) 169 , m_type(type) 170 , m_flags(flags) 171 { 172 } StructMember(void)173 StructMember(void) : m_flags(0) 174 { 175 } 176 getName(void) const177 const std::string &getName(void) const 178 { 179 return m_name; 180 } getType(void) const181 const VarType &getType(void) const 182 { 183 return m_type; 184 } getFlags(void) const185 uint32_t getFlags(void) const 186 { 187 return m_flags; 188 } 189 190 private: 191 std::string m_name; 192 VarType m_type; 193 uint32_t m_flags; 194 }; 195 196 class StructType 197 { 198 public: 199 typedef std::vector<StructMember>::iterator Iterator; 200 typedef std::vector<StructMember>::const_iterator ConstIterator; 201 StructType(const std::string & typeName)202 StructType(const std::string &typeName) : m_typeName(typeName) 203 { 204 } ~StructType(void)205 ~StructType(void) 206 { 207 } 208 getTypeName(void) const209 const std::string &getTypeName(void) const 210 { 211 return m_typeName; 212 } hasTypeName(void) const213 bool hasTypeName(void) const 214 { 215 return !m_typeName.empty(); 216 } 217 begin(void)218 inline Iterator begin(void) 219 { 220 return m_members.begin(); 221 } begin(void) const222 inline ConstIterator begin(void) const 223 { 224 return m_members.begin(); 225 } end(void)226 inline Iterator end(void) 227 { 228 return m_members.end(); 229 } end(void) const230 inline ConstIterator end(void) const 231 { 232 return m_members.end(); 233 } 234 235 void addMember(const std::string &name, const VarType &type, uint32_t flags = 0); 236 237 private: 238 std::string m_typeName; 239 std::vector<StructMember> m_members; 240 }; 241 242 class Uniform 243 { 244 public: 245 Uniform(const std::string &name, const VarType &type, uint32_t flags = 0); 246 getName(void) const247 const std::string &getName(void) const 248 { 249 return m_name; 250 } getType(void) const251 const VarType &getType(void) const 252 { 253 return m_type; 254 } getFlags(void) const255 uint32_t getFlags(void) const 256 { 257 return m_flags; 258 } 259 260 private: 261 std::string m_name; 262 VarType m_type; 263 uint32_t m_flags; 264 }; 265 266 class UniformBlock 267 { 268 public: 269 typedef std::vector<Uniform>::iterator Iterator; 270 typedef std::vector<Uniform>::const_iterator ConstIterator; 271 272 UniformBlock(const std::string &blockName); 273 getBlockName(void) const274 const std::string &getBlockName(void) const 275 { 276 return m_blockName; 277 } getInstanceName(void) const278 const std::string &getInstanceName(void) const 279 { 280 return m_instanceName; 281 } hasInstanceName(void) const282 bool hasInstanceName(void) const 283 { 284 return !m_instanceName.empty(); 285 } isArray(void) const286 bool isArray(void) const 287 { 288 return m_arraySize > 0; 289 } getArraySize(void) const290 int getArraySize(void) const 291 { 292 return m_arraySize; 293 } getFlags(void) const294 uint32_t getFlags(void) const 295 { 296 return m_flags; 297 } 298 setInstanceName(const std::string & name)299 void setInstanceName(const std::string &name) 300 { 301 m_instanceName = name; 302 } setFlags(uint32_t flags)303 void setFlags(uint32_t flags) 304 { 305 m_flags = flags; 306 } setArraySize(int arraySize)307 void setArraySize(int arraySize) 308 { 309 m_arraySize = arraySize; 310 } addUniform(const Uniform & uniform)311 void addUniform(const Uniform &uniform) 312 { 313 m_uniforms.push_back(uniform); 314 } 315 begin(void)316 inline Iterator begin(void) 317 { 318 return m_uniforms.begin(); 319 } begin(void) const320 inline ConstIterator begin(void) const 321 { 322 return m_uniforms.begin(); 323 } end(void)324 inline Iterator end(void) 325 { 326 return m_uniforms.end(); 327 } end(void) const328 inline ConstIterator end(void) const 329 { 330 return m_uniforms.end(); 331 } 332 333 private: 334 std::string m_blockName; 335 std::string m_instanceName; 336 std::vector<Uniform> m_uniforms; 337 int m_arraySize; //!< Array size or 0 if not interface block array. 338 uint32_t m_flags; 339 }; 340 341 typedef de::SharedPtr<StructType> StructTypeSP; 342 typedef de::SharedPtr<UniformBlock> UniformBlockSP; 343 344 class ShaderInterface 345 { 346 public: 347 ShaderInterface(void); 348 ~ShaderInterface(void); 349 350 StructType &allocStruct(const std::string &name); 351 void getNamedStructs(std::vector<const StructType *> &structs) const; 352 353 UniformBlock &allocBlock(const std::string &name); 354 getNumUniformBlocks(void) const355 int getNumUniformBlocks(void) const 356 { 357 return (int)m_uniformBlocks.size(); 358 } getUniformBlock(int ndx) const359 const UniformBlock &getUniformBlock(int ndx) const 360 { 361 return *m_uniformBlocks[ndx]; 362 } 363 bool usesBlockLayout(UniformFlags layoutFlag) const; 364 365 private: 366 std::vector<StructTypeSP> m_structs; 367 std::vector<UniformBlockSP> m_uniformBlocks; 368 }; 369 370 struct BlockLayoutEntry 371 { BlockLayoutEntryvkt::ubo::BlockLayoutEntry372 BlockLayoutEntry(void) : size(0), blockDeclarationNdx(-1), bindingNdx(-1), instanceNdx(-1) 373 { 374 } 375 376 std::string name; 377 int size; 378 std::vector<int> activeUniformIndices; 379 int blockDeclarationNdx; 380 int bindingNdx; 381 int instanceNdx; 382 }; 383 384 struct UniformLayoutEntry 385 { UniformLayoutEntryvkt::ubo::UniformLayoutEntry386 UniformLayoutEntry(void) 387 : type(glu::TYPE_LAST) 388 , size(0) 389 , blockNdx(-1) 390 , offset(-1) 391 , arraySize(-1) 392 , arrayStride(-1) 393 , matrixStride(-1) 394 , topLevelArraySize(-1) 395 , topLevelArrayStride(-1) 396 , isRowMajor(false) 397 , instanceNdx(0) 398 { 399 } 400 401 std::string name; 402 glu::DataType type; 403 int size; 404 int blockNdx; 405 int offset; 406 int arraySize; 407 int arrayStride; 408 int matrixStride; 409 int topLevelArraySize; 410 int topLevelArrayStride; 411 bool isRowMajor; 412 int instanceNdx; 413 }; 414 415 class UniformLayout 416 { 417 public: 418 std::vector<BlockLayoutEntry> blocks; 419 std::vector<UniformLayoutEntry> uniforms; 420 421 int getUniformLayoutIndex(int blockDeclarationNdx, const std::string &name) const; 422 int getBlockLayoutIndex(int blockDeclarationNdx, int instanceNdx) const; 423 }; 424 425 class UniformBlockCase : public vkt::TestCase 426 { 427 public: 428 enum BufferMode 429 { 430 BUFFERMODE_SINGLE = 0, //!< Single buffer shared between uniform blocks. 431 BUFFERMODE_PER_BLOCK, //!< Per-block buffers 432 433 BUFFERMODE_LAST 434 }; 435 436 UniformBlockCase(tcu::TestContext &testCtx, const std::string &name, BufferMode bufferMode, 437 MatrixLoadFlags matrixLoadFlag, bool shuffleUniformMembers = false); 438 ~UniformBlockCase(void); 439 440 virtual void delayedInit(void); 441 virtual void initPrograms(vk::SourceCollections &programCollection) const; 442 virtual TestInstance *createInstance(Context &context) const; usesBlockLayout(UniformFlags layoutFlag) const443 bool usesBlockLayout(UniformFlags layoutFlag) const 444 { 445 return m_interface.usesBlockLayout(layoutFlag); 446 } 447 448 protected: 449 BufferMode m_bufferMode; 450 ShaderInterface m_interface; 451 MatrixLoadFlags m_matrixLoadFlag; 452 const bool m_shuffleUniformMembers; //!< Used with explicit offsets to test out of order member offsets 453 454 private: 455 std::string m_vertShaderSource; 456 std::string m_fragShaderSource; 457 458 std::vector<uint8_t> m_data; //!< Data. 459 std::map<int, void *> m_blockPointers; //!< Reference block pointers. 460 UniformLayout m_uniformLayout; //!< std140 layout. 461 }; 462 463 } // namespace ubo 464 } // namespace vkt 465 466 #endif // _VKTUNIFORMBLOCKCASE_HPP 467