blob: c4e407cea1bb4a57f24f21deae81407309f1b68b [file] [log] [blame]
/*------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2020 The Khronos Group Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief Ray Tracing Misc tests
*//*--------------------------------------------------------------------*/
#include "vktRayTracingMiscTests.hpp"
#include "vktTestCaseUtil.hpp"
#include "vkDefs.hpp"
#include "vktTestCase.hpp"
#include "vkCmdUtil.hpp"
#include "vkObjUtil.hpp"
#include "vkBuilderUtil.hpp"
#include "vkBarrierUtil.hpp"
#include "vkBufferWithMemory.hpp"
#include "vkImageWithMemory.hpp"
#include "vkTypeUtil.hpp"
#include "vkRayTracingUtil.hpp"
#include "deRandom.hpp"
#include <algorithm>
#include <memory>
#include <sstream>
namespace vkt
{
namespace RayTracing
{
namespace
{
using namespace vk;
using namespace std;
enum class BaseType
{
F32,
F64,
I8,
I16,
I32,
I64,
U8,
U16,
U32,
U64,
UNKNOWN
};
enum class GeometryType
{
FIRST = 0,
AABB = FIRST,
TRIANGLES,
COUNT,
AABB_AND_TRIANGLES, //< Only compatible with ONE_TL_MANY_BLS_MANY_GEOMETRIES_WITH_VARYING_PRIM_TYPES AS layout.
};
enum class MatrixMajorOrder
{
COLUMN_MAJOR,
ROW_MAJOR,
UNKNOWN
};
enum class ShaderGroups
{
FIRST_GROUP = 0,
RAYGEN_GROUP = FIRST_GROUP,
MISS_GROUP,
HIT_GROUP,
FIRST_CALLABLE_GROUP,
};
enum class TestType
{
AABBS_AND_TRIS_IN_ONE_TL,
AS_STRESS_TEST,
CALLABLE_SHADER_STRESS_DYNAMIC_TEST,
CALLABLE_SHADER_STRESS_TEST,
CULL_MASK,
MAX_RAY_HIT_ATTRIBUTE_SIZE,
MAX_RT_INVOCATIONS_SUPPORTED,
CULL_MASK_EXTRA_BITS,
NO_DUPLICATE_ANY_HIT,
REPORT_INTERSECTION_RESULT,
RAY_PAYLOAD_IN,
RECURSIVE_TRACES_0,
RECURSIVE_TRACES_1,
RECURSIVE_TRACES_2,
RECURSIVE_TRACES_3,
RECURSIVE_TRACES_4,
RECURSIVE_TRACES_5,
RECURSIVE_TRACES_6,
RECURSIVE_TRACES_7,
RECURSIVE_TRACES_8,
RECURSIVE_TRACES_9,
RECURSIVE_TRACES_10,
RECURSIVE_TRACES_11,
RECURSIVE_TRACES_12,
RECURSIVE_TRACES_13,
RECURSIVE_TRACES_14,
RECURSIVE_TRACES_15,
RECURSIVE_TRACES_16,
RECURSIVE_TRACES_17,
RECURSIVE_TRACES_18,
RECURSIVE_TRACES_19,
RECURSIVE_TRACES_20,
RECURSIVE_TRACES_21,
RECURSIVE_TRACES_22,
RECURSIVE_TRACES_23,
RECURSIVE_TRACES_24,
RECURSIVE_TRACES_25,
RECURSIVE_TRACES_26,
RECURSIVE_TRACES_27,
RECURSIVE_TRACES_28,
RECURSIVE_TRACES_29,
SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_1,
SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_2,
SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_3,
SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_4,
SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_5,
SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_6,
SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_1,
SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_2,
SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_3,
SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_4,
SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_5,
SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_6,
SHADER_RECORD_BLOCK_SCALAR_1,
SHADER_RECORD_BLOCK_SCALAR_2,
SHADER_RECORD_BLOCK_SCALAR_3,
SHADER_RECORD_BLOCK_SCALAR_4,
SHADER_RECORD_BLOCK_SCALAR_5,
SHADER_RECORD_BLOCK_SCALAR_6,
SHADER_RECORD_BLOCK_STD430_1,
SHADER_RECORD_BLOCK_STD430_2,
SHADER_RECORD_BLOCK_STD430_3,
SHADER_RECORD_BLOCK_STD430_4,
SHADER_RECORD_BLOCK_STD430_5,
SHADER_RECORD_BLOCK_STD430_6,
IGNORE_ANY_HIT_STATICALLY,
IGNORE_ANY_HIT_DYNAMICALLY,
TERMINATE_ANY_HIT_STATICALLY,
TERMINATE_ANY_HIT_DYNAMICALLY,
TERMINATE_INTERSECTION_STATICALLY,
TERMINATE_INTERSECTION_DYNAMICALLY,
COUNT
};
enum class VariableType
{
FIRST,
FLOAT = FIRST,
VEC2,
VEC3,
VEC4,
MAT2,
MAT2X2,
MAT2X3,
MAT2X4,
MAT3,
MAT3X2,
MAT3X3,
MAT3X4,
MAT4,
MAT4X2,
MAT4X3,
MAT4X4,
INT,
IVEC2,
IVEC3,
IVEC4,
INT8,
I8VEC2,
I8VEC3,
I8VEC4,
INT16,
I16VEC2,
I16VEC3,
I16VEC4,
INT64,
I64VEC2,
I64VEC3,
I64VEC4,
UINT,
UVEC2,
UVEC3,
UVEC4,
UINT16,
U16VEC2,
U16VEC3,
U16VEC4,
UINT64,
U64VEC2,
U64VEC3,
U64VEC4,
UINT8,
U8VEC2,
U8VEC3,
U8VEC4,
DOUBLE,
DVEC2,
DVEC3,
DVEC4,
DMAT2,
DMAT2X2,
DMAT2X3,
DMAT2X4,
DMAT3,
DMAT3X2,
DMAT3X3,
DMAT3X4,
DMAT4,
DMAT4X2,
DMAT4X3,
DMAT4X4,
UNKNOWN,
COUNT = UNKNOWN,
};
enum class AccelerationStructureLayout
{
FIRST = 0,
ONE_TL_ONE_BL_ONE_GEOMETRY = FIRST,
ONE_TL_ONE_BL_MANY_GEOMETRIES,
ONE_TL_MANY_BLS_ONE_GEOMETRY,
ONE_TL_MANY_BLS_MANY_GEOMETRIES,
COUNT,
ONE_TL_MANY_BLS_MANY_GEOMETRIES_WITH_VARYING_PRIM_TYPES
};
static const VkFlags ALL_RAY_TRACING_STAGES = VK_SHADER_STAGE_RAYGEN_BIT_KHR
| VK_SHADER_STAGE_ANY_HIT_BIT_KHR
| VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR
| VK_SHADER_STAGE_MISS_BIT_KHR
| VK_SHADER_STAGE_INTERSECTION_BIT_KHR
| VK_SHADER_STAGE_CALLABLE_BIT_KHR;
struct CaseDef
{
TestType type;
GeometryType geometryType;
AccelerationStructureLayout asLayout;
CaseDef()
: type (TestType::COUNT),
geometryType (GeometryType::COUNT),
asLayout (AccelerationStructureLayout::COUNT)
{
/* Stub */
}
CaseDef(const TestType& inType)
: type (inType),
geometryType (GeometryType::COUNT),
asLayout (AccelerationStructureLayout::COUNT)
{
/* Stub */
}
CaseDef(const TestType& inType,
const GeometryType& inGeometryType,
const AccelerationStructureLayout& inAsLayout)
: type (inType),
geometryType (inGeometryType),
asLayout (inAsLayout)
{
/* Stub */
}
};
/* Helper global functions */
static const char* getSuffixForASLayout(const AccelerationStructureLayout& layout)
{
const char* result = "?!";
switch (layout)
{
case AccelerationStructureLayout::ONE_TL_ONE_BL_ONE_GEOMETRY: result = "1TL1BL1G"; break;
case AccelerationStructureLayout::ONE_TL_ONE_BL_MANY_GEOMETRIES: result = "1TL1BLnG"; break;
case AccelerationStructureLayout::ONE_TL_MANY_BLS_ONE_GEOMETRY: result = "1TLnBL1G"; break;
case AccelerationStructureLayout::ONE_TL_MANY_BLS_MANY_GEOMETRIES: result = "1TLnBLnG"; break;
default:
{
deAssertFail("This should never happen", __FILE__, __LINE__);
}
}
return result;
}
static const char* getSuffixForGeometryType(const GeometryType& type)
{
const char* result = "?!";
switch (type)
{
case GeometryType::AABB: result = "AABB"; break;
case GeometryType::TRIANGLES: result = "tri"; break;
default:
{
deAssertFail("This should never happen", __FILE__, __LINE__);
}
}
return result;
}
/* Instances and primitives in acceleration structures can have additional information assigned.
*
* By overriding functions of interest in this class, tests can further customize ASes generated by AS providers.
*/
class ASPropertyProvider
{
public:
virtual ~ASPropertyProvider()
{
/* Stub */
}
virtual deUint8 getCullMask(const deUint32& nBL, const deUint32& nInstance) const
{
DE_UNREF(nBL);
DE_UNREF(nInstance);
return 0xFF;
}
virtual deUint32 getInstanceCustomIndex(const deUint32& nBL, const deUint32& nInstance) const
{
DE_UNREF(nBL);
DE_UNREF(nInstance);
return 0;
}
};
class IGridASFeedback
{
public:
virtual ~IGridASFeedback()
{
/* Stub */
}
virtual void onCullMaskAssignedToCell (const tcu::UVec3& cellLocation, const deUint8& cullMaskAssigned) = 0;
virtual void onInstanceCustomIndexAssignedToCell(const tcu::UVec3& cellLocation, const deUint32& customIndexAssigned) = 0;
};
/* Acceleration structure data providers.
*
* These are expected to be reused across different test cases.
**/
class ASProviderBase
{
public:
virtual ~ASProviderBase()
{
/* Stub */
}
virtual std::unique_ptr<TopLevelAccelerationStructure> createTLAS( Context& context,
const AccelerationStructureLayout& asLayout,
VkCommandBuffer cmdBuffer,
const VkGeometryFlagsKHR& bottomLevelGeometryFlags,
const ASPropertyProvider* optAsPropertyProviderPtr = nullptr,
IGridASFeedback* optASFeedbackPtr = nullptr) const = 0;
virtual deUint32 getNPrimitives() const = 0;
};
/* A 3D grid built of primitives. Size and distribution of the geometry can be configured both at creation time and at a later time. */
class GridASProvider : public ASProviderBase
{
public:
GridASProvider( const tcu::Vec3& gridStartXYZ,
const tcu::Vec3& gridCellSizeXYZ,
const tcu::UVec3& gridSizeXYZ,
const tcu::Vec3& gridInterCellDeltaXYZ,
const GeometryType& geometryType)
:m_geometryType (geometryType),
m_gridCellSizeXYZ (gridCellSizeXYZ),
m_gridInterCellDeltaXYZ(gridInterCellDeltaXYZ),
m_gridSizeXYZ (gridSizeXYZ),
m_gridStartXYZ (gridStartXYZ)
{
fillVertexVec();
}
std::unique_ptr<TopLevelAccelerationStructure> createTLAS( Context& context,
const AccelerationStructureLayout& asLayout,
VkCommandBuffer cmdBuffer,
const VkGeometryFlagsKHR& bottomLevelGeometryFlags,
const ASPropertyProvider* optASPropertyProviderPtr,
IGridASFeedback* optASFeedbackPtr) const final
{
Allocator& allocator = context.getDefaultAllocator ();
const DeviceInterface& deviceInterface = context.getDeviceInterface ();
const VkDevice deviceVk = context.getDevice ();
const auto nCells = m_gridSizeXYZ.x() * m_gridSizeXYZ.y() * m_gridSizeXYZ.z();
std::unique_ptr<TopLevelAccelerationStructure> resultPtr;
de::MovePtr<TopLevelAccelerationStructure> tlPtr = makeTopLevelAccelerationStructure ();
DE_ASSERT(((asLayout == AccelerationStructureLayout::ONE_TL_MANY_BLS_MANY_GEOMETRIES_WITH_VARYING_PRIM_TYPES) && (m_geometryType == GeometryType::AABB_AND_TRIANGLES)) ||
((asLayout != AccelerationStructureLayout::ONE_TL_MANY_BLS_MANY_GEOMETRIES_WITH_VARYING_PRIM_TYPES) && (m_geometryType != GeometryType::AABB_AND_TRIANGLES)) );
switch (asLayout)
{
case AccelerationStructureLayout::ONE_TL_ONE_BL_ONE_GEOMETRY:
{
DE_ASSERT( (m_geometryType == GeometryType::AABB) || (m_geometryType == GeometryType::TRIANGLES) );
const auto& vertexVec = (m_geometryType == GeometryType::AABB) ? m_aabbVertexVec
: m_triVertexVec;
const auto cullMask = (optASPropertyProviderPtr != nullptr) ? optASPropertyProviderPtr->getCullMask(0, 0)
: static_cast<deUint8>(0xFF);
const auto instanceCustomIndex = (optASPropertyProviderPtr != nullptr) ? optASPropertyProviderPtr->getInstanceCustomIndex(0, 0)
: 0;
tlPtr->setInstanceCount(1);
{
de::MovePtr<BottomLevelAccelerationStructure> blPtr = makeBottomLevelAccelerationStructure();
blPtr->setGeometryCount (1u);
blPtr->addGeometry (vertexVec,
(m_geometryType == GeometryType::TRIANGLES),
bottomLevelGeometryFlags);
blPtr->createAndBuild( deviceInterface,
deviceVk,
cmdBuffer,
allocator);
tlPtr->addInstance( de::SharedPtr<BottomLevelAccelerationStructure>(blPtr.release() ),
identityMatrix3x4,
instanceCustomIndex,
cullMask);
}
if (optASFeedbackPtr != nullptr)
{
for (auto nCell = 0u;
nCell < nCells;
nCell++)
{
const auto cellX = (((nCell) % m_gridSizeXYZ.x() ));
const auto cellY = (((nCell / m_gridSizeXYZ.x() ) % m_gridSizeXYZ.y() ));
const auto cellZ = (((nCell / m_gridSizeXYZ.x() ) / m_gridSizeXYZ.y() ) % m_gridSizeXYZ.z() );
optASFeedbackPtr->onCullMaskAssignedToCell ( tcu::UVec3(cellX, cellY, cellZ),
cullMask);
optASFeedbackPtr->onInstanceCustomIndexAssignedToCell ( tcu::UVec3(cellX, cellY, cellZ),
instanceCustomIndex);
}
}
break;
}
case AccelerationStructureLayout::ONE_TL_ONE_BL_MANY_GEOMETRIES:
{
DE_ASSERT( (m_geometryType == GeometryType::AABB) || (m_geometryType == GeometryType::TRIANGLES) );
const auto& vertexVec = (m_geometryType == GeometryType::AABB) ? m_aabbVertexVec
: m_triVertexVec;
const auto nVerticesPerPrimitive = (m_geometryType == GeometryType::AABB) ? 2u
: 12u /* tris */ * 3 /* verts */;
const auto cullMask = (optASPropertyProviderPtr != nullptr) ? optASPropertyProviderPtr->getCullMask(0, 0)
: static_cast<deUint8>(0xFF);
const auto instanceCustomIndex = (optASPropertyProviderPtr != nullptr) ? optASPropertyProviderPtr->getInstanceCustomIndex(0, 0)
: 0;
DE_ASSERT( (vertexVec.size() % nVerticesPerPrimitive) == 0);
tlPtr->setInstanceCount(1);
{
de::MovePtr<BottomLevelAccelerationStructure> blPtr = makeBottomLevelAccelerationStructure();
const auto nGeometries = vertexVec.size() / nVerticesPerPrimitive;
blPtr->setGeometryCount (nGeometries);
for (deUint32 nGeometry = 0; nGeometry < nGeometries; ++nGeometry)
{
std::vector<tcu::Vec3> currentGeometry(nVerticesPerPrimitive);
for (deUint32 nVertex = 0; nVertex < nVerticesPerPrimitive; ++nVertex)
{
currentGeometry.at(nVertex) = vertexVec.at(nGeometry * nVerticesPerPrimitive + nVertex);
}
blPtr->addGeometry (currentGeometry,
(m_geometryType == GeometryType::TRIANGLES),
bottomLevelGeometryFlags);
}
blPtr->createAndBuild( deviceInterface,
deviceVk,
cmdBuffer,
allocator);
tlPtr->addInstance( de::SharedPtr<BottomLevelAccelerationStructure>(blPtr.release() ),
identityMatrix3x4,
instanceCustomIndex,
cullMask);
}
if (optASFeedbackPtr != nullptr)
{
for (auto nCell = 0u;
nCell < nCells;
nCell++)
{
const auto cellX = (((nCell) % m_gridSizeXYZ.x() ));
const auto cellY = (((nCell / m_gridSizeXYZ.x() ) % m_gridSizeXYZ.y() ));
const auto cellZ = (((nCell / m_gridSizeXYZ.x() ) / m_gridSizeXYZ.y() ) % m_gridSizeXYZ.z() );
optASFeedbackPtr->onCullMaskAssignedToCell ( tcu::UVec3(cellX, cellY, cellZ),
cullMask);
optASFeedbackPtr->onInstanceCustomIndexAssignedToCell ( tcu::UVec3(cellX, cellY, cellZ),
instanceCustomIndex);
}
}
break;
}
case AccelerationStructureLayout::ONE_TL_MANY_BLS_ONE_GEOMETRY:
{
DE_ASSERT( (m_geometryType == GeometryType::AABB) || (m_geometryType == GeometryType::TRIANGLES) );
const auto& vertexVec = (m_geometryType == GeometryType::AABB) ? m_aabbVertexVec
: m_triVertexVec;
const auto nVerticesPerPrimitive = (m_geometryType == GeometryType::AABB) ? 2u
: 12u /* tris */ * 3 /* verts */;
const auto nInstances = vertexVec.size() / nVerticesPerPrimitive;
DE_ASSERT( (vertexVec.size() % nVerticesPerPrimitive) == 0);
tlPtr->setInstanceCount(nInstances);
for (deUint32 nInstance = 0; nInstance < nInstances; nInstance++)
{
de::MovePtr<BottomLevelAccelerationStructure> blPtr = makeBottomLevelAccelerationStructure();
const auto cullMask = (optASPropertyProviderPtr != nullptr) ? optASPropertyProviderPtr->getCullMask(0, nInstance)
: static_cast<deUint8>(0xFF);
std::vector<tcu::Vec3> currentInstanceVertexVec;
const auto instanceCustomIndex = (optASPropertyProviderPtr != nullptr) ? optASPropertyProviderPtr->getInstanceCustomIndex(0, nInstance)
: 0;
for (deUint32 nVertex = 0; nVertex < nVerticesPerPrimitive; ++nVertex)
{
currentInstanceVertexVec.push_back(vertexVec.at(nInstance * nVerticesPerPrimitive + nVertex) );
}
blPtr->setGeometryCount (1u);
blPtr->addGeometry (currentInstanceVertexVec,
(m_geometryType == GeometryType::TRIANGLES),
bottomLevelGeometryFlags);
blPtr->createAndBuild( deviceInterface,
deviceVk,
cmdBuffer,
allocator);
tlPtr->addInstance( de::SharedPtr<BottomLevelAccelerationStructure>(blPtr.release() ),
identityMatrix3x4,
instanceCustomIndex,
cullMask);
if (optASFeedbackPtr != nullptr)
{
const auto cellX = (((nInstance) % m_gridSizeXYZ.x() ));
const auto cellY = (((nInstance / m_gridSizeXYZ.x() ) % m_gridSizeXYZ.y() ));
const auto cellZ = (((nInstance / m_gridSizeXYZ.x() ) / m_gridSizeXYZ.y() ) % m_gridSizeXYZ.z() );
optASFeedbackPtr->onCullMaskAssignedToCell( tcu::UVec3(cellX, cellY, cellZ),
cullMask);
optASFeedbackPtr->onInstanceCustomIndexAssignedToCell( tcu::UVec3(cellX, cellY, cellZ),
instanceCustomIndex);
}
}
break;
}
case AccelerationStructureLayout::ONE_TL_MANY_BLS_MANY_GEOMETRIES:
{
DE_ASSERT( (m_geometryType == GeometryType::AABB) || (m_geometryType == GeometryType::TRIANGLES) );
const auto& vertexVec = (m_geometryType == GeometryType::AABB) ? m_aabbVertexVec
: m_triVertexVec;
const auto nVerticesPerPrimitive = (m_geometryType == GeometryType::AABB) ? 2u
: 12u /* tris */ * 3 /* verts */;
const auto nPrimitivesDefined = static_cast<deUint32>(vertexVec.size() / nVerticesPerPrimitive);
const auto nPrimitivesPerBLAS = 4;
const auto nBottomLevelASes = nPrimitivesDefined / nPrimitivesPerBLAS;
DE_ASSERT( (vertexVec.size() % nVerticesPerPrimitive) == 0);
DE_ASSERT( (nPrimitivesDefined % nPrimitivesPerBLAS) == 0);
tlPtr->setInstanceCount(nBottomLevelASes);
for (deUint32 nBottomLevelAS = 0; nBottomLevelAS < nBottomLevelASes; nBottomLevelAS++)
{
de::MovePtr<BottomLevelAccelerationStructure> blPtr = makeBottomLevelAccelerationStructure();
const auto cullMask = (optASPropertyProviderPtr != nullptr) ? optASPropertyProviderPtr->getCullMask(nBottomLevelAS, 0)
: static_cast<deUint8>(0xFF);
const auto instanceCustomIndex = (optASPropertyProviderPtr != nullptr) ? optASPropertyProviderPtr->getInstanceCustomIndex(nBottomLevelAS, 0)
: 0;
blPtr->setGeometryCount(nPrimitivesPerBLAS);
for (deUint32 nGeometry = 0; nGeometry < nPrimitivesPerBLAS; nGeometry++)
{
std::vector<tcu::Vec3> currentVertexVec;
for (deUint32 nVertex = 0; nVertex < nVerticesPerPrimitive; ++nVertex)
{
currentVertexVec.push_back(vertexVec.at((nBottomLevelAS * nPrimitivesPerBLAS + nGeometry) * nVerticesPerPrimitive + nVertex) );
}
blPtr->addGeometry( currentVertexVec,
(m_geometryType == GeometryType::TRIANGLES),
bottomLevelGeometryFlags);
}
blPtr->createAndBuild( deviceInterface,
deviceVk,
cmdBuffer,
allocator);
tlPtr->addInstance( de::SharedPtr<BottomLevelAccelerationStructure>(blPtr.release() ),
identityMatrix3x4,
instanceCustomIndex,
cullMask);
if (optASFeedbackPtr != nullptr)
{
for (deUint32 cellIndex = nPrimitivesPerBLAS * nBottomLevelAS; cellIndex < nPrimitivesPerBLAS * (nBottomLevelAS + 1); cellIndex++)
{
const auto cellX = (((cellIndex) % m_gridSizeXYZ.x() ));
const auto cellY = (((cellIndex / m_gridSizeXYZ.x() ) % m_gridSizeXYZ.y() ));
const auto cellZ = (((cellIndex / m_gridSizeXYZ.x() ) / m_gridSizeXYZ.y() ) % m_gridSizeXYZ.z() );
optASFeedbackPtr->onCullMaskAssignedToCell ( tcu::UVec3(cellX, cellY, cellZ),
cullMask);
optASFeedbackPtr->onInstanceCustomIndexAssignedToCell ( tcu::UVec3(cellX, cellY, cellZ),
instanceCustomIndex);
}
}
}
break;
}
case AccelerationStructureLayout::ONE_TL_MANY_BLS_MANY_GEOMETRIES_WITH_VARYING_PRIM_TYPES:
{
DE_ASSERT(m_geometryType == GeometryType::AABB_AND_TRIANGLES);
const auto nCellsDefined = m_gridSizeXYZ[0] * m_gridSizeXYZ[1] * m_gridSizeXYZ[2];
const auto nPrimitivesPerBLAS = 1;
const auto nBottomLevelASes = nCellsDefined / nPrimitivesPerBLAS;
DE_ASSERT( (nCellsDefined % nPrimitivesPerBLAS) == 0);
tlPtr->setInstanceCount(nBottomLevelASes);
for (deUint32 nBottomLevelAS = 0; nBottomLevelAS < nBottomLevelASes; nBottomLevelAS++)
{
de::MovePtr<BottomLevelAccelerationStructure> blPtr = makeBottomLevelAccelerationStructure();
const auto cullMask = (optASPropertyProviderPtr != nullptr) ? optASPropertyProviderPtr->getCullMask(nBottomLevelAS, 0)
: static_cast<deUint8>(0xFF);
const auto instanceCustomIndex = (optASPropertyProviderPtr != nullptr) ? optASPropertyProviderPtr->getInstanceCustomIndex(nBottomLevelAS, 0)
: 0;
const bool usesAABB = (nBottomLevelAS % 2) == 0;
const auto& vertexVec = (usesAABB) ? m_aabbVertexVec
: m_triVertexVec;
const auto nVerticesPerPrimitive = (usesAABB) ? 2u
: 12u /* tris */ * 3 /* verts */;
// For this case, AABBs use the first shader group and triangles use the second shader group in the table.
const auto instanceSBTOffset = (usesAABB ? 0u : 1u);
blPtr->setGeometryCount(nPrimitivesPerBLAS);
for (deUint32 nGeometry = 0; nGeometry < nPrimitivesPerBLAS; nGeometry++)
{
DE_ASSERT( (vertexVec.size() % nVerticesPerPrimitive) == 0);
std::vector<tcu::Vec3> currentVertexVec;
for (deUint32 nVertex = 0; nVertex < nVerticesPerPrimitive; ++nVertex)
{
currentVertexVec.push_back(vertexVec.at((nBottomLevelAS * nPrimitivesPerBLAS + nGeometry) * nVerticesPerPrimitive + nVertex) );
}
blPtr->addGeometry( currentVertexVec,
!usesAABB,
bottomLevelGeometryFlags);
}
blPtr->createAndBuild ( deviceInterface,
deviceVk,
cmdBuffer,
allocator);
tlPtr->addInstance( de::SharedPtr<BottomLevelAccelerationStructure>(blPtr.release() ),
identityMatrix3x4,
instanceCustomIndex,
cullMask,
instanceSBTOffset);
if (optASFeedbackPtr != nullptr)
{
for (deUint32 cellIndex = nPrimitivesPerBLAS * nBottomLevelAS; cellIndex < nPrimitivesPerBLAS * (nBottomLevelAS + 1); cellIndex++)
{
const auto cellX = (((cellIndex) % m_gridSizeXYZ.x() ));
const auto cellY = (((cellIndex / m_gridSizeXYZ.x() ) % m_gridSizeXYZ.y() ));
const auto cellZ = (((cellIndex / m_gridSizeXYZ.x() ) / m_gridSizeXYZ.y() ) % m_gridSizeXYZ.z() );
optASFeedbackPtr->onCullMaskAssignedToCell ( tcu::UVec3(cellX, cellY, cellZ),
cullMask);
optASFeedbackPtr->onInstanceCustomIndexAssignedToCell ( tcu::UVec3(cellX, cellY, cellZ),
instanceCustomIndex);
}
}
}
break;
}
default:
{
deAssertFail("This should never happen", __FILE__, __LINE__);
}
}
tlPtr->createAndBuild( deviceInterface,
deviceVk,
cmdBuffer,
allocator);
resultPtr = decltype(resultPtr)(tlPtr.release() );
return resultPtr;
}
deUint32 getNPrimitives() const final
{
return m_gridSizeXYZ[0] * m_gridSizeXYZ[1] * m_gridSizeXYZ[2];
}
void setProperties( const tcu::Vec3& gridStartXYZ,
const tcu::Vec3& gridCellSizeXYZ,
const tcu::UVec3& gridSizeXYZ,
const tcu::Vec3& gridInterCellDeltaXYZ,
const GeometryType& geometryType)
{
m_gridStartXYZ = gridStartXYZ;
m_gridCellSizeXYZ = gridCellSizeXYZ;
m_gridSizeXYZ = gridSizeXYZ;
m_gridInterCellDeltaXYZ = gridInterCellDeltaXYZ;
m_geometryType = geometryType;
fillVertexVec();
}
private:
void fillVertexVec()
{
const auto nCellsNeeded = m_gridSizeXYZ.x() * m_gridSizeXYZ.y() * m_gridSizeXYZ.z();
m_aabbVertexVec.clear();
m_triVertexVec.clear ();
for (auto nCell = 0u;
nCell < nCellsNeeded;
nCell++)
{
const auto cellX = (((nCell) % m_gridSizeXYZ.x() ));
const auto cellY = (((nCell / m_gridSizeXYZ.x() ) % m_gridSizeXYZ.y() ));
const auto cellZ = (((nCell / m_gridSizeXYZ.x() ) / m_gridSizeXYZ.y() ) % m_gridSizeXYZ.z() );
const auto cellX1Y1Z1 = tcu::Vec3( m_gridStartXYZ.x() + static_cast<float>(cellX) * m_gridInterCellDeltaXYZ.x(),
m_gridStartXYZ.y() + static_cast<float>(cellY) * m_gridInterCellDeltaXYZ.y(),
m_gridStartXYZ.z() + static_cast<float>(cellZ) * m_gridInterCellDeltaXYZ.z() );
const auto cellX2Y2Z2 = tcu::Vec3( m_gridStartXYZ.x() + static_cast<float>(cellX) * m_gridInterCellDeltaXYZ.x() + m_gridCellSizeXYZ.x(),
m_gridStartXYZ.y() + static_cast<float>(cellY) * m_gridInterCellDeltaXYZ.y() + m_gridCellSizeXYZ.y(),
m_gridStartXYZ.z() + static_cast<float>(cellZ) * m_gridInterCellDeltaXYZ.z() + m_gridCellSizeXYZ.z() );
if (m_geometryType == GeometryType::AABB ||
m_geometryType == GeometryType::AABB_AND_TRIANGLES)
{
/* Cell = AABB of the cell */
m_aabbVertexVec.push_back(cellX1Y1Z1);
m_aabbVertexVec.push_back(cellX2Y2Z2);
}
if (m_geometryType == GeometryType::AABB_AND_TRIANGLES ||
m_geometryType == GeometryType::TRIANGLES)
{
/* Cell == Six triangles forming a cube
*
* Lower-case characters: vertices with Z == Z2
* Upper-case characters: vertices with Z == Z1
g h
C D
e f
A B
*/
const auto A = tcu::Vec3( cellX1Y1Z1.x(),
cellX1Y1Z1.y(),
cellX1Y1Z1.z() );
const auto B = tcu::Vec3( cellX2Y2Z2.x(),
cellX1Y1Z1.y(),
cellX1Y1Z1.z() );
const auto C = tcu::Vec3( cellX1Y1Z1.x(),
cellX2Y2Z2.y(),
cellX1Y1Z1.z() );
const auto D = tcu::Vec3( cellX2Y2Z2.x(),
cellX2Y2Z2.y(),
cellX1Y1Z1.z() );
const auto E = tcu::Vec3( cellX1Y1Z1.x(),
cellX1Y1Z1.y(),
cellX2Y2Z2.z() );
const auto F = tcu::Vec3( cellX2Y2Z2.x(),
cellX1Y1Z1.y(),
cellX2Y2Z2.z() );
const auto G = tcu::Vec3( cellX1Y1Z1.x(),
cellX2Y2Z2.y(),
cellX2Y2Z2.z() );
const auto H = tcu::Vec3( cellX2Y2Z2.x(),
cellX2Y2Z2.y(),
cellX2Y2Z2.z() );
// Z = Z1 face
m_triVertexVec.push_back(A);
m_triVertexVec.push_back(C);
m_triVertexVec.push_back(D);
m_triVertexVec.push_back(D);
m_triVertexVec.push_back(B);
m_triVertexVec.push_back(A);
// Z = Z2 face
m_triVertexVec.push_back(E);
m_triVertexVec.push_back(H);
m_triVertexVec.push_back(G);
m_triVertexVec.push_back(H);
m_triVertexVec.push_back(E);
m_triVertexVec.push_back(F);
// X = X0 face
m_triVertexVec.push_back(A);
m_triVertexVec.push_back(G);
m_triVertexVec.push_back(C);
m_triVertexVec.push_back(G);
m_triVertexVec.push_back(A);
m_triVertexVec.push_back(E);
// X = X1 face
m_triVertexVec.push_back(B);
m_triVertexVec.push_back(D);
m_triVertexVec.push_back(H);
m_triVertexVec.push_back(H);
m_triVertexVec.push_back(F);
m_triVertexVec.push_back(B);
// Y = Y0 face
m_triVertexVec.push_back(C);
m_triVertexVec.push_back(H);
m_triVertexVec.push_back(D);
m_triVertexVec.push_back(H);
m_triVertexVec.push_back(C);
m_triVertexVec.push_back(G);
// Y = y1 face
m_triVertexVec.push_back(A);
m_triVertexVec.push_back(B);
m_triVertexVec.push_back(E);
m_triVertexVec.push_back(B);
m_triVertexVec.push_back(F);
m_triVertexVec.push_back(E);
}
}
}
std::vector<tcu::Vec3> m_aabbVertexVec;
std::vector<tcu::Vec3> m_triVertexVec;
GeometryType m_geometryType;
tcu::Vec3 m_gridCellSizeXYZ;
tcu::Vec3 m_gridInterCellDeltaXYZ;
tcu::UVec3 m_gridSizeXYZ;
tcu::Vec3 m_gridStartXYZ;
};
/* Provides an AS holding a single {(0, 0, 0), (-1, 1, 0), {1, 1, 0} tri. */
class TriASProvider : public ASProviderBase
{
public:
TriASProvider()
{
/* Stub*/
}
std::unique_ptr<TopLevelAccelerationStructure> createTLAS( Context& context,
const AccelerationStructureLayout& /* asLayout */,
VkCommandBuffer cmdBuffer,
const VkGeometryFlagsKHR& bottomLevelGeometryFlags,
const ASPropertyProvider* optASPropertyProviderPtr,
IGridASFeedback* /* optASFeedbackPtr */) const final
{
Allocator& allocator = context.getDefaultAllocator ();
const DeviceInterface& deviceInterface = context.getDeviceInterface ();
const VkDevice deviceVk = context.getDevice ();
std::unique_ptr<TopLevelAccelerationStructure> resultPtr;
de::MovePtr<TopLevelAccelerationStructure> tlPtr = makeTopLevelAccelerationStructure ();
{
const auto cullMask = (optASPropertyProviderPtr != nullptr) ? optASPropertyProviderPtr->getCullMask(0, 0)
: static_cast<deUint8>(0xFF);
const auto instanceCustomIndex = (optASPropertyProviderPtr != nullptr) ? optASPropertyProviderPtr->getInstanceCustomIndex(0, 0)
: 0;
tlPtr->setInstanceCount(1);
{
de::MovePtr<BottomLevelAccelerationStructure> blPtr = makeBottomLevelAccelerationStructure();
const std::vector<tcu::Vec3> vertexVec = {tcu::Vec3(0, 0, 0), tcu::Vec3(-1, 1, 0), tcu::Vec3(1, 1, 0) };
blPtr->setGeometryCount (1u);
blPtr->addGeometry (vertexVec,
true, /* triangles */
bottomLevelGeometryFlags);
blPtr->createAndBuild( deviceInterface,
deviceVk,
cmdBuffer,
allocator);
tlPtr->addInstance( de::SharedPtr<BottomLevelAccelerationStructure>(blPtr.release() ),
identityMatrix3x4,
instanceCustomIndex,
cullMask);
}
}
tlPtr->createAndBuild( deviceInterface,
deviceVk,
cmdBuffer,
allocator);
resultPtr = decltype(resultPtr)(tlPtr.release() );
return resultPtr;
}
deUint32 getNPrimitives() const final
{
return 1;
}
};
/* Test logic providers ==> */
class TestBase
{
public:
virtual ~TestBase()
{
/* Stub */
}
virtual tcu::UVec3 getDispatchSize () const = 0;
virtual deUint32 getResultBufferSize () const = 0;
virtual std::vector<TopLevelAccelerationStructure*> getTLASPtrVecToBind () const = 0;
virtual void resetTLAS () = 0;
virtual void initAS ( vkt::Context& context,
RayTracingProperties* rtPropertiesPtr,
VkCommandBuffer commandBuffer) = 0;
virtual void initPrograms ( SourceCollections& programCollection) const = 0;
virtual bool verifyResultBuffer ( const void* inBufferPtr) const = 0;
virtual std::vector<std::string> getAHitShaderCollectionShaderNames() const
{
return {"ahit"};
}
virtual deUint32 getASBindingArraySize() const
{
return 1u;
}
virtual std::vector<std::string> getCallableShaderCollectionNames() const
{
return std::vector<std::string>{};
}
virtual std::vector<std::string> getCHitShaderCollectionShaderNames() const
{
return {"chit"};
}
virtual deUint32 getDynamicStackSize(deUint32 maxPipelineRayRecursionDepth) const
{
DE_ASSERT(false);
DE_UNREF(maxPipelineRayRecursionDepth);
return 0;
}
virtual std::vector<std::string> getIntersectionShaderCollectionShaderNames() const
{
return {"intersection"};
}
virtual deUint32 getMaxRecursionDepthUsed() const
{
return 1;
}
virtual std::vector<std::string> getMissShaderCollectionShaderNames() const
{
return {"miss"};
}
virtual deUint32 getNTraceRayInvocationsNeeded() const
{
return 1;
}
virtual Move<VkPipelineLayout> getPipelineLayout(const vk::DeviceInterface& deviceInterface,
VkDevice deviceVk,
VkDescriptorSetLayout descriptorSetLayout)
{
return makePipelineLayout( deviceInterface,
deviceVk,
descriptorSetLayout);
}
virtual std::vector<deUint8> getResultBufferStartData() const
{
return std::vector<deUint8>();
}
virtual const void* getShaderRecordData(const ShaderGroups& /* shaderGroup */) const
{
return nullptr;
}
virtual deUint32 getShaderRecordSize(const ShaderGroups& /* shaderGroup */) const
{
return 0;
}
virtual VkSpecializationInfo* getSpecializationInfoPtr(const VkShaderStageFlagBits& /* shaderStage */)
{
return nullptr;
}
virtual bool init( vkt::Context& /* context */,
RayTracingProperties* /* rtPropsPtr */)
{
return true;
}
virtual void onBeforeCmdTraceRays( const deUint32& /* nDispatch */,
vkt::Context& /* context */,
VkCommandBuffer /* commandBuffer */,
VkPipelineLayout /* pipelineLayout */)
{
/* Stub */
}
virtual void onShaderStackSizeDiscovered( const VkDeviceSize& /* raygenShaderStackSize */,
const VkDeviceSize& /* ahitShaderStackSize */,
const VkDeviceSize& /* chitShaderStackSize */,
const VkDeviceSize& /* missShaderStackSize */,
const VkDeviceSize& /* callableShaderStackSize */,
const VkDeviceSize& /* isectShaderStackSize */)
{
/* Stub */
}
virtual bool usesDynamicStackSize() const
{
return false;
}
};
class AABBTriTLTest : public TestBase,
public ASPropertyProvider
{
public:
AABBTriTLTest( const GeometryType& geometryType,
const AccelerationStructureLayout& asStructureLayout)
: m_asStructureLayout (asStructureLayout),
m_geometryType (geometryType),
m_gridSize (tcu::UVec3(720, 1, 1) ),
m_lastCustomInstanceIndexUsed (0)
{
}
~AABBTriTLTest()
{
/* Stub */
}
virtual std::vector<std::string> getAHitShaderCollectionShaderNames() const
{
return {"ahit", "ahit"};
}
std::vector<std::string> getCHitShaderCollectionShaderNames() const final
{
return {};
}
deUint32 getInstanceCustomIndex(const deUint32& nBL, const deUint32& nInstance) const final
{
DE_UNREF(nBL);
DE_UNREF(nInstance);
return ++m_lastCustomInstanceIndexUsed;
}
tcu::UVec3 getDispatchSize() const final
{
return tcu::UVec3(m_gridSize[0], m_gridSize[1], m_gridSize[2]);
}
deUint32 getResultBufferSize() const final
{
return static_cast<deUint32>((2 /* nHits, nMisses */ + m_gridSize[0] * m_gridSize[1] * m_gridSize[2] * 1 /* hit instance custom indices */) * sizeof(deUint32) );
}
std::vector<TopLevelAccelerationStructure*> getTLASPtrVecToBind() const final
{
DE_ASSERT(m_tlPtr != nullptr);
return {m_tlPtr.get() };
}
void resetTLAS() final
{
m_tlPtr.reset();
}
void initAS(vkt::Context& context,
RayTracingProperties* /* rtPropertiesPtr */,
VkCommandBuffer commandBuffer) final
{
/* Each AS holds a single unit AABB / cube built of tris.
*
* Geometry in the zeroth acceleration structure starts at the origin. Subsequent ASes
* hold geometry that is positioned so that geometry formed by the union of all ASes never
* intersects.
*
* Each raygen shader invocation uses a unique origin+target pair for the traced ray, and
* only one AS is expected to hold geometry that the ray can find intersection for.
* The AS index is stored in the result buffer, which is later verified by the CPU.
*
* Due to the fact AccelerationStructureEXT array indexing must be dynamically uniform and
* it is not guaranteed we can determine workgroup size on VK 1.1-conformant platforms,
* we can only trace rays against the same AS in a single ray trace dispatch.
*/
std::unique_ptr<GridASProvider> asProviderPtr(
new GridASProvider( tcu::Vec3 (0, 0, 0), /* gridStartXYZ */
tcu::Vec3 (1, 1, 1), /* gridCellSizeXYZ */
m_gridSize,
tcu::Vec3 (3, 0, 0), /* gridInterCellDeltaXYZ */
m_geometryType)
);
m_tlPtr = asProviderPtr->createTLAS( context,
m_asStructureLayout,
commandBuffer,
VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR,
this, /* optASPropertyProviderPtr */
nullptr); /* optASFeedbackPtr */
}
void initPrograms(SourceCollections& programCollection) const final
{
const vk::ShaderBuildOptions buildOptions( programCollection.usedVulkanVersion,
vk::SPIRV_VERSION_1_4,
0u, /* flags */
true); /* allowSpirv14 */
const char* hitPropsDefinition =
"struct HitProps\n"
"{\n"
" uint instanceCustomIndex;\n"
"};\n";
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"hitAttributeEXT vec3 dummyAttribute;\n"
"\n"
+ de::toString(hitPropsDefinition) +
"\n"
"layout(location = 0) rayPayloadInEXT uint dummy;\n"
"layout(set = 0, binding = 0, std430) buffer result\n"
"{\n"
" uint nHitsRegistered;\n"
" uint nMissesRegistered;\n"
" HitProps hits[];\n"
"};\n"
"\n"
"void main()\n"
"{\n"
" uint nHit = atomicAdd(nHitsRegistered, 1);\n"
"\n"
" hits[nHit].instanceCustomIndex = gl_InstanceCustomIndexEXT;\n"
"}\n";
programCollection.glslSources.add("ahit") << glu::AnyHitSource(css.str() ) << buildOptions;
}
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"hitAttributeEXT vec3 hitAttribute;\n"
"\n"
"void main()\n"
"{\n"
" reportIntersectionEXT(0.95f, 0);\n"
"}\n";
programCollection.glslSources.add("intersection") << glu::IntersectionSource(css.str() ) << buildOptions;
}
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
+ de::toString(hitPropsDefinition) +
"\n"
"layout(set = 0, binding = 0, std430) buffer result\n"
"{\n"
" uint nHitsRegistered;\n"
" uint nMissesRegistered;\n"
" HitProps hits[];\n"
"};\n"
"\n"
"layout(location = 0) rayPayloadInEXT uint rayIndex;\n"
"\n"
"void main()\n"
"{\n"
" atomicAdd(nMissesRegistered, 1);\n"
"}\n";
programCollection.glslSources.add("miss") << glu::MissSource(css.str() ) << buildOptions;
}
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"layout(location = 0) rayPayloadEXT uint dummy;\n"
"layout(set = 0, binding = 1) uniform accelerationStructureEXT accelerationStructure;\n"
"\n"
"void main()\n"
"{\n"
" uint nInvocation = gl_LaunchIDEXT.z * gl_LaunchSizeEXT.x * gl_LaunchSizeEXT.y + gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x;\n"
" uint rayFlags = gl_RayFlagsCullBackFacingTrianglesEXT;\n"
" float tmin = 0.001;\n"
" float tmax = 9.0;\n"
"\n"
" uint cullMask = 0xFF;\n"
" vec3 cellStartXYZ = vec3(nInvocation * 3.0, 0.0, 0.0);\n"
" vec3 cellEndXYZ = cellStartXYZ + vec3(1.0);\n"
" vec3 target = mix(cellStartXYZ, cellEndXYZ, vec3(0.5) );\n"
" vec3 origin = target - vec3(0, 2, 0);\n"
" vec3 direct = normalize(target - origin);\n"
"\n"
" traceRayEXT(accelerationStructure, rayFlags, cullMask, 0, 0, 0, origin, tmin, direct, tmax, 0);\n"
"}\n";
programCollection.glslSources.add("rgen") << glu::RaygenSource(css.str() ) << buildOptions;
}
}
bool verifyResultBuffer (const void* resultDataPtr) const final
{
const deUint32* resultU32Ptr = reinterpret_cast<const deUint32*>(resultDataPtr);
bool result = false;
typedef struct
{
deUint32 instanceCustomIndex;
} HitProperties;
std::map<deUint32, deUint32> customInstanceIndexToHitCountMap;
const auto nHitsReported = *resultU32Ptr;
const auto nMissesReported = *(resultU32Ptr + 1);
if (nHitsReported != m_gridSize[0] * m_gridSize[1] * m_gridSize[2])
{
goto end;
}
if (nMissesReported != 0)
{
goto end;
}
for (deUint32 nHit = 0; nHit < nHitsReported; ++nHit)
{
const HitProperties* hitPropsPtr = reinterpret_cast<const HitProperties*>(resultU32Ptr + 2 /* preamble ints */) + nHit;
customInstanceIndexToHitCountMap[hitPropsPtr->instanceCustomIndex]++;
if (customInstanceIndexToHitCountMap[hitPropsPtr->instanceCustomIndex] > 1)
{
goto end;
}
}
for (deUint32 nInstance = 0; nInstance < nHitsReported; ++nInstance)
{
if (customInstanceIndexToHitCountMap.find(1 + nInstance) == customInstanceIndexToHitCountMap.end() )
{
goto end;
}
}
result = true;
end:
return result;
}
private:
const AccelerationStructureLayout m_asStructureLayout;
const GeometryType m_geometryType;
const tcu::UVec3 m_gridSize;
mutable deUint32 m_lastCustomInstanceIndexUsed;
std::unique_ptr<TopLevelAccelerationStructure> m_tlPtr;
};
class ASStressTest : public TestBase,
public ASPropertyProvider
{
public:
ASStressTest( const GeometryType& geometryType,
const AccelerationStructureLayout& asStructureLayout)
: m_asStructureLayout (asStructureLayout),
m_geometryType (geometryType),
m_lastCustomInstanceIndexUsed (0),
m_nASesToUse (0),
m_nMaxASToUse (16u)
{
}
~ASStressTest()
{
/* Stub */
}
deUint32 getASBindingArraySize() const final
{
DE_ASSERT(m_nASesToUse != 0);
return m_nASesToUse;
}
std::vector<std::string> getCHitShaderCollectionShaderNames() const final
{
return {};
}
deUint32 getInstanceCustomIndex(const deUint32& nBL, const deUint32& nInstance) const final
{
DE_UNREF(nBL);
DE_UNREF(nInstance);
return ++m_lastCustomInstanceIndexUsed;
}
tcu::UVec3 getDispatchSize() const final
{
return tcu::UVec3(1, 1, 1);
}
deUint32 getNTraceRayInvocationsNeeded() const final
{
return m_nMaxASToUse;
}
deUint32 getResultBufferSize() const final
{
return static_cast<deUint32>((2 /* nHits, nMisses */ + 2 * m_nMaxASToUse /* hit instance custom indices + AS index */) * sizeof(deUint32) );
}
std::vector<TopLevelAccelerationStructure*> getTLASPtrVecToBind() const final
{
std::vector<TopLevelAccelerationStructure*> resultVec;
DE_ASSERT(m_tlPtrVec.size() != 0);
for (auto& currentTLPtr : m_tlPtrVec)
{
resultVec.push_back(currentTLPtr.get() );
}
return resultVec;
}
void resetTLAS() final
{
for (auto& currentTLPtr : m_tlPtrVec)
{
currentTLPtr.reset();
}
}
bool init( vkt::Context& /* context */,
RayTracingProperties* rtPropertiesPtr) final
{
/* NOTE: We clamp the number below to a sensible value, in case the implementation has no restrictions on the number of
* ASes accessible to shaders.
*/
m_nASesToUse = std::min(rtPropertiesPtr->getMaxDescriptorSetAccelerationStructures(),
m_nMaxASToUse);
return true;
}
void initAS(vkt::Context& context,
RayTracingProperties* /* rtPropertiesPtr */,
VkCommandBuffer commandBuffer) final
{
/* Each AS holds a single unit AABB / cube built of tris.
*
* Geometry in the zeroth acceleration structure starts at the origin. Subsequent ASes
* hold geometry that is positioned so that geometry formed by the union of all ASes never
* intersects.
*
* Each raygen shader invocation uses a unique origin+target pair for the traced ray, and
* only one AS is expected to hold geometry that the ray can find intersection for.
* The AS index is stored in the result buffer, which is later verified by the CPU.
*
* Due to the fact AccelerationStructureEXT array indexing must be dynamically uniform and
* it is not guaranteed we can determine workgroup size on VK 1.1-conformant platforms,
* we can only trace rays against the same AS in a single ray trace dispatch.
*/
std::unique_ptr<GridASProvider> asProviderPtr(
new GridASProvider( tcu::Vec3 (0, 0, 0), /* gridStartXYZ */
tcu::Vec3 (1, 1, 1), /* gridCellSizeXYZ */
tcu::UVec3(1, 1, 1), /* gridSizeXYZ */
tcu::Vec3 (0, 0, 0), /* gridInterCellDeltaXYZ */
m_geometryType)
);
for (deUint32 nAS = 0; nAS < m_nASesToUse; ++nAS)
{
const auto origin = tcu::Vec3(3.0f * static_cast<float>(nAS), 0.0f, 0.0f);
asProviderPtr->setProperties(
origin,
tcu::Vec3(1, 1, 1), /* gridCellSizeXYZ */
tcu::UVec3(1, 1, 1), /* gridSizeXYZ */
tcu::Vec3(0, 0, 0), /* gridInterCellDeltaXYZ */
m_geometryType
);
auto tlPtr = asProviderPtr->createTLAS( context,
m_asStructureLayout,
commandBuffer,
VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR,
this, /* optASPropertyProviderPtr */
nullptr); /* optASFeedbackPtr */
m_tlPtrVec.push_back(std::move(tlPtr) );
}
}
void initPrograms(SourceCollections& programCollection) const final
{
const vk::ShaderBuildOptions buildOptions( programCollection.usedVulkanVersion,
vk::SPIRV_VERSION_1_4,
0u, /* flags */
true); /* allowSpirv14 */
const char* hitPropsDefinition =
"struct HitProps\n"
"{\n"
" uint instanceCustomIndex;\n"
" uint nAS;\n"
"};\n";
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"hitAttributeEXT vec3 dummyAttribute;\n"
"\n"
+ de::toString(hitPropsDefinition) +
"\n"
"layout(location = 0) rayPayloadInEXT uint nAS;\n"
"layout(set = 0, binding = 0, std430) buffer result\n"
"{\n"
" uint nHitsRegistered;\n"
" uint nMissesRegistered;\n"
" HitProps hits[];\n"
"};\n"
"\n"
"void main()\n"
"{\n"
" uint nHit = atomicAdd(nHitsRegistered, 1);\n"
"\n"
" hits[nHit].instanceCustomIndex = gl_InstanceCustomIndexEXT;\n"
" hits[nHit].nAS = nAS;\n"
"}\n";
programCollection.glslSources.add("ahit") << glu::AnyHitSource(css.str() ) << buildOptions;
}
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"hitAttributeEXT vec3 hitAttribute;\n"
"\n"
"void main()\n"
"{\n"
" reportIntersectionEXT(0.95f, 0);\n"
"}\n";
programCollection.glslSources.add("intersection") << glu::IntersectionSource(css.str() ) << buildOptions;
}
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
+ de::toString(hitPropsDefinition) +
"\n"
"layout(set = 0, binding = 0, std430) buffer result\n"
"{\n"
" uint nHitsRegistered;\n"
" uint nMissesRegistered;\n"
" HitProps hits[];\n"
"};\n"
"\n"
"layout(location = 0) rayPayloadInEXT uint rayIndex;\n"
"\n"
"void main()\n"
"{\n"
" atomicAdd(nMissesRegistered, 1);\n"
"}\n";
programCollection.glslSources.add("miss") << glu::MissSource(css.str() ) << buildOptions;
}
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"layout(push_constant) uniform pcUB\n"
"{\n"
" uint nAS;\n"
"} ub;\n"
"\n"
"layout(location = 0) rayPayloadEXT uint payload;\n"
"layout(set = 0, binding = 1) uniform accelerationStructureEXT accelerationStructures[" + de::toString(m_nMaxASToUse) + "];\n"
"\n"
"void main()\n"
"{\n"
" uint nInvocation = gl_LaunchIDEXT.z * gl_LaunchSizeEXT.x * gl_LaunchSizeEXT.y + gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x;\n"
" uint rayFlags = gl_RayFlagsCullBackFacingTrianglesEXT;\n"
" float tmin = 0.001;\n"
" float tmax = 9.0;\n"
"\n"
" uint cullMask = 0xFF;\n"
" vec3 cellStartXYZ = vec3(ub.nAS * 3.0, 0.0, 0.0);\n"
" vec3 cellEndXYZ = cellStartXYZ + vec3(1.0);\n"
" vec3 target = mix(cellStartXYZ, cellEndXYZ, vec3(0.5) );\n"
" vec3 origin = target - vec3(0, 2, 0);\n"
" vec3 direct = normalize(target - origin);\n"
"\n"
" payload = ub.nAS;\n"
"\n"
" traceRayEXT(accelerationStructures[ub.nAS], rayFlags, cullMask, 0, 0, 0, origin, tmin, direct, tmax, 0);\n"
"}\n";
programCollection.glslSources.add("rgen") << glu::RaygenSource(css.str() ) << buildOptions;
}
}
Move<VkPipelineLayout> getPipelineLayout( const vk::DeviceInterface& deviceInterface,
VkDevice deviceVk,
VkDescriptorSetLayout descriptorSetLayout) final
{
VkPushConstantRange pushConstantRange;
pushConstantRange.offset = 0;
pushConstantRange.size = sizeof(deUint32);
pushConstantRange.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_KHR;
return makePipelineLayout( deviceInterface,
deviceVk,
1, /* setLayoutCount */
&descriptorSetLayout,
1, /* pushRangeCount */
&pushConstantRange);
}
void onBeforeCmdTraceRays( const deUint32& nDispatch,
vkt::Context& context,
VkCommandBuffer commandBuffer,
VkPipelineLayout pipelineLayout) final
{
/* No need for a sync point in-between trace ray commands - all writes are atomic */
VkMemoryBarrier memBarrier;
memBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
memBarrier.pNext = nullptr;
memBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
memBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
context.getDeviceInterface().cmdPipelineBarrier(commandBuffer,
VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, /* srcStageMask */
VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, /* dstStageMask */
0, /* dependencyFlags */
1, /* memoryBarrierCount */
&memBarrier,
0, /* bufferMemoryBarrierCount */
nullptr, /* pBufferMemoryBarriers */
0, /* imageMemoryBarrierCount */
nullptr); /* pImageMemoryBarriers */
context.getDeviceInterface().cmdPushConstants( commandBuffer,
pipelineLayout,
VK_SHADER_STAGE_RAYGEN_BIT_KHR,
0, /* offset */
sizeof(deUint32),
&nDispatch);
}
bool verifyResultBuffer (const void* resultDataPtr) const final
{
const deUint32* resultU32Ptr = reinterpret_cast<const deUint32*>(resultDataPtr);
bool result = false;
typedef struct
{
deUint32 instanceCustomIndex;
deUint32 nAS;
} HitProperties;
const auto nHitsReported = *resultU32Ptr;
const auto nMissesReported = *(resultU32Ptr + 1);
if (nHitsReported != m_nMaxASToUse)
{
goto end;
}
if (nMissesReported != 0)
{
goto end;
}
for (deUint32 nHit = 0; nHit < nHitsReported; ++nHit)
{
const HitProperties* hitPropsPtr = reinterpret_cast<const HitProperties*>(resultU32Ptr + 2 /* preamble ints */) + nHit;
if (hitPropsPtr->instanceCustomIndex != (nHit + 1) )
{
goto end;
}
if (hitPropsPtr->nAS != nHit)
{
goto end;
}
}
result = true;
end:
return result;
}
private:
const AccelerationStructureLayout m_asStructureLayout;
const GeometryType m_geometryType;
mutable deUint32 m_lastCustomInstanceIndexUsed;
deUint32 m_nASesToUse;
std::vector<std::unique_ptr<TopLevelAccelerationStructure> > m_tlPtrVec;
const deUint32 m_nMaxASToUse;
};
class CallableShaderStressTest: public TestBase
{
public:
CallableShaderStressTest( const GeometryType& geometryType,
const AccelerationStructureLayout& asStructureLayout,
const bool& useDynamicStackSize)
: m_asStructureLayout (asStructureLayout),
m_geometryType (geometryType),
m_gridSizeXYZ (tcu::UVec3 (128, 1, 1) ),
m_nMaxCallableLevels ( (useDynamicStackSize) ? 8
: 2 /* as per spec */),
m_useDynamicStackSize (useDynamicStackSize),
m_ahitShaderStackSize (0),
m_callableShaderStackSize (0),
m_chitShaderStackSize (0),
m_isectShaderStackSize (0),
m_missShaderStackSize (0),
m_raygenShaderStackSize (0)
{
}
~CallableShaderStressTest()
{
/* Stub */
}
std::vector<std::string> getCallableShaderCollectionNames() const final
{
std::vector<std::string> resultVec(m_nMaxCallableLevels);
for (deUint32 nLevel = 0; nLevel < m_nMaxCallableLevels; nLevel++)
{
resultVec.at(nLevel) = "call" + de::toString(nLevel);
}
return resultVec;
}
tcu::UVec3 getDispatchSize() const final
{
DE_ASSERT(m_gridSizeXYZ[0] != 0);
DE_ASSERT(m_gridSizeXYZ[1] != 0);
DE_ASSERT(m_gridSizeXYZ[2] != 0);
return tcu::UVec3(m_gridSizeXYZ[0], m_gridSizeXYZ[1], m_gridSizeXYZ[2]);
}
deUint32 getDynamicStackSize(const deUint32 maxPipelineRayRecursionDepth) const final
{
deUint32 result = 0;
const auto maxStackSpaceNeededForZerothTrace = static_cast<deUint32>(de::max(de::max(m_chitShaderStackSize, m_missShaderStackSize), m_isectShaderStackSize + m_ahitShaderStackSize) );
const auto maxStackSpaceNeededForNonZerothTraces = static_cast<deUint32>(de::max(m_chitShaderStackSize, m_missShaderStackSize) );
DE_ASSERT(m_useDynamicStackSize);
result = static_cast<deUint32>(m_raygenShaderStackSize) +
de::min(1u, maxPipelineRayRecursionDepth) * maxStackSpaceNeededForZerothTrace +
de::max(0u, maxPipelineRayRecursionDepth - 1) * maxStackSpaceNeededForNonZerothTraces +
m_nMaxCallableLevels * static_cast<deUint32>(m_callableShaderStackSize);
DE_ASSERT(result != 0);
return result;
}
deUint32 getResultBufferSize() const final
{
const auto nRaysTraced = m_gridSizeXYZ[0] * m_gridSizeXYZ[1] * m_gridSizeXYZ[2];
const auto nClosestHitShaderInvocationsExpected = nRaysTraced / 2;
const auto nMissShaderInvocationsExpected = nRaysTraced / 2;
const auto resultItemSize = sizeof(deUint32) * 3 /* shaderStage, nOriginRay, nLevel */ + sizeof(float) * m_nMaxCallableLevels;
DE_ASSERT((nRaysTraced % 2) == 0);
DE_ASSERT(m_nMaxCallableLevels != 0);
DE_ASSERT(m_gridSizeXYZ[0] != 0);
DE_ASSERT(m_gridSizeXYZ[1] != 0);
DE_ASSERT(m_gridSizeXYZ[2] != 0);
return static_cast<deUint32>(sizeof(deUint32) /* nItemsStored */ + (resultItemSize * m_nMaxCallableLevels) * (nRaysTraced + nMissShaderInvocationsExpected + nClosestHitShaderInvocationsExpected) );
}
std::vector<TopLevelAccelerationStructure*> getTLASPtrVecToBind() const final
{
DE_ASSERT(m_tlPtr != nullptr);
return {m_tlPtr.get() };
}
bool init( vkt::Context& /* context */,
RayTracingProperties* rtPropertiesPtr) final
{
DE_UNREF(rtPropertiesPtr);
return true;
}
void initAS(vkt::Context& context,
RayTracingProperties* /* rtPropertiesPtr */,
VkCommandBuffer commandBuffer) final
{
std::unique_ptr<GridASProvider> asProviderPtr(
new GridASProvider( tcu::Vec3 (0, 0, 0), /* gridStartXYZ */
tcu::Vec3 (1, 1, 1), /* gridCellSizeXYZ */
m_gridSizeXYZ,
tcu::Vec3 (6, 0, 0), /* gridInterCellDeltaXYZ */
m_geometryType)
);
m_tlPtr = asProviderPtr->createTLAS( context,
m_asStructureLayout,
commandBuffer,
0, /* bottomLevelGeometryFlags */
nullptr, /* optASPropertyProviderPtr */
nullptr); /* optASFeedbackPtr */
}
void initPrograms(SourceCollections& programCollection) const final
{
const vk::ShaderBuildOptions buildOptions( programCollection.usedVulkanVersion,
vk::SPIRV_VERSION_1_4,
0u, /* flags */
true); /* allowSpirv14 */
std::vector<std::string> callableDataDefinitions (m_nMaxCallableLevels);
std::vector<std::string> callableDataInDefinitions (m_nMaxCallableLevels);
for (deUint32 nCallableDataLevel = 0; nCallableDataLevel < m_nMaxCallableLevels; ++nCallableDataLevel)
{
const auto locationsPerCallableData = (3 /* uints */ + (nCallableDataLevel + 1) /* dataChunks */);
const auto callableDataLocation = locationsPerCallableData * nCallableDataLevel;
callableDataDefinitions.at(nCallableDataLevel) =
"layout (location = " + de::toString(callableDataLocation) + ") callableDataEXT struct\n"
"{\n"
" uint shaderStage;\n"
" uint nOriginRay;\n"
" uint nLevel;\n"
" float dataChunk[" + de::toString(nCallableDataLevel + 1) + "];\n"
"} callableData" + de::toString(nCallableDataLevel) + ";\n";
callableDataInDefinitions.at(nCallableDataLevel) =
"layout(location = " + de::toString(callableDataLocation) + ") callableDataInEXT struct\n"
"{\n"
" uint shaderStage;\n"
" uint nOriginRay;\n"
" uint nLevel;\n"
" float dataChunk[" + de::toString(nCallableDataLevel + 1) + "];\n"
"} inData;\n";
m_callableDataLevelToCallableDataLocation[nCallableDataLevel] = callableDataLocation;
}
const auto resultBufferDefinition =
"struct ResultData\n"
"{\n"
" uint shaderStage;\n"
" uint nOriginRay;\n"
" uint nLevel;\n"
" float dataChunk[" + de::toString(m_nMaxCallableLevels) + "];\n"
"};\n"
"\n"
"layout(set = 0, binding = 0, std430) buffer result\n"
"{\n"
" uint nInvocationsRegistered;\n"
" ResultData resultData[];\n"
"};\n";
{
std::stringstream css;
/* NOTE: executeCallable() is unavailable in ahit stage */
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"layout(location = 128) rayPayloadInEXT uint dummy;\n"
"\n"
"void main()\n"
"{\n"
"}\n";
programCollection.glslSources.add("ahit") << glu::AnyHitSource(css.str() ) << buildOptions;
}
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"layout(location = 128) rayPayloadInEXT uint rayIndex;\n"
"\n" +
de::toString(callableDataDefinitions.at(0) ) +
de::toString(resultBufferDefinition) +
"void main()\n"
"{\n"
" uint nInvocation = gl_LaunchIDEXT.z * gl_LaunchSizeEXT.x * gl_LaunchSizeEXT.y + gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x;\n"
"\n"
" callableData0.shaderStage = 3;\n"
" callableData0.nOriginRay = nInvocation;\n"
" callableData0.nLevel = 0;\n"
" callableData0.dataChunk[0] = float(nInvocation);\n"
"\n"
" executeCallableEXT(0 /* sbtRecordIndex */, " + de::toString(m_callableDataLevelToCallableDataLocation.at(0) ) + ");\n"
"}\n";
programCollection.glslSources.add("chit") << glu::ClosestHitSource(css.str() ) << buildOptions;
}
{
std::stringstream css;
/* NOTE: executeCallable() is unavailable in isect stage */
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"void main()\n"
"{\n"
" reportIntersectionEXT(0.95f, 0);\n"
"}\n";
programCollection.glslSources.add("intersection") << glu::IntersectionSource(css.str() ) << buildOptions;
}
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n" +
de::toString(callableDataDefinitions.at(0) ) +
de::toString(resultBufferDefinition) +
"\n"
"void main()\n"
"{\n"
" uint nInvocation = gl_LaunchIDEXT.z * gl_LaunchSizeEXT.x * gl_LaunchSizeEXT.y + gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x;\n"
"\n"
" callableData0.shaderStage = 2;\n"
" callableData0.nOriginRay = nInvocation;\n"
" callableData0.nLevel = 0;\n"
" callableData0.dataChunk[0] = float(nInvocation);\n"
"\n"
" executeCallableEXT(0 /* sbtRecordIndex */, " + de::toString(m_callableDataLevelToCallableDataLocation.at(0) ) + ");\n"
"}\n";
programCollection.glslSources.add("miss") << glu::MissSource(css.str() ) << buildOptions;
}
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
+ de::toString(callableDataDefinitions.at(0) ) +
"layout(location = 128) rayPayloadEXT uint dummy;\n"
"layout(set = 0, binding = 1) uniform accelerationStructureEXT accelerationStructure;\n"
"\n"
"void main()\n"
"{\n"
" uint nInvocation = gl_LaunchIDEXT.z * gl_LaunchSizeEXT.x * gl_LaunchSizeEXT.y + gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x;\n"
" uint rayFlags = 0;\n"
" float tmin = 0.001;\n"
" float tmax = 9.0;\n"
"\n"
" uint cullMask = 0xFF;\n"
" vec3 cellStartXYZ = vec3(nInvocation * 3.0, 0.0, 0.0);\n"
" vec3 cellEndXYZ = cellStartXYZ + vec3(1.0);\n"
" vec3 target = mix(cellStartXYZ, cellEndXYZ, vec3(0.5) );\n"
" vec3 origin = target - vec3(0, 2, 0);\n"
" vec3 direct = normalize(target - origin);\n"
"\n"
" callableData0.shaderStage = 0;\n"
" callableData0.nOriginRay = nInvocation;\n"
" callableData0.nLevel = 0;\n"
" callableData0.dataChunk[0] = float(nInvocation);\n"
"\n"
" executeCallableEXT(0 /* sbtRecordIndex */, " + de::toString(m_callableDataLevelToCallableDataLocation.at(0) ) + ");\n"
"\n"
" traceRayEXT(accelerationStructure, rayFlags, cullMask, 0, 0, 0, origin, tmin, direct, tmax, 128);\n"
"}\n";
programCollection.glslSources.add("rgen") << glu::RaygenSource(css.str() ) << buildOptions;
}
for (deUint32 nCallableShader = 0; nCallableShader < m_nMaxCallableLevels; ++nCallableShader)
{
const bool canInvokeExecutable = (nCallableShader != (m_nMaxCallableLevels - 1) );
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
+ de::toString(resultBufferDefinition);
if ((nCallableShader + 1) != m_nMaxCallableLevels)
{
css << de::toString(callableDataDefinitions.at(nCallableShader + 1) );
}
css <<
callableDataInDefinitions[nCallableShader] +
"\n"
"void main()\n"
"{\n"
" uint nInvocation = atomicAdd(nInvocationsRegistered, 1);\n"
"\n"
" resultData[nInvocation].shaderStage = inData.shaderStage;\n"
" resultData[nInvocation].nOriginRay = inData.nOriginRay;\n"
" resultData[nInvocation].nLevel = inData.nLevel;\n";
for (deUint32 nLevel = 0; nLevel < nCallableShader + 1; ++nLevel)
{
css <<
" resultData[nInvocation].dataChunk[" + de::toString(nLevel) + "] = inData.dataChunk[" + de::toString(nLevel) + "];\n";
}
if (canInvokeExecutable)
{
css <<
"\n"
" callableData" + de::toString(nCallableShader + 1) + ".shaderStage = 1;\n"
" callableData" + de::toString(nCallableShader + 1) + ".nOriginRay = inData.nOriginRay;\n"
" callableData" + de::toString(nCallableShader + 1) + ".nLevel = " + de::toString(nCallableShader) + ";\n"
"\n";
for (deUint32 nLevel = 0; nLevel <= nCallableShader + 1; ++nLevel)
{
css <<
" callableData" + de::toString(nCallableShader + 1) + ".dataChunk[" + de::toString(nLevel) + "] = float(inData.nOriginRay + " + de::toString(nLevel) + ");\n";
}
css <<
"\n"
" executeCallableEXT(" + de::toString(nCallableShader + 1) + ", " + de::toString(m_callableDataLevelToCallableDataLocation[nCallableShader + 1]) + ");\n";
}
css <<
"\n"
"};\n";
programCollection.glslSources.add("call" + de::toString(nCallableShader) ) << glu::CallableSource(css.str() ) << buildOptions;
}
}
void onShaderStackSizeDiscovered( const VkDeviceSize& raygenShaderStackSize,
const VkDeviceSize& ahitShaderStackSize,
const VkDeviceSize& chitShaderStackSize,
const VkDeviceSize& missShaderStackSize,
const VkDeviceSize& callableShaderStackSize,
const VkDeviceSize& isectShaderStackSize) final
{
m_ahitShaderStackSize = ahitShaderStackSize;
m_callableShaderStackSize = callableShaderStackSize;
m_chitShaderStackSize = chitShaderStackSize;
m_isectShaderStackSize = isectShaderStackSize;
m_missShaderStackSize = missShaderStackSize;
m_raygenShaderStackSize = raygenShaderStackSize;
}
void resetTLAS() final
{
m_tlPtr.reset();
}
bool usesDynamicStackSize() const final
{
return m_useDynamicStackSize;
}
bool verifyResultBuffer (const void* resultDataPtr) const final
{
const deUint32* resultU32Ptr = reinterpret_cast<const deUint32*>(resultDataPtr);
bool result = false;
const auto nItemsStored = *resultU32Ptr;
/* Convert raw binary data into a human-readable vector representation */
struct ResultItem
{
VkShaderStageFlagBits shaderStage;
deUint32 nLevel;
std::vector<float> dataChunk;
ResultItem()
: shaderStage (VK_SHADER_STAGE_ALL),
nLevel (0)
{
/* Stub */
}
};
std::map<deUint32, std::vector<ResultItem> > nRayToResultItemVecMap;
for (deUint32 nItem = 0; nItem < nItemsStored; ++nItem)
{
const deUint32* itemDataPtr = resultU32Ptr + 1 /* nItemsStored */ + nItem * (3 /* preamble ints */ + m_nMaxCallableLevels /* received data */);
ResultItem item;
const auto& nOriginRay = *(itemDataPtr + 1);
item.dataChunk.resize(m_nMaxCallableLevels);
switch (*itemDataPtr)
{
case 0: item.shaderStage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; break;
case 1: item.shaderStage = VK_SHADER_STAGE_CALLABLE_BIT_KHR; break;
case 2: item.shaderStage = VK_SHADER_STAGE_MISS_BIT_KHR; break;
case 3: item.shaderStage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; break;
default:
{
deAssertFail("This should never happen", __FILE__, __LINE__);
}
}
item.nLevel = *(itemDataPtr + 2);
memcpy( item.dataChunk.data(),
itemDataPtr + 3,
m_nMaxCallableLevels * sizeof(float) );
nRayToResultItemVecMap[nOriginRay].push_back(item);
}
for (deUint32 nRay = 0; nRay < m_gridSizeXYZ[0] * m_gridSizeXYZ[1] * m_gridSizeXYZ[2]; ++nRay)
{
/* 1. Make sure each ray generated the anticipated number of stores */
const bool closestHitShaderInvoked = (nRay % 2) == 0;
const bool missShaderInvoked = (nRay % 2) != 0;
const deUint32 nShaderStagesInvokingCallables = 1 + /* raygen */
((closestHitShaderInvoked) ? 1 : 0) +
((missShaderInvoked) ? 1 : 0);
auto rayIterator = nRayToResultItemVecMap.find(nRay);
if (rayIterator == nRayToResultItemVecMap.end())
{
goto end;
}
if (rayIterator->second.size() != nShaderStagesInvokingCallables * m_nMaxCallableLevels)
{
goto end;
}
/* 2. Make sure each shader stage generated the anticipated number of result items */
{
deUint32 nCallableShaderStageItemsFound = 0;
deUint32 nClosestHitShaderStageItemsFound = 0;
deUint32 nMissShaderStageItemsFound = 0;
deUint32 nRaygenShaderStageItemsFound = 0;
for (const auto& currentItem : rayIterator->second)
{
if (currentItem.shaderStage == VK_SHADER_STAGE_RAYGEN_BIT_KHR)
{
nRaygenShaderStageItemsFound++;
}
else
if (currentItem.shaderStage == VK_SHADER_STAGE_CALLABLE_BIT_KHR)
{
nCallableShaderStageItemsFound ++;
}
else
if (currentItem.shaderStage == VK_SHADER_STAGE_MISS_BIT_KHR)
{
nMissShaderStageItemsFound ++;
}
else
if (currentItem.shaderStage == VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR)
{
nClosestHitShaderStageItemsFound ++;
}
else
{
DE_ASSERT(false);
}
}
if (nRaygenShaderStageItemsFound != 1)
{
goto end;
}
/* Even rays hit geometry. Odd ones don't */
if (!missShaderInvoked)
{
if (nClosestHitShaderStageItemsFound == 0)
{
goto end;
}
if (nMissShaderStageItemsFound != 0)
{
goto end;
}
}
else
{
if (nClosestHitShaderStageItemsFound != 0)
{
goto end;
}
if (nMissShaderStageItemsFound != 1)
{
goto end;
}
}
if (nCallableShaderStageItemsFound != nShaderStagesInvokingCallables * (m_nMaxCallableLevels - 1) )
{
goto end;
}
}
/* 3. Verify data chunk's correctness */
{
for (const auto& currentItem : rayIterator->second)
{
const auto nValidItemsRequired = (currentItem.shaderStage == VK_SHADER_STAGE_RAYGEN_BIT_KHR) ? 1
: (currentItem.shaderStage == VK_SHADER_STAGE_MISS_BIT_KHR) ? 1
: (currentItem.shaderStage == VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR) ? 1
: (currentItem.nLevel + 1);
for (deUint32 nItem = 0; nItem < nValidItemsRequired; ++nItem)
{
if (fabsf(currentItem.dataChunk.at(nItem) - static_cast<float>(nRay + nItem)) > 1e-3f)
{
goto end;
}
}
}
}
/* 4. Verify all shader levels have been reported for relevant shader stages */
{
std::map<VkShaderStageFlagBits, std::vector<deUint32> > shaderStageToLevelVecReportedMap;
for (const auto& currentItem : rayIterator->second)
{
shaderStageToLevelVecReportedMap[currentItem.shaderStage].push_back(currentItem.nLevel);
}
if (shaderStageToLevelVecReportedMap.at(VK_SHADER_STAGE_RAYGEN_BIT_KHR).size() != 1 ||
shaderStageToLevelVecReportedMap.at(VK_SHADER_STAGE_RAYGEN_BIT_KHR).at (0) != 0)
{
goto end;
}
if (closestHitShaderInvoked)
{
if (shaderStageToLevelVecReportedMap.at(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR).size() != 1 ||
shaderStageToLevelVecReportedMap.at(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR).at (0) != 0)
{
goto end;
}
}
else
{
if (shaderStageToLevelVecReportedMap.find(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR) != shaderStageToLevelVecReportedMap.end() )
{
goto end;
}
}
if (missShaderInvoked)
{
if (shaderStageToLevelVecReportedMap.at(VK_SHADER_STAGE_MISS_BIT_KHR).size() != 1 ||
shaderStageToLevelVecReportedMap.at(VK_SHADER_STAGE_MISS_BIT_KHR).at (0) != 0)
{
goto end;
}
}
else
{
if (shaderStageToLevelVecReportedMap.find(VK_SHADER_STAGE_MISS_BIT_KHR) != shaderStageToLevelVecReportedMap.end() )
{
goto end;
}
}
if (shaderStageToLevelVecReportedMap.at(VK_SHADER_STAGE_CALLABLE_BIT_KHR).size() != nShaderStagesInvokingCallables * (m_nMaxCallableLevels - 1))
{
goto end;
}
for (deUint32 nLevel = 0; nLevel < m_nMaxCallableLevels - 1; ++nLevel)
{
const auto& vec = shaderStageToLevelVecReportedMap.at(VK_SHADER_STAGE_CALLABLE_BIT_KHR);
auto vecIterator = std::find(vec.begin (),
vec.end (),
nLevel);
if (vecIterator == vec.end())
{
goto end;
}
}
}
}
result = true;
end:
return result;
}
private:
const AccelerationStructureLayout m_asStructureLayout;
const GeometryType m_geometryType;
const tcu::UVec3 m_gridSizeXYZ;
const deUint32 m_nMaxCallableLevels;
const bool m_useDynamicStackSize;
std::unique_ptr<TopLevelAccelerationStructure> m_tlPtr;
VkDeviceSize m_ahitShaderStackSize;
VkDeviceSize m_callableShaderStackSize;
VkDeviceSize m_chitShaderStackSize;
VkDeviceSize m_isectShaderStackSize;
VkDeviceSize m_missShaderStackSize;
VkDeviceSize m_raygenShaderStackSize;
mutable std::map<deUint32, deUint32> m_callableDataLevelToCallableDataLocation;
};
class CullMaskTest : public TestBase,
public ASPropertyProvider
{
public:
CullMaskTest( const AccelerationStructureLayout& asLayout,
const GeometryType& geometryType,
const bool& useExtraCullMaskBits)
:m_asLayout (asLayout),
m_geometryType (geometryType),
m_nMaxHitsToRegister (256),
m_nRaysPerInvocation (4),
m_useExtraCullMaskBits (useExtraCullMaskBits),
m_lastCustomInstanceIndexUsed (0),
m_nCullMasksUsed (1)
{
/* Stub */
}
~CullMaskTest()
{
/* Stub */
}
std::vector<std::string> getCHitShaderCollectionShaderNames() const final
{
return {};
}
deUint8 getCullMask(const deUint32& nBL, const deUint32& nInstance) const final
{
DE_UNREF(nBL);
DE_UNREF(nInstance);
deUint8 result = (m_nCullMasksUsed++) & 0xFF;
DE_ASSERT(result != 0);
return result;
}
deUint32 getInstanceCustomIndex(const deUint32& nBL, const deUint32& nInstance) const final
{
DE_UNREF(nBL);
DE_UNREF(nInstance);
/* NOTE: The formula below generates a sequence of unique large values. */
deUint32 result = (m_lastCustomInstanceIndexUsed * 7 + 153325) & ((1 << 24) - 1);
if (m_instanceCustomIndexVec.size() <= nInstance)
{
m_instanceCustomIndexVec.resize(nInstance + 1);
}
m_instanceCustomIndexVec [nInstance] = result;
m_lastCustomInstanceIndexUsed = result;
return result;
}
tcu::UVec3 getDispatchSize() const final
{
//< 3*5*17 == 255, which coincidentally is the maximum cull mask value the spec permits.
//<
//< This global WG size is excessively large if m_nRaysPerInvocation > 1 but the raygen shader has
//< a guard condition check that drops extraneous invocations.
return tcu::UVec3(3, 5, 17);
}
deUint32 getResultBufferSize() const final
{
return static_cast<deUint32>((1 + m_nMaxHitsToRegister * 2) * sizeof(deUint32) );
}
std::vector<TopLevelAccelerationStructure*> getTLASPtrVecToBind() const final
{
return {m_tlPtr.get() };
}
void resetTLAS() final
{
m_tlPtr.reset();
}
void initAS(vkt::Context& context,
RayTracingProperties* /* rtPropertiesPtr */,
VkCommandBuffer commandBuffer) final
{
m_asProviderPtr.reset(
new GridASProvider( tcu::Vec3 (0, 0, 0), /* gridStartXYZ */
tcu::Vec3 (1, 1, 1), /* gridCellSizeXYZ */
tcu::UVec3 (3, 5, 17), /* gridSizeXYZ */
tcu::Vec3 (2.0f, 2.0f, 2.0f), /* gridInterCellDeltaXYZ */
m_geometryType)
);
m_tlPtr = m_asProviderPtr->createTLAS( context,
m_asLayout,
commandBuffer,
VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR,
this, /* optASPropertyProviderPtr */
nullptr); /* optASFeedbackPtr */
}
void initPrograms(SourceCollections& programCollection) const final
{
const vk::ShaderBuildOptions buildOptions( programCollection.usedVulkanVersion,
vk::SPIRV_VERSION_1_4,
0u, /* flags */
true); /* allowSpirv14 */
const char* hitPropsDefinition =
"struct HitProps\n"
"{\n"
" uint rayIndex;\n"
" uint instanceCustomIndex;\n"
"};\n";
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"hitAttributeEXT vec3 dummyAttribute;\n"
"\n"
+ de::toString(hitPropsDefinition) +
"\n"
"layout(location = 0) rayPayloadInEXT uint nRay;\n"
"layout(set = 0, binding = 0, std430) buffer result\n"
"{\n"
" uint nHitsRegistered;\n"
" uint nMissesRegistered;\n"
" HitProps hits[];\n"
"};\n"
"\n"
"void main()\n"
"{\n"
" uint nHit = atomicAdd(nHitsRegistered, 1);\n"
"\n"
" if (nHit < " + de::toString(m_nMaxHitsToRegister) + ")\n"
" {\n"
" hits[nHit].rayIndex = nRay;\n"
" hits[nHit].instanceCustomIndex = gl_InstanceCustomIndexEXT;\n"
" }\n"
"}\n";
programCollection.glslSources.add("ahit") << glu::AnyHitSource(css.str() ) << buildOptions;
}
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"hitAttributeEXT vec3 hitAttribute;\n"
"\n"
"void main()\n"
"{\n"
" reportIntersectionEXT(0.95f, 0);\n"
"}\n";
programCollection.glslSources.add("intersection") << glu::IntersectionSource(css.str() ) << buildOptions;
}
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
+ de::toString(hitPropsDefinition) +
"\n"
"layout(set = 0, binding = 0, std430) buffer result\n"
"{\n"
" uint nHitsRegistered;\n"
" uint nMissesRegistered;\n"
" HitProps hits[];\n"
"};\n"
"\n"
"layout(location = 0) rayPayloadInEXT uint rayIndex;\n"
"\n"
"void main()\n"
"{\n"
" atomicAdd(nMissesRegistered, 1);\n"
"}\n";
programCollection.glslSources.add("miss") << glu::MissSource(css.str() ) << buildOptions;
}
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"layout(location = 0) rayPayloadEXT uint rayIndex;\n"
"layout(set = 0, binding = 1) uniform accelerationStructureEXT topLevelAS;\n"
"\n"
"void main()\n"
"{\n"
" const uint nRaysPerInvocation = " + de::toString(m_nRaysPerInvocation) + ";\n"
"\n"
" uint nInvocation = gl_LaunchIDEXT.z * gl_LaunchSizeEXT.x * gl_LaunchSizeEXT.y + gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x;\n"
" uint rayFlags = gl_RayFlagsCullBackFacingTrianglesEXT;\n"
" float tmin = 0.001;\n"
" float tmax = 4.0;\n"
"\n"
" if (nInvocation >= 256 / nRaysPerInvocation)\n"
" {\n"
" return;\n"
" }\n"
"\n"
" for (uint nRay = 0; nRay < nRaysPerInvocation; ++nRay)\n"
" {\n"
" uint cullMask = 1 + nInvocation * nRaysPerInvocation + nRay;\n";
if (m_useExtraCullMaskBits)
{
css << "cullMask |= 0x00FFFFFF;\n";
}
css <<
" uint nCell = nInvocation * nRaysPerInvocation + nRay;\n"
" uvec3 cellXYZ = uvec3(nCell % gl_LaunchSizeEXT.x, (nCell / gl_LaunchSizeEXT.x) % gl_LaunchSizeEXT.y, (nCell / gl_LaunchSizeEXT.x / gl_LaunchSizeEXT.y) % gl_LaunchSizeEXT.z);\n"
" vec3 cellStartXYZ = vec3(cellXYZ) * vec3(2.0);\n"
" vec3 cellEndXYZ = cellStartXYZ + vec3(1.0);\n"
" vec3 target = mix(cellStartXYZ, cellEndXYZ, vec3(0.5) );\n"
" vec3 origin = target - vec3(1, 1, 1);\n"
" vec3 direct = normalize(target - origin);\n"
"\n"
" if (nCell < 255)\n"
" {\n"
" rayIndex = nCell;"
"\n"
" traceRayEXT(topLevelAS, rayFlags, cullMask, 0, 0, 0, origin, tmin, direct, tmax, 0);\n"
" }\n"
" }\n"
"}\n";
programCollection.glslSources.add("rgen") << glu::RaygenSource(css.str() ) << buildOptions;
}
}
bool verifyResultBuffer (const void* resultDataPtr) const final
{
const deUint32* resultU32Ptr = reinterpret_cast<const deUint32*>(resultDataPtr);
const auto nHitsReported = *resultU32Ptr;
const auto nMissesReported = *(resultU32Ptr + 1);
bool result = true;
// For each traced ray:
//
// 1. Exactly one ahit invocation per ray should be reported.
// 2. All hits reported for a ray R should point to a primitive with a valid custom instance index
// 3. The reported custom instance indices must be valid.
std::map<deUint32, std::vector<deUint32> > customInstanceIndexToRayIndexVecMap;
std::map<deUint32, std::vector<deUint32> > rayIndexToCustomInstanceIndexVecMap;
typedef struct
{
deUint32 rayIndex;
deUint32 customInstanceHit;
} HitProperties;
if (nHitsReported != 0xFF)
{
result = false;
goto end;
}
if (nMissesReported != 0)
{
result = false;
goto end;
}
for (deUint32 nHit = 0; nHit < nHitsReported; ++nHit)
{
const HitProperties* hitPropsPtr = reinterpret_cast<const HitProperties*>(resultU32Ptr + 2 /* preamble ints */ + nHit * 2 /* ints per HitProperties item */);
customInstanceIndexToRayIndexVecMap[hitPropsPtr->customInstanceHit].push_back(hitPropsPtr->rayIndex);
rayIndexToCustomInstanceIndexVecMap[hitPropsPtr->rayIndex].push_back (hitPropsPtr->customInstanceHit);
}
if (static_cast<deUint32>(customInstanceIndexToRayIndexVecMap.size()) != nHitsReported)
{
/* Invalid number of unique custom instance indices reported. */
result = false;
goto end;
}
if (static_cast<deUint32>(rayIndexToCustomInstanceIndexVecMap.size()) != nHitsReported)
{
/* Invalid ray indices reported by ahit invocations */
result = false;
goto end;
}
for (const auto& currentItem : customInstanceIndexToRayIndexVecMap)
{
if (currentItem.second.size() != 1)
{
/* More than one ray associated with the same custom instance index */
result = false;
goto end;
}
if (currentItem.second.at(0) > 255)
{
/* Invalid ray index associated with the instance index */
result = false;
goto end;
}
if (std::find( m_instanceCustomIndexVec.begin (),
m_instanceCustomIndexVec.end (),
currentItem.first) == m_instanceCustomIndexVec.end() )
{
/* Invalid custom instance index reported for the ray */
result = false;
goto end;
}
}
end:
return result;
}
private:
const AccelerationStructureLayout m_asLayout;
const GeometryType m_geometryType;
const deUint32 m_nMaxHitsToRegister;
const deUint32 m_nRaysPerInvocation;
const bool m_useExtraCullMaskBits;
mutable std::vector<deUint32> m_instanceCustomIndexVec;
mutable deUint32 m_lastCustomInstanceIndexUsed;
mutable deUint32 m_nCullMasksUsed;
std::unique_ptr<GridASProvider> m_asProviderPtr;
std::unique_ptr<TopLevelAccelerationStructure> m_tlPtr;
};
class MAXRayHitAttributeSizeTest: public TestBase
{
public:
MAXRayHitAttributeSizeTest( const GeometryType& geometryType,
const AccelerationStructureLayout& asStructureLayout)
: m_asStructureLayout (asStructureLayout),
m_geometryType (geometryType),
m_gridSizeXYZ (tcu::UVec3 (512, 1, 1) ),
m_nRayAttributeU32s (0)
{
}
~MAXRayHitAttributeSizeTest()
{
/* Stub */
}
tcu::UVec3 getDispatchSize() const final
{
DE_ASSERT(m_gridSizeXYZ[0] != 0);
DE_ASSERT(m_gridSizeXYZ[1] != 0);
DE_ASSERT(m_gridSizeXYZ[2] != 0);
return tcu::UVec3(m_gridSizeXYZ[0], m_gridSizeXYZ[1], m_gridSizeXYZ[2]);
}
deUint32 getResultBufferSize() const final
{
DE_ASSERT(m_gridSizeXYZ[0] != 0);
DE_ASSERT(m_gridSizeXYZ[1] != 0);
DE_ASSERT(m_gridSizeXYZ[2] != 0);
return static_cast<deUint32>((3 /* nAHits, nCHits, nMisses */ + m_gridSizeXYZ[0] * m_gridSizeXYZ[1] * m_gridSizeXYZ[2] * m_nRayAttributeU32s * 2 /* stages where result data is stored */) * sizeof(deUint32) );
}
VkSpecializationInfo* getSpecializationInfoPtr(const VkShaderStageFlagBits& shaderStage) final
{
VkSpecializationInfo* resultPtr = nullptr;
if (shaderStage == VK_SHADER_STAGE_INTERSECTION_BIT_KHR ||
shaderStage == VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR ||
shaderStage == VK_SHADER_STAGE_ANY_HIT_BIT_KHR)
{
resultPtr = &m_specializationInfo;
}
return resultPtr;
}
std::vector<TopLevelAccelerationStructure*> getTLASPtrVecToBind() const final
{
DE_ASSERT(m_tlPtr != nullptr);
return {m_tlPtr.get() };
}
void resetTLAS() final
{
m_tlPtr.reset();
}
bool init( vkt::Context& /* context */,
RayTracingProperties* rtPropertiesPtr) final
{
const auto maxRayHitAttributeSize = rtPropertiesPtr->getMaxRayHitAttributeSize();
// TODO: If U8s are supported, we could cover the remaining space with these..
m_nRayAttributeU32s = maxRayHitAttributeSize / static_cast<deUint32>(sizeof(deUint32) );
DE_ASSERT(m_nRayAttributeU32s != 0);
m_specializationInfoMapEntry.constantID = 1;
m_specializationInfoMapEntry.offset = 0;
m_specializationInfoMapEntry.size = sizeof(deUint32);
m_specializationInfo.dataSize = sizeof(deUint32);
m_specializationInfo.mapEntryCount = 1;
m_specializationInfo.pData = reinterpret_cast<const void*>(&m_nRayAttributeU32s);
m_specializationInfo.pMapEntries = &m_specializationInfoMapEntry;
return true;
}
void initAS(vkt::Context& context,
RayTracingProperties* /* rtPropertiesPtr */,
VkCommandBuffer commandBuffer) final
{
std::unique_ptr<GridASProvider> asProviderPtr(
new GridASProvider( tcu::Vec3 (0, 0, 0), /* gridStartXYZ */
tcu::Vec3 (1, 1, 1), /* gridCellSizeXYZ */
m_gridSizeXYZ,
tcu::Vec3 (6, 0, 0), /* gridInterCellDeltaXYZ */
m_geometryType)
);
m_tlPtr = asProviderPtr->createTLAS( context,
m_asStructureLayout,
commandBuffer,
0, /* bottomLevelGeometryFlags */
nullptr, /* optASPropertyProviderPtr */
nullptr); /* optASFeedbackPtr */
}
void initPrograms(SourceCollections& programCollection) const final
{
const vk::ShaderBuildOptions buildOptions( programCollection.usedVulkanVersion,
vk::SPIRV_VERSION_1_4,
0u, /* flags */
true); /* allowSpirv14 */
const char* constantDefinitions =
"layout(constant_id = 1) const uint N_UINTS_IN_HIT_ATTRIBUTE = 1;\n";
const char* hitAttributeDefinition =
"\n"
"hitAttributeEXT block\n"
"{\n"
" uint values[N_UINTS_IN_HIT_ATTRIBUTE];\n"
"};\n"
"\n";
const char* resultBufferDefinition =
"layout(set = 0, binding = 0, std430) buffer result\n"
"{\n"
" uint nAHitsRegistered;\n"
" uint nCHitsRegistered;\n"
" uint nMissesRegistered;\n"
" uint retrievedValues[N_UINTS_IN_HIT_ATTRIBUTE];\n"
"};\n";
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
+ de::toString(constantDefinitions)
+ de::toString(hitAttributeDefinition) +
"\n"
"layout(location = 0) rayPayloadInEXT uint dummy;\n"
+ de::toString(resultBufferDefinition) +
"\n"
"void main()\n"
"{\n"
" atomicAdd(nAHitsRegistered, 1);\n"
"\n"
" uint nInvocation = gl_LaunchIDEXT.z * gl_LaunchSizeEXT.x * gl_LaunchSizeEXT.y + gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x;\n"
"\n"
" for (uint nUint = 0; nUint < N_UINTS_IN_HIT_ATTRIBUTE; ++nUint)\n"
" {\n"
" retrievedValues[(2 * nInvocation + 1) * N_UINTS_IN_HIT_ATTRIBUTE + nUint] = values[nUint];\n"
" }\n"
"}\n";
programCollection.glslSources.add("ahit") << glu::AnyHitSource(css.str() ) << buildOptions;
}
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
+ de::toString(constantDefinitions)
+ de::toString(hitAttributeDefinition) +
de::toString(resultBufferDefinition) +
"\n"
"layout(location = 0) rayPayloadInEXT uint rayIndex;\n"
"\n"
"void main()\n"
"{\n"
" atomicAdd(nCHitsRegistered, 1);\n"
"\n"
" uint nInvocation = gl_LaunchIDEXT.z * gl_LaunchSizeEXT.x * gl_LaunchSizeEXT.y + gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x;\n"
"\n"
" for (uint nUint = 0; nUint < N_UINTS_IN_HIT_ATTRIBUTE; ++nUint)\n"
" {\n"
" retrievedValues[(2 * nInvocation + 0) * N_UINTS_IN_HIT_ATTRIBUTE + nUint] = values[nUint];\n"
" }\n"
"}\n";
programCollection.glslSources.add("chit") << glu::ClosestHitSource(css.str() ) << buildOptions;
}
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
+ de::toString(constantDefinitions)
+ de::toString(hitAttributeDefinition) +
de::toString(resultBufferDefinition) +
"\n"
"void main()\n"
"{\n"
" uint nInvocation = gl_LaunchIDEXT.z * gl_LaunchSizeEXT.x * gl_LaunchSizeEXT.y + gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x;\n"
"\n"
" for (uint nUint = 0; nUint < N_UINTS_IN_HIT_ATTRIBUTE; ++nUint)\n"
" {\n"
" values[nUint] = 1 + nInvocation + nUint;\n"
" }\n"
"\n"
" reportIntersectionEXT(0.95f, 0);\n"
"}\n";
programCollection.glslSources.add("intersection") << glu::IntersectionSource(css.str() ) << buildOptions;
}
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
+ de::toString(constantDefinitions)
+ de::toString(resultBufferDefinition) +
"\n"
"void main()\n"
"{\n"
" atomicAdd(nMissesRegistered, 1);\n"
"}\n";
programCollection.glslSources.add("miss") << glu::MissSource(css.str() ) << buildOptions;
}
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"layout(location = 0) rayPayloadEXT uint dummy;\n"
"layout(set = 0, binding = 1) uniform accelerationStructureEXT accelerationStructure;\n"
"\n"
"void main()\n"
"{\n"
" uint nInvocation = gl_LaunchIDEXT.z * gl_LaunchSizeEXT.x * gl_LaunchSizeEXT.y + gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x;\n"
" uint rayFlags = 0;\n"
" float tmin = 0.001;\n"
" float tmax = 9.0;\n"
"\n"
" uint cullMask = 0xFF;\n"
" vec3 cellStartXYZ = vec3(nInvocation * 3.0, 0.0, 0.0);\n"
" vec3 cellEndXYZ = cellStartXYZ + vec3(1.0);\n"
" vec3 target = mix(cellStartXYZ, cellEndXYZ, vec3(0.5) );\n"
" vec3 origin = target - vec3(0, 2, 0);\n"
" vec3 direct = normalize(target - origin);\n"
"\n"
" traceRayEXT(accelerationStructure, rayFlags, cullMask, 0, 0, 0, origin, tmin, direct, tmax, 0);\n"
"}\n";
programCollection.glslSources.add("rgen") << glu::RaygenSource(css.str() ) << buildOptions;
}
}
bool verifyResultBuffer (const void* resultDataPtr) const final
{
const deUint32* resultU32Ptr = reinterpret_cast<const deUint32*>(resultDataPtr);
bool result = false;
const auto nAHitsReported = *resultU32Ptr;
const auto nCHitsRegistered = *(resultU32Ptr + 1);
const auto nMissesRegistered = *(resultU32Ptr + 2);
if (nAHitsReported != m_gridSizeXYZ[0] * m_gridSizeXYZ[1] * m_gridSizeXYZ[2] / 2)
{
goto end;
}
if (nCHitsRegistered != nAHitsReported)
{
goto end;
}
if (nMissesRegistered != nAHitsReported)
{
goto end;
}
for (deUint32 nHit = 0; nHit < nAHitsReported; ++nHit)
{
const deUint32* ahitValues = resultU32Ptr + 3 /* preamble ints */ + (2 * nHit + 0) * m_nRayAttributeU32s;
const deUint32* chitValues = resultU32Ptr + 3 /* preamble ints */ + (2 * nHit + 1) * m_nRayAttributeU32s;
const bool missExpected = (nHit % 2) != 0;
for (deUint32 nValue = 0; nValue < m_nRayAttributeU32s; ++nValue)
{
if (!missExpected)
{
if (ahitValues[nValue] != 1 + nHit + nValue)
{
goto end;
}
if (chitValues[nValue] != 1 + nHit + nValue)
{
goto end;
}
}
else
{
if (ahitValues[nValue] != 0)
{
goto end;
}
if (chitValues[nValue] != 0)
{
goto end;
}
}
}
}
result = true;
end:
return result;
}
private:
const AccelerationStructureLayout m_asStructureLayout;
const GeometryType m_geometryType;
const tcu::UVec3 m_gridSizeXYZ;
deUint32 m_nRayAttributeU32s;
std::unique_ptr<TopLevelAccelerationStructure> m_tlPtr;
VkSpecializationInfo m_specializationInfo;
VkSpecializationMapEntry m_specializationInfoMapEntry;
};
class MAXRTInvocationsSupportedTest : public TestBase,
public ASPropertyProvider,
public IGridASFeedback
{
public:
MAXRTInvocationsSupportedTest( const GeometryType& geometryType,
const AccelerationStructureLayout& asStructureLayout)
: m_asStructureLayout (asStructureLayout),
m_geometryType (geometryType),
m_lastCustomInstanceIndexUsed (0),
m_nMaxCells (8 * 8 * 8)
{
}
~MAXRTInvocationsSupportedTest()
{
/* Stub */
}
std::vector<std::string> getCHitShaderCollectionShaderNames() const final
{
return {};
}
deUint32 getInstanceCustomIndex(const deUint32& nBL, const deUint32& nInstance) const final
{
DE_UNREF(nBL);
DE_UNREF(nInstance);
return ++m_lastCustomInstanceIndexUsed;
}
tcu::UVec3 getDispatchSize() const final
{
DE_ASSERT(m_gridSizeXYZ[0] != 0);
DE_ASSERT(m_gridSizeXYZ[1] != 0);
DE_ASSERT(m_gridSizeXYZ[2] != 0);
return tcu::UVec3(m_gridSizeXYZ[0], m_gridSizeXYZ[1], m_gridSizeXYZ[2]);
}
deUint32 getResultBufferSize() const final
{
DE_ASSERT(m_gridSizeXYZ[0] != 0);
DE_ASSERT(m_gridSizeXYZ[1] != 0);
DE_ASSERT(m_gridSizeXYZ[2] != 0);
return static_cast<deUint32>((2 /* nHits, nMisses */ + m_gridSizeXYZ[0] * m_gridSizeXYZ[1] * m_gridSizeXYZ[2] * 1 /* hit instance custom index */) * sizeof(deUint32) );
}
std::vector<TopLevelAccelerationStructure*> getTLASPtrVecToBind() const final
{
DE_ASSERT(m_tlPtr != nullptr);
return {m_tlPtr.get() };
}
bool init( vkt::Context& context,
RayTracingProperties* rtPropertiesPtr) final
{
/* NOTE: In order to avoid running into a situation where the test attempts to create a buffer of size larger than permitted by Vulkan,
* we limit the maximum number of testable invocations to 2^29 on 64bit CTS build and driver or to 2^27 on 32bit */
const auto maxComputeWorkGroupCount = context.getDeviceProperties().limits.maxComputeWorkGroupCount;
const auto maxComputeWorkGroupSize = context.getDeviceProperties().limits.maxComputeWorkGroupSize;
const deUint64 maxGlobalRTWorkGroupSize[3] = { static_cast<deUint64>(maxComputeWorkGroupCount[0]) * static_cast<deUint64>(maxComputeWorkGroupSize[0]),
static_cast<deUint64>(maxComputeWorkGroupCount[1]) * static_cast<deUint64>(maxComputeWorkGroupSize[1]),
static_cast<deUint64>(maxComputeWorkGroupCount[2]) * static_cast<deUint64>(maxComputeWorkGroupSize[2]) };
const auto maxRayDispatchInvocationCount = de::min( static_cast<deUint64>(rtPropertiesPtr->getMaxRayDispatchInvocationCount() ),
#if (DE_PTR_SIZE == 4)
static_cast<deUint64>(1ULL << 27) );
#else
static_cast<deUint64>(1ULL << 29) );
#endif
m_gridSizeXYZ[0] = de::max( 1u,
static_cast<deUint32>((maxRayDispatchInvocationCount) % maxGlobalRTWorkGroupSize[0]) );
m_gridSizeXYZ[1] = de::max( 1u,
static_cast<deUint32>((maxRayDispatchInvocationCount / m_gridSizeXYZ[0]) % maxGlobalRTWorkGroupSize[1]) );
m_gridSizeXYZ[2] = de::max( 1u,
static_cast<deUint32>((maxRayDispatchInvocationCount / m_gridSizeXYZ[0] / m_gridSizeXYZ[1]) % maxGlobalRTWorkGroupSize[2]) );
/* TODO: The simple formulas above may need to be improved to handle your implementation correctly */
DE_ASSERT(m_gridSizeXYZ[0] * m_gridSizeXYZ[1] * m_gridSizeXYZ[2] == maxRayDispatchInvocationCount);
return true;
}
void initAS(vkt::Context& context,
RayTracingProperties* /* rtPropertiesPtr */,
VkCommandBuffer commandBuffer) final
{
std::unique_ptr<GridASProvider> asProviderPtr(
new GridASProvider( tcu::Vec3 (0, 0, 0), /* gridStartXYZ */
tcu::Vec3 (1, 1, 1), /* gridCellSizeXYZ */
tcu::UVec3(512, 1, 1), /* gridSizeXYZ */
tcu::Vec3 (3, 0, 0), /* gridInterCellDeltaXYZ */
m_geometryType)
);
m_tlPtr = asProviderPtr->createTLAS( context,
m_asStructureLayout,
commandBuffer,
VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR,
this, /* optASPropertyProviderPtr */
this); /* optASFeedbackPtr */
}
void initPrograms(SourceCollections& programCollection) const final
{
const vk::ShaderBuildOptions buildOptions( programCollection.usedVulkanVersion,
vk::SPIRV_VERSION_1_4,
0u, /* flags */
true); /* allowSpirv14 */
const char* hitPropsDefinition =
"struct HitProps\n"
"{\n"
" uint instanceCustomIndex;\n"
"};\n";
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"hitAttributeEXT vec3 dummyAttribute;\n"
"\n"
+ de::toString(hitPropsDefinition) +
"\n"
"layout(location = 0) rayPayloadInEXT uint dummy;\n"
"layout(set = 0, binding = 0, std430) buffer result\n"
"{\n"
" uint nHitsRegistered;\n"
" uint nMissesRegistered;\n"
" HitProps hits[];\n"
"};\n"
"\n"
"void main()\n"
"{\n"
" atomicAdd(nHitsRegistered, 1);\n"
"\n"
" uint nInvocation = gl_LaunchIDEXT.z * gl_LaunchSizeEXT.x * gl_LaunchSizeEXT.y + gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x;\n"
"\n"
" hits[nInvocation].instanceCustomIndex = gl_InstanceCustomIndexEXT;\n"
"}\n";
programCollection.glslSources.add("ahit") << glu::AnyHitSource(css.str() ) << buildOptions;
}
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"hitAttributeEXT vec3 hitAttribute;\n"
"\n"
"void main()\n"
"{\n"
" reportIntersectionEXT(0.95f, 0);\n"
"}\n";
programCollection.glslSources.add("intersection") << glu::IntersectionSource(css.str() ) << buildOptions;
}
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
+ de::toString(hitPropsDefinition) +
"\n"
"layout(set = 0, binding = 0, std430) buffer result\n"
"{\n"
" uint nHitsRegistered;\n"
" uint nMissesRegistered;\n"
" HitProps hits[];\n"
"};\n"
"\n"
"layout(location = 0) rayPayloadInEXT uint rayIndex;\n"
"\n"
"void main()\n"
"{\n"
" atomicAdd(nMissesRegistered, 1);\n"
"}\n";
programCollection.glslSources.add("miss") << glu::MissSource(css.str() ) << buildOptions;
}
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"layout(location = 0) rayPayloadEXT uint dummy;\n"
"layout(set = 0, binding = 1) uniform accelerationStructureEXT accelerationStructure;\n"
"\n"
"void main()\n"
"{\n"
" uint nInvocation = gl_LaunchIDEXT.z * gl_LaunchSizeEXT.x * gl_LaunchSizeEXT.y + gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x;\n"
" uint rayFlags = 0;\n"
" float tmin = 0.001;\n"
" float tmax = 2.1;\n"
"\n"
" uint cullMask = 0xFF;\n"
" vec3 cellStartXYZ = vec3( (nInvocation % " + de::toString(m_nMaxCells) + ") * 3, 0.0, 0.0);\n"
" vec3 cellEndXYZ = cellStartXYZ + vec3(1.0);\n"
" vec3 target = mix(cellStartXYZ, cellEndXYZ, vec3(0.5) );\n"
" vec3 origin = target - vec3(0, 2, 0);\n"
" vec3 direct = normalize(target - origin);\n"
"\n"
" traceRayEXT(accelerationStructure, rayFlags, cullMask, 0, 0, 0, origin, tmin, direct, tmax, 0);\n"
"}\n";
programCollection.glslSources.add("rgen") << glu::RaygenSource(css.str() ) << buildOptions;
}
}
void resetTLAS() final
{
m_tlPtr.reset();
}
bool verifyResultBuffer (const void* resultDataPtr) const final
{
const deUint32* resultU32Ptr = reinterpret_cast<const deUint32*>(resultDataPtr);
bool result = false;
typedef struct
{
deUint32 instanceCustomIndex;
} HitProperties;
const auto nHitsReported = *resultU32Ptr;
const auto nMissesReported = *(resultU32Ptr + 1);
if (nHitsReported != m_gridSizeXYZ[0] * m_gridSizeXYZ[1] * m_gridSizeXYZ[2])
{
goto end;
}
if (nMissesReported != 0)
{
goto end;
}
for (deUint32 nRay = 0; nRay < nHitsReported; ++nRay)
{
const HitProperties* hitPropsPtr = reinterpret_cast<const HitProperties*>(resultU32Ptr + 2 /* preamble ints */) + nRay;
if (m_nRayToInstanceIndexExpected.at(nRay % m_nMaxCells) != hitPropsPtr->instanceCustomIndex)
{
goto end;
}
}
result = true;
end:
return result;
}
private:
void onCullMaskAssignedToCell(const tcu::UVec3& cellLocation, const deUint8& cullMaskAssigned)
{
/* Dont'care */
DE_UNREF(cellLocation);
DE_UNREF(cullMaskAssigned);
}
void onInstanceCustomIndexAssignedToCell(const tcu::UVec3& cellLocation, const deUint32& customIndexAssigned)
{
DE_ASSERT(cellLocation[1] == 0);
DE_ASSERT(cellLocation[2] == 0);
m_nRayToInstanceIndexExpected[cellLocation[0] ] = customIndexAssigned;
}
const AccelerationStructureLayout m_asStructureLayout;
const GeometryType m_geometryType;
tcu::UVec3 m_gridSizeXYZ;
mutable deUint32 m_lastCustomInstanceIndexUsed;
const deUint32 m_nMaxCells;
std::unique_ptr<TopLevelAccelerationStructure> m_tlPtr;
std::map<deUint32, deUint32> m_nRayToInstanceIndexExpected;
};
class NoDuplicateAnyHitTest : public TestBase
{
public:
NoDuplicateAnyHitTest( const AccelerationStructureLayout& asLayout,
const GeometryType& geometryType)
:m_asLayout (asLayout),
m_geometryType (geometryType),
m_gridSizeXYZ (tcu::UVec3(4, 4, 4) ),
m_nRaysToTrace (32)
{
/* Stub */
}
~NoDuplicateAnyHitTest()
{
/* Stub */
}
std::vector<std::string> getCHitShaderCollectionShaderNames() const final
{
return {};
}
tcu::UVec3 getDispatchSize() const final
{
return tcu::UVec3(4, 4, m_nRaysToTrace / (4 * 4) + 1);
}
deUint32 getResultBufferSize() const final
{
const auto nPrimitives = m_gridSizeXYZ[0] * m_gridSizeXYZ[1] * m_gridSizeXYZ[2];
return static_cast<deUint32>((2 /* nHits, nMisses */ + 3 * nPrimitives /* instancePrimitiveIDPairsUsed */) * sizeof(deUint32) * m_nRaysToTrace);
}
std::vector<TopLevelAccelerationStructure*> getTLASPtrVecToBind() const final
{
return {m_tlPtr.get() };
}
void resetTLAS() final
{
m_tlPtr.reset();
}
void initAS(vkt::Context& context,
RayTracingProperties* /* rtPropertiesPtr */,
VkCommandBuffer commandBuffer) final
{
m_asProviderPtr.reset(
new GridASProvider( tcu::Vec3 (0, 0, 0), /* gridStartXYZ */
tcu::Vec3 (1, 1, 1), /* gridCellSizeXYZ */
m_gridSizeXYZ,
tcu::Vec3 (2.0f, 2.0f, 2.0f), /* gridInterCellDeltaXYZ */
m_geometryType)
);
m_tlPtr = m_asProviderPtr->createTLAS( context,
m_asLayout,
commandBuffer,
VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR,
nullptr, /* optASPropertyProviderPtr */
nullptr); /* optASFedbackPtr */
}
void initPrograms(SourceCollections& programCollection) const final
{
const vk::ShaderBuildOptions buildOptions( programCollection.usedVulkanVersion,
vk::SPIRV_VERSION_1_4,
0u, /* flags */
true); /* allowSpirv14 */
const auto nTotalPrimitives = m_gridSizeXYZ[0] * m_gridSizeXYZ[1] * m_gridSizeXYZ[2];
const auto hitPropertiesDefinition = "struct HitProperties\n"
"{\n"
" uint nHitsRegistered;\n"
" uint nMissRegistered;\n"
" uint instancePrimitiveIDPairsUsed[3 * " + de::toString(nTotalPrimitives) + "];\n"
"};\n";
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"hitAttributeEXT vec3 dummyAttribute;\n"
"\n"
+ hitPropertiesDefinition +
"\n"
"layout(location = 0) rayPayloadInEXT dummy { vec3 dummyVec;};\n"
"layout(set = 0, binding = 0, std430) buffer result\n"
"{\n"
" HitProperties rayToHitProps[" << de::toString(m_nRaysToTrace) << "];\n"
"};\n"
"\n"
"void main()\n"
"{\n"
" uint nRay = gl_LaunchIDEXT.z * gl_LaunchSizeEXT.x * gl_LaunchSizeEXT.y + gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x;\n"
" uint nHitsRegistered = atomicAdd(rayToHitProps[nRay].nHitsRegistered, 1);\n"
"\n"
" rayToHitProps[nRay].instancePrimitiveIDPairsUsed[3 * nHitsRegistered + 0] = 1 + gl_InstanceID;\n"
" rayToHitProps[nRay].instancePrimitiveIDPairsUsed[3 * nHitsRegistered + 1] = 1 + gl_PrimitiveID;\n"
" rayToHitProps[nRay].instancePrimitiveIDPairsUsed[3 * nHitsRegistered + 2] = 1 + gl_GeometryIndexEXT;\n"
"}\n";
programCollection.glslSources.add("ahit") << glu::AnyHitSource(css.str() ) << buildOptions;
}
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"hitAttributeEXT vec3 hitAttribute;\n"
"\n"
"void main()\n"
"{\n"
" reportIntersectionEXT(0.95f, 0);\n"
"}\n";
programCollection.glslSources.add("intersection") << glu::IntersectionSource(css.str() ) << buildOptions;
}
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
+ hitPropertiesDefinition +
"layout(location = 0) rayPayloadInEXT vec3 dummy;\n"
"layout(set = 0, binding = 0, std430) buffer result\n"
"{\n"
" HitProperties rayToHitProps[" << de::toString(m_nRaysToTrace) << "];\n"
"};\n"
"\n"
"void main()\n"
"{\n"
" uint nRay = gl_LaunchIDEXT.z * gl_LaunchSizeEXT.x * gl_LaunchSizeEXT.y + gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x;\n"
"\n"
" atomicAdd(rayToHitProps[nRay].nMissRegistered, 1);\n"
"}\n";
programCollection.glslSources.add("miss") << glu::MissSource(css.str() ) << buildOptions;
}
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
+ hitPropertiesDefinition +
"layout(location = 0) rayPayloadEXT vec3 dummy;\n"
"layout(set = 0, binding = 1) uniform accelerationStructureEXT topLevelAS;\n"
"\n"
"void main()\n"
"{\n"
" uint nInvocation = gl_LaunchIDEXT.z * gl_LaunchSizeEXT.x * gl_LaunchSizeEXT.y + gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x;\n"
" uint rayFlags = 0;\n"
" uint cullMask = 0xFF;\n"
" float tmin = 0.001;\n"
" float tmax = 9.0;\n"
" vec3 origin = vec3(4, 4, 4);\n"
" vec3 target = vec3(float(gl_LaunchIDEXT.x * 2) + 0.5f, float(gl_LaunchIDEXT.y * 2) + 0.5f, float(gl_LaunchIDEXT.z * 2) + 0.5f);\n"
" vec3 direct = normalize(target - origin);\n"
"\n"
" if (nInvocation >= " << m_nRaysToTrace << ")\n"
" {\n"
" return;\n"
" }\n"
"\n"
" traceRayEXT(topLevelAS, rayFlags, cullMask, 0, 0, 0, origin, tmin, direct, tmax, 0);\n"
"}\n";
programCollection.glslSources.add("rgen") << glu::RaygenSource(css.str() ) << buildOptions;
}
}
bool verifyResultBuffer (const void* resultDataPtr) const final
{
const auto nTotalPrimitives = m_gridSizeXYZ[0] * m_gridSizeXYZ[1] * m_gridSizeXYZ[2];
bool result = true;
for (deUint32 nRay = 0; nRay < m_nRaysToTrace; ++nRay)
{
std::vector<std::tuple<deUint32, deUint32, deUint32> > tupleVec;
const auto rayProps = reinterpret_cast<const deUint32*>(resultDataPtr) + (2 + 3 * nTotalPrimitives) * nRay;
// 1. At least one ahit invocation must have been made.
if (rayProps[0] == 0)
{
result = false;
goto end;
}
// 2. It's OK for each ray to intersect many AABBs, but no AABB should have had >1 ahit invocation fired.
for (deUint32 nPrimitive = 0; nPrimitive < nTotalPrimitives; nPrimitive++)
{
const auto instanceID = rayProps[2 /* nHits, nMissesRegistered */ + 3 * nPrimitive + 0];
const auto primitiveID = rayProps[2 /* nHits, nMissesRegistered */ + 3 * nPrimitive + 1];
const auto geometryIndex = rayProps[2 /* nHits, nMissesRegistered */ + 3 * nPrimitive + 2];
const auto currentTuple = std::tuple<deUint32, deUint32, deUint32>(instanceID, primitiveID, geometryIndex);
if (instanceID != 0 ||
primitiveID != 0 ||
geometryIndex != 0)
{
if (std::find( tupleVec.begin(),
tupleVec.end (),
currentTuple) != tupleVec.end() )
{
result = false;
goto end;
}
tupleVec.push_back(currentTuple);
}
}
// 3. None of the traced rays should have triggered the miss shader invocation.
if (rayProps[1] != 0)
{
result = false;
goto end;
}
}
end:
return result;
}
private:
const AccelerationStructureLayout m_asLayout;
const GeometryType m_geometryType;
const tcu::UVec3 m_gridSizeXYZ;
const deUint32 m_nRaysToTrace;
std::unique_ptr<GridASProvider> m_asProviderPtr;
std::unique_ptr<TopLevelAccelerationStructure> m_tlPtr;
};
const std::vector<VariableType> g_ShaderRecordBlockTestVars1 =
{
VariableType::FLOAT,
VariableType::VEC2,
VariableType::VEC3,
VariableType::VEC4,
VariableType::MAT2,
VariableType::MAT2X2,
VariableType::MAT2X3,
VariableType::MAT2X4,
VariableType::MAT3,
VariableType::MAT3X2,
VariableType::MAT3X3,
VariableType::MAT3X4,
VariableType::MAT4,
VariableType::MAT4X2,
VariableType::MAT4X3,
VariableType::MAT4X4,
VariableType::INT,
VariableType::IVEC2,
VariableType::IVEC3,
VariableType::IVEC4,
VariableType::UINT,
VariableType::UVEC2,
VariableType::UVEC3,
VariableType::UVEC4,
};
const std::vector<VariableType> g_ShaderRecordBlockTestVars2 =
{
VariableType::DOUBLE,
VariableType::DVEC2,
VariableType::DVEC3,
VariableType::DVEC4,
VariableType::DMAT2,
VariableType::DMAT2X2,
VariableType::DMAT2X3,
VariableType::DMAT2X4,
VariableType::DMAT3,
};
const std::vector<VariableType> g_ShaderRecordBlockTestVars3 =
{
VariableType::DMAT3X2,
VariableType::DMAT3X3,
VariableType::DMAT3X4,
VariableType::DMAT4,
VariableType::DMAT4X2,
VariableType::DMAT4X3,
VariableType::DMAT4X4,
};
const std::vector<VariableType> g_ShaderRecordBlockTestVars4 =
{
VariableType::VEC3,
VariableType::VEC4,
VariableType::INT16,
VariableType::I16VEC2,
VariableType::I16VEC3,
VariableType::I16VEC4,
VariableType::MAT3X3,
VariableType::MAT3X4,
VariableType::MAT4X3,
VariableType::UINT16,
VariableType::U16VEC2,
VariableType::U16VEC3,
VariableType::U16VEC4,
};
const std::vector<VariableType> g_ShaderRecordBlockTestVars5 =
{
VariableType::VEC3,
VariableType::VEC4,
VariableType::INT64,
VariableType::I64VEC2,
VariableType::I64VEC3,
VariableType::I64VEC4,
VariableType::MAT3X3,
VariableType::MAT3X4,
VariableType::MAT4X3,
VariableType::UINT64,
VariableType::U64VEC2,
VariableType::U64VEC3,
VariableType::U64VEC4,
};
const std::vector<VariableType> g_ShaderRecordBlockTestVars6 =
{
VariableType::VEC3,
VariableType::VEC4,
VariableType::INT8,
VariableType::I8VEC2,
VariableType::I8VEC3,
VariableType::I8VEC4,
VariableType::MAT3X3,
VariableType::MAT3X4,
VariableType::MAT4X3,
VariableType::UINT8,
VariableType::U8VEC2,
VariableType::U8VEC3,
VariableType::U8VEC4,
};
class ShaderRecordBlockTest : public TestBase
{
public:
ShaderRecordBlockTest( const TestType& testType, const std::vector<VariableType>& varTypesToTest)
: m_gridSizeXYZ (tcu::UVec3(2, 2, 2) ),
m_testType (testType),
m_varTypesToTest (varTypesToTest),
m_resultBufferSize (0),
m_shaderRecordSize (0)
{
initTestItems();
}
~ShaderRecordBlockTest()
{
/* Stub */
}
tcu::UVec3 getDispatchSize() const final
{
return tcu::UVec3(3, 1, 1);
}
deUint32 getResultBufferSize() const final
{
return m_resultBufferSize;
}
const void* getShaderRecordData(const ShaderGroups& shaderGroup) const final
{
return (shaderGroup == ShaderGroups::HIT_GROUP) ? m_shaderGroupToRecordDataMap.at(shaderGroup).data()
: (shaderGroup == ShaderGroups::MISS_GROUP) ? m_shaderGroupToRecordDataMap.at(shaderGroup).data()
: nullptr;
}
deUint32 getShaderRecordSize(const ShaderGroups& shaderGroup) const final
{
DE_ASSERT(m_shaderRecordSize != 0);
return ((shaderGroup == ShaderGroups::HIT_GROUP) ||
(shaderGroup == ShaderGroups::MISS_GROUP)) ? m_shaderRecordSize
: 0;
}
std::vector<TopLevelAccelerationStructure*> getTLASPtrVecToBind() const final
{
return {m_tlPtr.get() };
}
static std::vector<VariableType> getVarsToTest(const TestType& testType)
{
return ((testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_1) || (testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_1) || (testType == TestType::SHADER_RECORD_BLOCK_SCALAR_1) || (testType == TestType::SHADER_RECORD_BLOCK_STD430_1)) ? g_ShaderRecordBlockTestVars1
: ((testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_2) || (testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_2) || (testType == TestType::SHADER_RECORD_BLOCK_SCALAR_2) || (testType == TestType::SHADER_RECORD_BLOCK_STD430_2)) ? g_ShaderRecordBlockTestVars2
: ((testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_3) || (testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_3) || (testType == TestType::SHADER_RECORD_BLOCK_SCALAR_3) || (testType == TestType::SHADER_RECORD_BLOCK_STD430_3)) ? g_ShaderRecordBlockTestVars3
: ((testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_4) || (testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_4) || (testType == TestType::SHADER_RECORD_BLOCK_SCALAR_4) || (testType == TestType::SHADER_RECORD_BLOCK_STD430_4)) ? g_ShaderRecordBlockTestVars4
: ((testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_5) || (testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_5) || (testType == TestType::SHADER_RECORD_BLOCK_SCALAR_5) || (testType == TestType::SHADER_RECORD_BLOCK_STD430_5)) ? g_ShaderRecordBlockTestVars5
: g_ShaderRecordBlockTestVars6;
}
void resetTLAS() final
{
m_tlPtr.reset();
}
bool init( vkt::Context& /* context */,
RayTracingProperties* /* rtPropsPtr */) final
{
// Cache required result buffer size.
{
deUint32 largestBaseTypeSizeUsed = 0;
const auto& lastItem = m_testItems.items.back();
const deUint32 nResultBytesPerShaderStage = lastItem.resultBufferProps.bufferOffset + lastItem.arraySize * lastItem.resultBufferProps.arrayStride;
const VkShaderStageFlagBits shaderStages[] =
{
VK_SHADER_STAGE_MISS_BIT_KHR,
VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,
VK_SHADER_STAGE_INTERSECTION_BIT_KHR,
VK_SHADER_STAGE_ANY_HIT_BIT_KHR,
};
m_shaderRecordSize = lastItem.inputBufferProps.bufferOffset + lastItem.arraySize * lastItem.inputBufferProps.arrayStride;
for (const auto& currentTestItem : m_testItems.items)
{
const auto baseType = getBaseType (currentTestItem.type);
const auto componentSize = getComponentSizeBytes (baseType);
largestBaseTypeSizeUsed = de::max(componentSize, largestBaseTypeSizeUsed);
}
for (const auto& currentShaderStage : shaderStages)
{
m_shaderStageToResultBufferOffset[currentShaderStage] = m_resultBufferSize;
m_resultBufferSize = de::roundUp(m_resultBufferSize, static_cast<deUint32>(sizeof(largestBaseTypeSizeUsed)) );
m_resultBufferSize += nResultBytesPerShaderStage;
}
}
return true;
}
void initAS(vkt::Context& context,
RayTracingProperties* /* rtPropertiesPtr */,
VkCommandBuffer commandBuffer) final
{
m_asProviderPtr.reset(
new GridASProvider( tcu::Vec3 (0, 0, 0), /* gridStartXYZ */
tcu::Vec3 (1, 1, 1), /* gridCellSizeXYZ */
m_gridSizeXYZ,
tcu::Vec3 (2.0f, 2.0f, 2.0f), /* gridInterCellDeltaXYZ */
GeometryType::AABB)
);
m_tlPtr = m_asProviderPtr->createTLAS( context,
AccelerationStructureLayout::ONE_TL_MANY_BLS_MANY_GEOMETRIES,
commandBuffer,
VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR,
nullptr, /* optASPropertyProviderPtr */
nullptr); /* optASFedbackPtr */
}
void initPrograms(SourceCollections& programCollection) const final
{
const vk::ShaderBuildOptions buildOptions( programCollection.usedVulkanVersion,
vk::SPIRV_VERSION_1_4,
0u, /* flags */
true); /* allowSpirv14 */
const bool isSTD430Test = isExplicitSTD430OffsetTest (m_testType) ||
isSTD430LayoutTest (m_testType);
const bool requires16BitStorage = usesI16 (m_testType) ||
usesU16 (m_testType);
const bool requires8BitStorage = usesI8 (m_testType) ||
usesU8 (m_testType);
const bool requiresInt64 = usesI64 (m_testType) ||
usesU64 (m_testType);
const bool usesExplicitOffsets = isExplicitScalarOffsetTest (m_testType) ||
isExplicitSTD430OffsetTest (m_testType);
const auto inputBlockVariablesGLSL = getGLSLForStructItem ( m_testItems,
usesExplicitOffsets,
true /* targetsInputBuffer */);
const auto outputStructVariablesGLSL = getGLSLForStructItem ( m_testItems,
false, /* includeOffsetLayoutQualifier */
false /* targetsInputBuffer */);
const auto inputBufferGLSL = "layout (" + std::string((!isSTD430Test) ? "scalar, " : "std430, ") + "shaderRecordEXT) buffer ib\n"
"{\n" +
inputBlockVariablesGLSL +
"} inputBuffer;\n";
const auto outputBufferGLSL = "struct OutputData\n"
"{\n" +
outputStructVariablesGLSL +
"};\n"
"\n"
"layout (std430, set = 0, binding = 0) buffer ob\n"
"{\n"
" OutputData results[4];\n"
"};\n";
std::string preamble;
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n";
if (!isSTD430Test)
{
css << "#extension GL_EXT_scalar_block_layout : require\n";
}
if (requires16BitStorage)
{
css << "#extension GL_EXT_shader_16bit_storage : require\n";
}
if (requires8BitStorage)
{
css << "#extension GL_EXT_shader_8bit_storage : require\n";
}
if (requiresInt64)
{
css << "#extension GL_ARB_gpu_shader_int64 : require\n";
}
preamble = css.str();
}
{
std::stringstream css;
css << preamble
<<
"\n"
" hitAttributeEXT vec3 dummyAttribute;\n"
"layout(location = 0) rayPayloadInEXT dummy { vec3 dummyVec;};\n"
"\n" +
inputBufferGLSL +
outputBufferGLSL +
"\n"
"void main()\n"
"{\n" +
getGLSLForSetters(m_testItems, 3) +
"}\n";
programCollection.glslSources.add("ahit") << glu::AnyHitSource(css.str() ) << buildOptions;
}
{
std::stringstream css;
css << preamble
<<
"\n"
"layout(location = 0) rayPayloadInEXT dummy { vec3 dummyVec;};\n" +
inputBufferGLSL +
outputBufferGLSL +
"\n"
"void main()\n"
"{\n" +
getGLSLForSetters(m_testItems, 1) +
"}\n";
programCollection.glslSources.add("chit") << glu::ClosestHitSource(css.str() ) << buildOptions;
}
{
std::stringstream css;
css << preamble
<<
"\n"
"hitAttributeEXT vec3 hitAttribute;\n"
"\n" +
inputBufferGLSL +
outputBufferGLSL +
"\n"
"void main()\n"
"{\n" +
getGLSLForSetters(m_testItems, 2) +
"\n"
" reportIntersectionEXT(0.95f, 0);\n"
"}\n";
programCollection.glslSources.add("intersection") << glu::IntersectionSource(css.str() ) << buildOptions;
}
{
std::stringstream css;
css << preamble
<<
"\n"
"layout(location = 0) rayPayloadInEXT vec3 dummy;\n"
"\n" +
inputBufferGLSL +
outputBufferGLSL +
"\n"
"void main()\n"
"{\n"
" uint nRay = gl_LaunchIDEXT.z * gl_LaunchSizeEXT.x * gl_LaunchSizeEXT.y + gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x;\n"
"\n" +
getGLSLForSetters(m_testItems, 0) +
"}\n";
programCollection.glslSources.add("miss") << glu::MissSource(css.str() ) << buildOptions;
}
{
std::stringstream css;
css << preamble
<<
"layout(location = 0) rayPayloadEXT vec3 dummy;\n"
"layout(set = 0, binding = 1) uniform accelerationStructureEXT accelerationStructure;\n"
"\n"
"void main()\n"
"{\n"
" uint nInvocation = gl_LaunchIDEXT.z * gl_LaunchSizeEXT.x * gl_LaunchSizeEXT.y + gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x;\n"
" uint rayFlags = 0;\n"
" float tmin = 0.001;\n"
" float tmax = 9.0;\n"
"\n"
" uint cullMask = 0xFF;\n"
" vec3 cellStartXYZ = vec3(nInvocation * 2.0, 0.0, 0.0);\n"
" vec3 cellEndXYZ = cellStartXYZ + vec3(1.0);\n"
" vec3 target = mix(cellStartXYZ, cellEndXYZ, vec3(0.5) );\n"
" vec3 origin = target - vec3(0, 2, 0);\n"
" vec3 direct = normalize(target - origin);\n"
"\n"
" traceRayEXT(accelerationStructure, rayFlags, cullMask, 0, 0, 0, origin, tmin, direct, tmax, 0);\n"
"}\n";
programCollection.glslSources.add("rgen") << glu::RaygenSource(css.str() ) << buildOptions;
}
}
static bool isExplicitScalarOffsetTest(const TestType& testType)
{
return (testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_1) ||
(testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_2) ||
(testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_3) ||
(testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_4) ||
(testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_5) ||
(testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_6);
}
static bool isExplicitSTD430OffsetTest(const TestType& testType)
{
return (testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_1) ||
(testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_2) ||
(testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_3) ||
(testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_4) ||
(testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_5) ||
(testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_6);
}
static bool isScalarLayoutTest(const TestType& testType)
{
return (testType == TestType::SHADER_RECORD_BLOCK_SCALAR_1) ||
(testType == TestType::SHADER_RECORD_BLOCK_SCALAR_2) ||
(testType == TestType::SHADER_RECORD_BLOCK_SCALAR_3) ||
(testType == TestType::SHADER_RECORD_BLOCK_SCALAR_4) ||
(testType == TestType::SHADER_RECORD_BLOCK_SCALAR_5) ||
(testType == TestType::SHADER_RECORD_BLOCK_SCALAR_6);
}
static bool isSTD430LayoutTest(const TestType& testType)
{
return (testType == TestType::SHADER_RECORD_BLOCK_STD430_1) ||
(testType == TestType::SHADER_RECORD_BLOCK_STD430_2) ||
(testType == TestType::SHADER_RECORD_BLOCK_STD430_3) ||
(testType == TestType::SHADER_RECORD_BLOCK_STD430_4) ||
(testType == TestType::SHADER_RECORD_BLOCK_STD430_5) ||
(testType == TestType::SHADER_RECORD_BLOCK_STD430_6);
}
static bool isTest(const TestType& testType)
{
return (testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_1) ||
(testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_2) ||
(testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_3) ||
(testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_4) ||
(testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_5) ||
(testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_6) ||
(testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_1) ||
(testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_2) ||
(testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_3) ||
(testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_4) ||
(testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_5) ||
(testType == TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_6) ||
(testType == TestType::SHADER_RECORD_BLOCK_SCALAR_1) ||
(testType == TestType::SHADER_RECORD_BLOCK_SCALAR_2) ||
(testType == TestType::SHADER_RECORD_BLOCK_SCALAR_3) ||
(testType == TestType::SHADER_RECORD_BLOCK_SCALAR_4) ||
(testType == TestType::SHADER_RECORD_BLOCK_SCALAR_5) ||
(testType == TestType::SHADER_RECORD_BLOCK_SCALAR_6) ||
(testType == TestType::SHADER_RECORD_BLOCK_STD430_1) ||
(testType == TestType::SHADER_RECORD_BLOCK_STD430_2) ||
(testType == TestType::SHADER_RECORD_BLOCK_STD430_3) ||
(testType == TestType::SHADER_RECORD_BLOCK_STD430_4) ||
(testType == TestType::SHADER_RECORD_BLOCK_STD430_5) ||
(testType == TestType::SHADER_RECORD_BLOCK_STD430_6);
}
static bool usesF64(const TestType& testType)
{
const auto tested_var_types = getVarsToTest(testType);
const bool has_f64 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::DOUBLE) != tested_var_types.end();
const bool has_f64vec2 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::DVEC2) != tested_var_types.end();
const bool has_f64vec3 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::DVEC3) != tested_var_types.end();
const bool has_f64vec4 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::DVEC4) != tested_var_types.end();
const bool has_f64mat2 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::DMAT2) != tested_var_types.end();
const bool has_f64mat3 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::DMAT3) != tested_var_types.end();
const bool has_f64mat4 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::DMAT4) != tested_var_types.end();
return (has_f64 || has_f64vec2 || has_f64vec3 || has_f64vec4 || has_f64mat2 || has_f64mat3 || has_f64mat4);
}
static bool usesI8(const TestType& testType)
{
const auto tested_var_types = getVarsToTest(testType);
const bool has_i8 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::INT8) != tested_var_types.end();
const bool has_i8vec2 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::I8VEC2) != tested_var_types.end();
const bool has_i8vec3 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::I8VEC3) != tested_var_types.end();
const bool has_i8vec4 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::I8VEC4) != tested_var_types.end();
return (has_i8 || has_i8vec2 || has_i8vec3 || has_i8vec4);
}
static bool usesI16(const TestType& testType)
{
const auto tested_var_types = getVarsToTest(testType);
const bool has_i16 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::INT16) != tested_var_types.end();
const bool has_i16vec2 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::I16VEC2) != tested_var_types.end();
const bool has_i16vec3 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::I16VEC3) != tested_var_types.end();
const bool has_i16vec4 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::I16VEC4) != tested_var_types.end();
return (has_i16 || has_i16vec2 || has_i16vec3 || has_i16vec4);
}
static bool usesI64(const TestType& testType)
{
const auto tested_var_types = getVarsToTest(testType);
const bool has_i64 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::INT64) != tested_var_types.end();
const bool has_i64vec2 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::I64VEC2) != tested_var_types.end();
const bool has_i64vec3 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::I64VEC3) != tested_var_types.end();
const bool has_i64vec4 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::I64VEC4) != tested_var_types.end();
return (has_i64 || has_i64vec2 || has_i64vec3 || has_i64vec4);
}
static bool usesU8(const TestType& testType)
{
const auto tested_var_types = getVarsToTest(testType);
const bool has_u8 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::UINT8) != tested_var_types.end();
const bool has_u8vec2 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::U8VEC2) != tested_var_types.end();
const bool has_u8vec3 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::U8VEC3) != tested_var_types.end();
const bool has_u8vec4 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::U8VEC4) != tested_var_types.end();
return (has_u8 || has_u8vec2 || has_u8vec3 || has_u8vec4);
}
static bool usesU16(const TestType& testType)
{
const auto tested_var_types = getVarsToTest(testType);
const bool has_u16 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::UINT16) != tested_var_types.end();
const bool has_u16vec2 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::U16VEC2) != tested_var_types.end();
const bool has_u16vec3 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::U16VEC3) != tested_var_types.end();
const bool has_u16vec4 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::U16VEC4) != tested_var_types.end();
return (has_u16 || has_u16vec2 || has_u16vec3 || has_u16vec4);
}
static bool usesU64(const TestType& testType)
{
const auto tested_var_types = getVarsToTest(testType);
const bool has_u64 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::UINT64) != tested_var_types.end();
const bool has_u64vec2 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::U64VEC2) != tested_var_types.end();
const bool has_u64vec3 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::U64VEC3) != tested_var_types.end();
const bool has_u64vec4 = std::find ( tested_var_types.begin (),
tested_var_types.end (),
VariableType::U64VEC4) != tested_var_types.end();
return (has_u64 || has_u64vec2 || has_u64vec3 || has_u64vec4);
}
bool verifyResultBuffer (const void* resultBufferDataPtr) const final
{
bool result = false;
for (const auto& iterator : m_shaderStageToResultBufferOffset)
{
const auto currentShaderStage = iterator.first;
const auto shaderGroup = ( (currentShaderStage == VK_SHADER_STAGE_ANY_HIT_BIT_KHR) ||
(currentShaderStage == VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR) ||
(currentShaderStage == VK_SHADER_STAGE_INTERSECTION_BIT_KHR) ) ? ShaderGroups::HIT_GROUP
: ShaderGroups::MISS_GROUP;
const auto resultStartOffset = iterator.second;
if (currentShaderStage != VK_SHADER_STAGE_MISS_BIT_KHR) continue;
for (const auto& currentItem : m_testItems.items)
{
const auto baseDataType = getBaseType (currentItem.type);
const auto componentSize = getComponentSizeBytes (baseDataType);
const auto& expectedDataVec = currentItem.shaderGroupToRecordDataMap.at (shaderGroup);
auto expectedDataPtr = reinterpret_cast<const deUint8*> (expectedDataVec.data() );
const auto isMatrixType = isMatrix (currentItem.type);
const auto nComponents = getNComponents (currentItem.type);
const deUint8* resultDataPtr = reinterpret_cast<const deUint8*> (resultBufferDataPtr) + resultStartOffset + currentItem.resultBufferProps.bufferOffset;
for (deUint32 nArrayItem = 0; nArrayItem < currentItem.arraySize; ++nArrayItem)
{
for (deUint32 nComponent = 0; nComponent < nComponents; ++nComponent)
{
const auto expectedComponentDataPtr = expectedDataPtr + ((!isMatrixType) ? componentSize * nComponent
: currentItem.inputBufferProps.matrixElementStartOffsets.at(nComponent) );
const auto resultComponentDataPtr = resultDataPtr + ((!isMatrixType) ? componentSize * nComponent
: currentItem.resultBufferProps.matrixElementStartOffsets.at(nComponent) );
switch (baseDataType)
{
case BaseType::F32:
{
if (fabs(*reinterpret_cast<const float*>(resultComponentDataPtr) - *reinterpret_cast<const float*>(expectedComponentDataPtr)) > 1e-3f)
{
goto end;
}
break;
}
case BaseType::F64:
{
if (fabs(*reinterpret_cast<const double*>(resultComponentDataPtr) - *reinterpret_cast<const double*>(expectedComponentDataPtr)) > 1e-3)
{
goto end;
}
break;
}
case BaseType::I8:
{
if (*reinterpret_cast<const deInt8*>(resultComponentDataPtr) != *reinterpret_cast<const deInt8*>(expectedComponentDataPtr))
{
goto end;
}
break;
}
case BaseType::I16:
{
if (*reinterpret_cast<const deInt16*>(resultComponentDataPtr) != *reinterpret_cast<const deInt16*>(expectedComponentDataPtr))
{
goto end;
}
break;
}
case BaseType::I32:
{
if (*reinterpret_cast<const deInt32*>(resultComponentDataPtr) != *reinterpret_cast<const deInt32*>(expectedComponentDataPtr))
{
goto end;
}
break;
}
case BaseType::I64:
{
if (*reinterpret_cast<const deInt64*>(resultComponentDataPtr) != *reinterpret_cast<const deInt64*>(expectedComponentDataPtr))
{
goto end;
}
break;
}
case BaseType::U8:
{
if (*reinterpret_cast<const deUint8*>(resultComponentDataPtr) != *reinterpret_cast<const deUint8*>(expectedComponentDataPtr))
{
goto end;
}
break;
}
case BaseType::U16:
{
if (*reinterpret_cast<const deUint16*>(resultComponentDataPtr) != *reinterpret_cast<const deUint16*>(expectedComponentDataPtr))
{
goto end;
}
break;
}
case BaseType::U32:
{
if (*reinterpret_cast<const deUint32*>(resultComponentDataPtr) != *reinterpret_cast<const deUint32*>(expectedComponentDataPtr))
{
goto end;
}
break;
}
case BaseType::U64:
{
if (*reinterpret_cast<const deUint64*>(resultComponentDataPtr) != *reinterpret_cast<const deUint64*>(expectedComponentDataPtr))
{
goto end;
}
break;
}
default:
{
DE_ASSERT(false);
}
}
}
expectedDataPtr += currentItem.inputBufferProps.arrayStride;
resultDataPtr += currentItem.resultBufferProps.arrayStride;
}
}
}
result = true;
end:
return result;
}
private:
typedef struct Item
{
struct BufferProps
{
deUint32 arrayStride;
deUint32 bufferOffset;
std::vector<deUint32> matrixElementStartOffsets; //< Holds offsets to consecutive matrix element values.
BufferProps()
: arrayStride (0),
bufferOffset(0xFFFFFFFF)
{
/* Stub */
}
};
BufferProps inputBufferProps;
BufferProps resultBufferProps;
deUint32 arraySize;
MatrixMajorOrder matrixOrder;
std::string name;
VariableType type;
std::map<ShaderGroups, std::vector<deUint8> > shaderGroupToRecordDataMap;
Item()
:arraySize (0),
matrixOrder (MatrixMajorOrder::UNKNOWN),
type (VariableType::UNKNOWN)
{
/* Stub */
}
} Item;
struct StructItem
{
std::vector<Item> items;
};
// Private functions
BaseType getBaseType(const VariableType& type) const
{
auto result = BaseType::UNKNOWN;
switch (type)
{
case VariableType::FLOAT:
case VariableType::MAT2:
case VariableType::MAT2X2:
case VariableType::MAT2X3:
case VariableType::MAT2X4:
case VariableType::MAT3:
case VariableType::MAT3X2:
case VariableType::MAT3X3:
case VariableType::MAT3X4:
case VariableType::MAT4:
case VariableType::MAT4X2:
case VariableType::MAT4X3:
case VariableType::MAT4X4:
case VariableType::VEC2:
case VariableType::VEC3:
case VariableType::VEC4:
{
result = BaseType::F32;
break;
}
case VariableType::DOUBLE:
case VariableType::DMAT2:
case VariableType::DMAT2X2:
case VariableType::DMAT2X3:
case VariableType::DMAT2X4:
case VariableType::DMAT3:
case VariableType::DMAT3X2:
case VariableType::DMAT3X3:
case VariableType::DMAT3X4:
case VariableType::DMAT4:
case VariableType::DMAT4X2:
case VariableType::DMAT4X3:
case VariableType::DMAT4X4:
case VariableType::DVEC2:
case VariableType::DVEC3:
case VariableType::DVEC4:
{
result = BaseType::F64;
break;
}
case VariableType::INT16:
case VariableType::I16VEC2:
case VariableType::I16VEC3:
case VariableType::I16VEC4:
{
result = BaseType::I16;
break;
}
case VariableType::INT:
case VariableType::IVEC2:
case VariableType::IVEC3:
case VariableType::IVEC4:
{
result = BaseType::I32;
break;
}
case VariableType::INT64:
case VariableType::I64VEC2:
case VariableType::I64VEC3:
case VariableType::I64VEC4:
{
result = BaseType::I64;
break;
}
case VariableType::INT8:
case VariableType::I8VEC2:
case VariableType::I8VEC3:
case VariableType::I8VEC4:
{
result = BaseType::I8;
break;
}
case VariableType::UINT16:
case VariableType::U16VEC2:
case VariableType::U16VEC3:
case VariableType::U16VEC4:
{
result = BaseType::U16;
break;
}
case VariableType::UINT:
case VariableType::UVEC2:
case VariableType::UVEC3:
case VariableType::UVEC4:
{
result = BaseType::U32;
break;
}
case VariableType::UINT64:
case VariableType::U64VEC2:
case VariableType::U64VEC3:
case VariableType::U64VEC4:
{
result = BaseType::U64;
break;
}
case VariableType::UINT8:
case VariableType::U8VEC2:
case VariableType::U8VEC3:
case VariableType::U8VEC4:
{
result = BaseType::U8;
break;
}
default:
{
DE_ASSERT(false);
}
}
return result;
}
deUint32 getComponentSizeBytes(const BaseType& type) const
{
deUint32 result = 0;
switch (type)
{
case BaseType::I8:
case BaseType::U8:
{
result = 1;
break;
}
case BaseType::I16:
case BaseType::U16:
{
result = 2;
break;
}
case BaseType::F32:
case BaseType::I32:
case BaseType::U32:
{
result = 4;
break;
}
case BaseType::F64:
case BaseType::I64:
case BaseType::U64:
{
result = 8;
break;
}
default:
{
DE_ASSERT(false);
}
}
return result;
}
std::string getGLSLForSetters( const StructItem& item,
const deUint32& nResultArrayItem) const
{
std::string result;
for (const auto& currentItem : item.items)
{
if (currentItem.arraySize > 1)
{
result += "for (uint nArrayItem = 0; nArrayItem < " + de::toString(currentItem.arraySize) + "; ++nArrayItem)\n"
"{\n";
}
result += "results[" + de::toString(nResultArrayItem) + "]." + currentItem.name;
if (currentItem.arraySize > 1)
{
result += "[nArrayItem]";
}
result += " = inputBuffer." + currentItem.name;
if (currentItem.arraySize > 1)
{
result += "[nArrayItem]";
}
result += ";\n";
if (currentItem.arraySize > 1)
{
result += "}\n";
}
}
return result;
}
std::string getGLSLForStructItem( const StructItem& item,
const bool& includeOffsetLayoutQualifier,
const bool& targetsInputBuffer) const
{
std::string result;
for (const auto& currentItem : item.items)
{
const bool needsMatrixOrderQualifier = (currentItem.matrixOrder == MatrixMajorOrder::ROW_MAJOR);
const auto variableTypeGLSL = getVariableTypeGLSLType (currentItem.type);
deUint32 nLayoutQualifiersUsed = 0;
const deUint32 nLayoutQualifierUses = ((includeOffsetLayoutQualifier) ? 1 : 0) +
((needsMatrixOrderQualifier) ? 1 : 0);
const bool usesLayoutQualifiers = (nLayoutQualifierUses > 0);
if (usesLayoutQualifiers)
{
result += "layout(";
}
if (includeOffsetLayoutQualifier)
{
result += "offset = " + de::toString((targetsInputBuffer) ? currentItem.inputBufferProps.bufferOffset
: currentItem.resultBufferProps.bufferOffset);
if ( (++nLayoutQualifiersUsed) != nLayoutQualifierUses)
{
result += ", ";
}
}
if (needsMatrixOrderQualifier)
{
result += ((currentItem.matrixOrder == MatrixMajorOrder::COLUMN_MAJOR) ? "column_major"
: "row_major");
if ( (++nLayoutQualifiersUsed) != nLayoutQualifierUses)
{
result += ", ";
}
}
if (usesLayoutQualifiers)
{
result += ") ";
}
result += variableTypeGLSL + std::string(" ") + currentItem.name;
if (currentItem.arraySize != 1)
{
result += "[" + de::toString(currentItem.arraySize) + "]";
}
result += ";\n";
}
return result;
}
tcu::UVec2 getMatrixSize(const VariableType& type) const
{
auto result = tcu::UVec2();
switch (type)
{
case VariableType::DMAT2:
case VariableType::DMAT2X2:
case VariableType::MAT2:
case VariableType::MAT2X2:
{
result = tcu::UVec2(2, 2);
break;
}
case VariableType::DMAT2X3:
case VariableType::MAT2X3:
{
result = tcu::UVec2(2, 3);
break;
}
case VariableType::DMAT2X4:
case VariableType::MAT2X4:
{
result = tcu::UVec2(2, 4);
break;
}
case VariableType::DMAT3:
case VariableType::DMAT3X3:
case VariableType::MAT3:
case VariableType::MAT3X3:
{
result = tcu::UVec2(3, 3);
break;
}
case VariableType::DMAT3X2:
case VariableType::MAT3X2:
{
result = tcu::UVec2(3, 2);
break;
}
case VariableType::DMAT3X4:
case VariableType::MAT3X4:
{
result = tcu::UVec2(3, 4);
break;
}
case VariableType::DMAT4:
case VariableType::DMAT4X4:
case VariableType::MAT4:
case VariableType::MAT4X4:
{
result = tcu::UVec2(4, 4);
break;
}
case VariableType::DMAT4X2:
case VariableType::MAT4X2:
{
result = tcu::UVec2(4, 2);
break;
}
case VariableType::DMAT4X3:
case VariableType::MAT4X3:
{
result = tcu::UVec2(4, 3);
break;
}
default:
{
DE_ASSERT(false);
break;
}
}
return result;
}
deUint32 getNComponents(const VariableType& type) const
{
deUint32 result = 0;
switch (type)
{
case VariableType::DOUBLE:
case VariableType::FLOAT:
case VariableType::INT8:
case VariableType::INT16:
case VariableType::INT64:
case VariableType::INT:
case VariableType::UINT:
case VariableType::UINT8:
case VariableType::UINT16:
case VariableType::UINT64:
{
result = 1;
break;
}
case VariableType::DVEC2:
case VariableType::I8VEC2:
case VariableType::I16VEC2:
case VariableType::I64VEC2:
case VariableType::IVEC2:
case VariableType::U8VEC2:
case VariableType::U16VEC2:
case VariableType::U64VEC2:
case VariableType::UVEC2:
case VariableType::VEC2:
{
result = 2;
break;
}
case VariableType::DVEC3:
case VariableType::I8VEC3:
case VariableType::I16VEC3:
case VariableType::I64VEC3:
case VariableType::IVEC3:
case VariableType::U8VEC3:
case VariableType::U16VEC3:
case VariableType::U64VEC3:
case VariableType::UVEC3:
case VariableType::VEC3:
{
result = 3;
break;
}
case VariableType::DMAT2:
case VariableType::DMAT2X2:
case VariableType::DVEC4:
case VariableType::I8VEC4:
case VariableType::I16VEC4:
case VariableType::I64VEC4:
case VariableType::IVEC4:
case VariableType::MAT2:
case VariableType::MAT2X2:
case VariableType::U8VEC4:
case VariableType::U16VEC4:
case VariableType::U64VEC4:
case VariableType::UVEC4:
case VariableType::VEC4:
{
result = 4;
break;
}
case VariableType::DMAT2X3:
case VariableType::DMAT3X2:
case VariableType::MAT2X3:
case VariableType::MAT3X2:
{
result = 6;
break;
}
case VariableType::DMAT2X4:
case VariableType::DMAT4X2:
case VariableType::MAT2X4:
case VariableType::MAT4X2:
{
result = 8;
break;
}
case VariableType::DMAT3:
case VariableType::DMAT3X3:
case VariableType::MAT3:
case VariableType::MAT3X3:
{
result = 9;
break;
}
case VariableType::DMAT3X4:
case VariableType::DMAT4X3:
case VariableType::MAT3X4:
case VariableType::MAT4X3:
{
result = 12;
break;
}
case VariableType::DMAT4:
case VariableType::DMAT4X4:
case VariableType::MAT4:
case VariableType::MAT4X4:
{
result = 16;
break;
}
default:
{
DE_ASSERT(false);
}
}
return result;
}
deUint32 getNMatrixColumns(const VariableType& type) const
{
deUint32 result = 0;
switch (type)
{
case VariableType::DMAT2:
case VariableType::DMAT2X2:
case VariableType::DMAT2X3:
case VariableType::DMAT2X4:
case VariableType::MAT2:
case VariableType::MAT2X2:
case VariableType::MAT2X3:
case VariableType::MAT2X4:
{
result = 2;
break;
}
case VariableType::DMAT3:
case VariableType::DMAT3X2:
case VariableType::DMAT3X3:
case VariableType::DMAT3X4:
case VariableType::MAT3:
case VariableType::MAT3X2:
case VariableType::MAT3X4:
case VariableType::MAT3X3:
{
result = 3;
break;
}
case VariableType::DMAT4X2:
case VariableType::MAT4X2:
case VariableType::DMAT4X3:
case VariableType::MAT4X3:
case VariableType::DMAT4X4:
case VariableType::DMAT4:
case VariableType::MAT4X4:
case VariableType::MAT4:
{
result = 4;
break;
}
default:
{
DE_ASSERT(false);
}
}
return result;
}
deUint32 getNMatrixRows(const VariableType& type) const
{
deUint32 result = 0;
switch (type)
{
case VariableType::DMAT2:
case VariableType::DMAT2X2:
case VariableType::DMAT3X2:
case VariableType::DMAT4X2:
case VariableType::MAT2:
case VariableType::MAT2X2:
case VariableType::MAT3X2:
case VariableType::MAT4X2:
{
result = 2;
break;
}
case VariableType::DMAT2X3:
case VariableType::DMAT3:
case VariableType::DMAT3X3:
case VariableType::DMAT4X3:
case VariableType::MAT2X3:
case VariableType::MAT3:
case VariableType::MAT3X3:
case VariableType::MAT4X3:
{
result = 3;
break;
}
case VariableType::DMAT2X4:
case VariableType::DMAT3X4:
case VariableType::DMAT4:
case VariableType::DMAT4X4:
case VariableType::MAT2X4:
case VariableType::MAT3X4:
case VariableType::MAT4:
case VariableType::MAT4X4:
{
result = 4;
break;
}
default:
{
DE_ASSERT(false);
}
}
return result;
}
const char* getVariableTypeGLSLType(const VariableType& type) const
{
const char* resultPtr = "!?";
switch (type)
{
case VariableType::DOUBLE: resultPtr = "double"; break;
case VariableType::DMAT2: resultPtr = "dmat2"; break;
case VariableType::DMAT2X2: resultPtr = "dmat2x2"; break;
case VariableType::DMAT2X3: resultPtr = "dmat2x3"; break;
case VariableType::DMAT2X4: resultPtr = "dmat2x4"; break;
case VariableType::DMAT3: resultPtr = "dmat3"; break;
case VariableType::DMAT3X2: resultPtr = "dmat3x2"; break;
case VariableType::DMAT3X3: resultPtr = "dmat3x3"; break;
case VariableType::DMAT3X4: resultPtr = "dmat3x4"; break;
case VariableType::DMAT4: resultPtr = "dmat4"; break;
case VariableType::DMAT4X2: resultPtr = "dmat4x2"; break;
case VariableType::DMAT4X3: resultPtr = "dmat4x3"; break;
case VariableType::DMAT4X4: resultPtr = "dmat4x4"; break;
case VariableType::DVEC2: resultPtr = "dvec2"; break;
case VariableType::DVEC3: resultPtr = "dvec3"; break;
case VariableType::DVEC4: resultPtr = "dvec4"; break;
case VariableType::FLOAT: resultPtr = "float"; break;
case VariableType::INT16: resultPtr = "int16_t"; break;
case VariableType::INT64: resultPtr = "int64_t"; break;
case VariableType::INT8: resultPtr = "int8_t"; break;
case VariableType::INT: resultPtr = "int"; break;
case VariableType::I16VEC2: resultPtr = "i16vec2"; break;
case VariableType::I16VEC3: resultPtr = "i16vec3"; break;
case VariableType::I16VEC4: resultPtr = "i16vec4"; break;
case VariableType::I64VEC2: resultPtr = "i64vec2"; break;
case VariableType::I64VEC3: resultPtr = "i64vec3"; break;
case VariableType::I64VEC4: resultPtr = "i64vec4"; break;
case VariableType::I8VEC2: resultPtr = "i8vec2"; break;
case VariableType::I8VEC3: resultPtr = "i8vec3"; break;
case VariableType::I8VEC4: resultPtr = "i8vec4"; break;
case VariableType::IVEC2: resultPtr = "ivec2"; break;
case VariableType::IVEC3: resultPtr = "ivec3"; break;
case VariableType::IVEC4: resultPtr = "ivec4"; break;
case VariableType::MAT2: resultPtr = "mat2"; break;
case VariableType::MAT2X2: resultPtr = "mat2x2"; break;
case VariableType::MAT2X3: resultPtr = "mat2x3"; break;
case VariableType::MAT2X4: resultPtr = "mat2x4"; break;
case VariableType::MAT3: resultPtr = "mat3"; break;
case VariableType::MAT3X2: resultPtr = "mat3x2"; break;
case VariableType::MAT3X3: resultPtr = "mat3x3"; break;
case VariableType::MAT3X4: resultPtr = "mat3x4"; break;
case VariableType::MAT4: resultPtr = "mat4"; break;
case VariableType::MAT4X2: resultPtr = "mat4x2"; break;
case VariableType::MAT4X3: resultPtr = "mat4x3"; break;
case VariableType::MAT4X4: resultPtr = "mat4x4"; break;
case VariableType::UINT16: resultPtr = "uint16_t"; break;
case VariableType::UINT64: resultPtr = "uint64_t"; break;
case VariableType::UINT8: resultPtr = "uint8_t"; break;
case VariableType::UINT: resultPtr = "uint"; break;
case VariableType::U16VEC2: resultPtr = "u16vec2"; break;
case VariableType::U16VEC3: resultPtr = "u16vec3"; break;
case VariableType::U16VEC4: resultPtr = "u16vec4"; break;
case VariableType::U64VEC2: resultPtr = "u64vec2"; break;
case VariableType::U64VEC3: resultPtr = "u64vec3"; break;
case VariableType::U64VEC4: resultPtr = "u64vec4"; break;
case VariableType::U8VEC2: resultPtr = "u8vec2"; break;
case VariableType::U8VEC3: resultPtr = "u8vec3"; break;
case VariableType::U8VEC4: resultPtr = "u8vec4"; break;
case VariableType::UVEC2: resultPtr = "uvec2"; break;
case VariableType::UVEC3: resultPtr = "uvec3"; break;
case VariableType::UVEC4: resultPtr = "uvec4"; break;
case VariableType::VEC2: resultPtr = "vec2"; break;
case VariableType::VEC3: resultPtr = "vec3"; break;
case VariableType::VEC4: resultPtr = "vec4"; break;
default:
{
DE_ASSERT(false);
}
}
return resultPtr;
}
void initTestItems()
{
de::Random randomNumberGenerator(13567);
const deUint32 testArraySizes[] =
{
3,
7,
5
};
const ShaderGroups shaderGroups[] =
{
ShaderGroups::HIT_GROUP,
ShaderGroups::MISS_GROUP,
};
const auto nTestArraySizes = sizeof(testArraySizes) / sizeof(testArraySizes[0]);
for (const auto& currentVariableType : m_varTypesToTest)
{
const auto currentArraySize = testArraySizes[static_cast<deUint32>(m_testItems.items.size() ) % nTestArraySizes];
Item newItem;
newItem.arraySize = currentArraySize;
newItem.name = "var" + de::toString(m_testItems.items.size() );
newItem.type = currentVariableType;
// TODO: glslang issue.
// newItem.matrixOrder = static_cast<MatrixMajorOrder>(static_cast<deUint32>(m_testItems.items.size() ) % static_cast<deUint32>(MatrixMajorOrder::UNKNOWN) );
newItem.matrixOrder = MatrixMajorOrder::COLUMN_MAJOR;
m_testItems.items.push_back(newItem);
}
// Determine start offsets for matrix elements.
//
// Note: result buffer aways uses std430 layout.
setSTD430MatrixElementOffsets (m_testItems, false /* updateInputBufferProps */);
setSTD430ArrayStrides (m_testItems, false /* updateInputBufferProps */);
setSTD430BufferOffsets (m_testItems, false /* updateInputBufferProps */);
switch (m_testType)
{
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_1:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_2:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_3:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_4:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_5:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_6:
{
setExplicitScalarOffsetMatrixElementOffsets(m_testItems, true /* updateInputBufferProps */);
break;
}
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_1:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_2:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_3:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_4:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_5:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_6:
{
setExplicitSTD430OffsetMatrixElementOffsets(m_testItems, true /* updateInputBufferProps */);
break;
}
case TestType::SHADER_RECORD_BLOCK_SCALAR_1:
case TestType::SHADER_RECORD_BLOCK_SCALAR_2:
case TestType::SHADER_RECORD_BLOCK_SCALAR_3:
case TestType::SHADER_RECORD_BLOCK_SCALAR_4:
case TestType::SHADER_RECORD_BLOCK_SCALAR_5:
case TestType::SHADER_RECORD_BLOCK_SCALAR_6:
{
setScalarMatrixElementOffsets(m_testItems, true /* updateInputBufferProps */);
break;
}
case TestType::SHADER_RECORD_BLOCK_STD430_1:
case TestType::SHADER_RECORD_BLOCK_STD430_2:
case TestType::SHADER_RECORD_BLOCK_STD430_3:
case TestType::SHADER_RECORD_BLOCK_STD430_4:
case TestType::SHADER_RECORD_BLOCK_STD430_5:
case TestType::SHADER_RECORD_BLOCK_STD430_6:
{
setSTD430MatrixElementOffsets(m_testItems, true /* updateInputBufferProps */);
break;
}
default:
{
DE_ASSERT(false);
}
}
// Configure array strides for the variables.
switch (m_testType)
{
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_1:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_2:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_3:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_4:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_5:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_6:
{
setExplicitScalarOffsetArrayStrides(m_testItems, true /* updateInputBufferProps */);
break;
}
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_1:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_2:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_3:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_4:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_5:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_6:
{
setExplicitSTD430OffsetArrayStrides(m_testItems, true /* updateInputBufferProps */);
break;
}
case TestType::SHADER_RECORD_BLOCK_SCALAR_1:
case TestType::SHADER_RECORD_BLOCK_SCALAR_2:
case TestType::SHADER_RECORD_BLOCK_SCALAR_3:
case TestType::SHADER_RECORD_BLOCK_SCALAR_4:
case TestType::SHADER_RECORD_BLOCK_SCALAR_5:
case TestType::SHADER_RECORD_BLOCK_SCALAR_6:
{
setScalarArrayStrides(m_testItems, true /* updateInputBufferProps */);
break;
}
case TestType::SHADER_RECORD_BLOCK_STD430_1:
case TestType::SHADER_RECORD_BLOCK_STD430_2:
case TestType::SHADER_RECORD_BLOCK_STD430_3:
case TestType::SHADER_RECORD_BLOCK_STD430_4:
case TestType::SHADER_RECORD_BLOCK_STD430_5:
case TestType::SHADER_RECORD_BLOCK_STD430_6:
{
setSTD430ArrayStrides(m_testItems, true /* updateInputBufferProps */);
break;
}
default:
{
DE_ASSERT(false);
}
}
// Configure buffer offsets for the variables.
switch (m_testType)
{
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_1:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_2:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_3:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_4:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_5:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_6:
{
setExplicitScalarOffsetBufferOffsets(m_testItems, true /* updateInputBufferProps */);
break;
}
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_1:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_2:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_3:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_4:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_5:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_6:
{
setExplicitSTD430OffsetBufferOffsets(m_testItems, true /* updateInputBufferProps */);
break;
}
case TestType::SHADER_RECORD_BLOCK_SCALAR_1:
case TestType::SHADER_RECORD_BLOCK_SCALAR_2:
case TestType::SHADER_RECORD_BLOCK_SCALAR_3:
case TestType::SHADER_RECORD_BLOCK_SCALAR_4:
case TestType::SHADER_RECORD_BLOCK_SCALAR_5:
case TestType::SHADER_RECORD_BLOCK_SCALAR_6:
{
setScalarBufferOffsets(m_testItems, true /* updateInputBufferProps */);
break;
}
case TestType::SHADER_RECORD_BLOCK_STD430_1:
case TestType::SHADER_RECORD_BLOCK_STD430_2:
case TestType::SHADER_RECORD_BLOCK_STD430_3:
case TestType::SHADER_RECORD_BLOCK_STD430_4:
case TestType::SHADER_RECORD_BLOCK_STD430_5:
case TestType::SHADER_RECORD_BLOCK_STD430_6:
{
setSTD430BufferOffsets(m_testItems, true /* updateInputBufferProps */);
break;
}
default:
{
DE_ASSERT(false);
}
}
// Bake data to be used in the tested buffer.
for (auto& currentTestItem : m_testItems.items)
{
const auto baseType = getBaseType (currentTestItem.type);
const auto componentSizeBytes = getComponentSizeBytes (baseType);
const bool isMatrixType = isMatrix (currentTestItem.type);
const auto nComponents = getNComponents (currentTestItem.type);
const auto nBytesNeeded = currentTestItem.arraySize * currentTestItem.inputBufferProps.arrayStride;
for (const auto& currentShaderGroup : shaderGroups)
{
auto& currentDataVec = currentTestItem.shaderGroupToRecordDataMap[currentShaderGroup];
currentDataVec.resize(nBytesNeeded);
for (deUint32 nArrayItem = 0; nArrayItem < currentTestItem.arraySize; ++nArrayItem)
{
deUint8* currentItemDataPtr = currentDataVec.data() + nArrayItem * currentTestItem.inputBufferProps.arrayStride;
for (deUint32 nComponent = 0; nComponent < nComponents; ++nComponent)
{
switch (baseType)
{
case BaseType::F32:
{
DE_ASSERT(currentItemDataPtr + sizeof(float) <= currentDataVec.data() + currentDataVec.size() );
*reinterpret_cast<float*>(currentItemDataPtr) = randomNumberGenerator.getFloat();
break;
}
case BaseType::F64:
{
DE_ASSERT(currentItemDataPtr + sizeof(double) <= currentDataVec.data() + currentDataVec.size() );
*reinterpret_cast<double*>(currentItemDataPtr) = randomNumberGenerator.getDouble();
break;
}
case BaseType::I8:
{
DE_ASSERT(currentItemDataPtr + sizeof(deInt8) <= currentDataVec.data() + currentDataVec.size() );
*reinterpret_cast<deInt8*>(currentItemDataPtr) = static_cast<deInt8>(randomNumberGenerator.getInt(-128, 127) );
break;
}
case BaseType::I16:
{
DE_ASSERT(currentItemDataPtr + sizeof(deInt16) <= currentDataVec.data() + currentDataVec.size() );
*reinterpret_cast<deInt16*>(currentItemDataPtr) = static_cast<deInt16>(randomNumberGenerator.getInt(-32768, 32767) );
break;
}
case BaseType::I32:
{
DE_ASSERT(currentItemDataPtr + sizeof(deInt32) <= currentDataVec.data() + currentDataVec.size() );
*reinterpret_cast<deInt32*>(currentItemDataPtr) = randomNumberGenerator.getInt(static_cast<int>(-2147483648LL), static_cast<int>(2147483647LL) );
break;
}
case BaseType::I64:
{
DE_ASSERT(currentItemDataPtr + sizeof(deInt64) <= currentDataVec.data() + currentDataVec.size() );
*reinterpret_cast<deInt64*>(currentItemDataPtr) = randomNumberGenerator.getInt64();
break;
}
case BaseType::U8:
{
DE_ASSERT(currentItemDataPtr + sizeof(deUint8) <= currentDataVec.data() + currentDataVec.size() );
*reinterpret_cast<deUint8*>(currentItemDataPtr) = randomNumberGenerator.getUint8();
break;
}
case BaseType::U16:
{
DE_ASSERT(currentItemDataPtr + sizeof(deUint16) <= currentDataVec.data() + currentDataVec.size() );
*reinterpret_cast<deUint16*>(currentItemDataPtr) = randomNumberGenerator.getUint16();
break;
}
case BaseType::U32:
{
DE_ASSERT(currentItemDataPtr + sizeof(deUint32) <= currentDataVec.data() + currentDataVec.size() );
*reinterpret_cast<deUint32*>(currentItemDataPtr) = randomNumberGenerator.getUint32();
break;
}
case BaseType::U64:
{
DE_ASSERT(currentItemDataPtr + sizeof(deUint64) <= currentDataVec.data() + currentDataVec.size() );
*reinterpret_cast<deUint64*>(currentItemDataPtr) = randomNumberGenerator.getUint64();
break;
}
default:
{
DE_ASSERT(false);
}
}
if (isMatrixType)
{
if (nComponent != (nComponents - 1) )
{
const auto delta = currentTestItem.inputBufferProps.matrixElementStartOffsets.at(nComponent + 1) - currentTestItem.inputBufferProps.matrixElementStartOffsets.at(nComponent + 0);
DE_ASSERT(delta >= componentSizeBytes);
currentItemDataPtr += delta;
}
}
else
{
currentItemDataPtr += componentSizeBytes;
}
}
}
}
}
// Merge individual member data into coalesced buffers.
for (const auto& currentShaderGroup : shaderGroups)
{
auto& resultVec = m_shaderGroupToRecordDataMap[currentShaderGroup];
{
const auto& lastItem = m_testItems.items.back();
resultVec.resize(lastItem.inputBufferProps.bufferOffset + lastItem.shaderGroupToRecordDataMap.at(currentShaderGroup).size() );
}
for (const auto& currentVariable : m_testItems.items)
{
const auto& currentVariableDataVec = currentVariable.shaderGroupToRecordDataMap.at(currentShaderGroup);
DE_ASSERT(resultVec.size() >= currentVariable.inputBufferProps.bufferOffset + currentVariableDataVec.size());
memcpy( resultVec.data() + currentVariable.inputBufferProps.bufferOffset,
currentVariableDataVec.data(),
currentVariableDataVec.size() );
}
}
}
bool isMatrix(const VariableType& type) const
{
bool result = false;
switch (type)
{
case VariableType::DMAT2:
case VariableType::DMAT2X2:
case VariableType::DMAT2X3:
case VariableType::DMAT2X4:
case VariableType::DMAT3:
case VariableType::DMAT3X2:
case VariableType::DMAT3X3:
case VariableType::DMAT3X4:
case VariableType::DMAT4:
case VariableType::DMAT4X2:
case VariableType::DMAT4X3:
case VariableType::DMAT4X4:
case VariableType::MAT2:
case VariableType::MAT2X2:
case VariableType::MAT2X3:
case VariableType::MAT2X4:
case VariableType::MAT3:
case VariableType::MAT3X2:
case VariableType::MAT3X3:
case VariableType::MAT3X4:
case VariableType::MAT4:
case VariableType::MAT4X2:
case VariableType::MAT4X3:
case VariableType::MAT4X4:
{
result = true;
break;
}
case VariableType::DOUBLE:
case VariableType::DVEC2:
case VariableType::DVEC3:
case VariableType::DVEC4:
case VariableType::FLOAT:
case VariableType::INT8:
case VariableType::INT64:
case VariableType::INT16:
case VariableType::INT:
case VariableType::I16VEC2:
case VariableType::I16VEC3:
case VariableType::I16VEC4:
case VariableType::I64VEC2:
case VariableType::I64VEC3:
case VariableType::I64VEC4:
case VariableType::I8VEC2:
case VariableType::I8VEC3:
case VariableType::I8VEC4:
case VariableType::IVEC2:
case VariableType::IVEC3:
case VariableType::IVEC4:
case VariableType::UINT8:
case VariableType::UINT64:
case VariableType::UINT16:
case VariableType::UINT:
case VariableType::U16VEC2:
case VariableType::U16VEC3:
case VariableType::U16VEC4:
case VariableType::U64VEC2:
case VariableType::U64VEC3:
case VariableType::U64VEC4:
case VariableType::U8VEC2:
case VariableType::U8VEC3:
case VariableType::U8VEC4:
case VariableType::UVEC2:
case VariableType::UVEC3:
case VariableType::UVEC4:
case VariableType::VEC2:
case VariableType::VEC3:
case VariableType::VEC4:
{
result = false;
break;
}
default:
{
DE_ASSERT(false);
}
}
return result;
}
void setExplicitScalarOffsetArrayStrides( StructItem& inputStruct,
const bool& updateInputBufferProps)
{
return setScalarArrayStrides(inputStruct, updateInputBufferProps);
}
void setExplicitScalarOffsetBufferOffsets( StructItem& inputStruct,
const bool& updateInputBufferProps)
{
deUint32 nBytesConsumed = 0;
for (auto& currentItem : inputStruct.items)
{
const auto baseType = getBaseType (currentItem.type);
auto& bufferProps = (updateInputBufferProps) ? currentItem.inputBufferProps : currentItem.resultBufferProps;
const auto componentSizeBytes = getComponentSizeBytes (baseType);
const auto isMatrixVariable = isMatrix (currentItem.type);
const auto nComponents = getNComponents (currentItem.type);
bufferProps.bufferOffset = de::roundUp(nBytesConsumed, componentSizeBytes * 2);
if (isMatrixVariable)
{
nBytesConsumed = bufferProps.bufferOffset + currentItem.arraySize * bufferProps.arrayStride;
}
else
{
nBytesConsumed = bufferProps.bufferOffset + currentItem.arraySize * componentSizeBytes * nComponents;
}
}
}
void setExplicitScalarOffsetElementOffsets( StructItem& inputStruct,
const bool& updateInputBufferProps)
{
return setScalarMatrixElementOffsets(inputStruct, updateInputBufferProps);
}
void setExplicitScalarOffsetMatrixElementOffsets( StructItem& inputStruct,
const bool& updateInputBufferProps)
{
return setScalarMatrixElementOffsets(inputStruct, updateInputBufferProps);
}
void setExplicitSTD430OffsetArrayStrides( StructItem& inputStruct,
const bool& updateInputBufferProps)
{
return setSTD430ArrayStrides(inputStruct, updateInputBufferProps);
}
void setExplicitSTD430OffsetBufferOffsets( StructItem& inputStruct,
const bool& updateInputBufferProps)
{
deUint32 nBytesConsumed = 0;
for (auto& currentItem : inputStruct.items)
{
const auto baseType = getBaseType (currentItem.type);
auto& bufferProps = (updateInputBufferProps) ? currentItem.inputBufferProps : currentItem.resultBufferProps;
const auto componentSizeBytes = getComponentSizeBytes (baseType);
const auto isMatrixVariable = isMatrix (currentItem.type);
const auto nComponents = getNComponents (currentItem.type);
deUint32 requiredAlignment = 0;
deUint32 nMatrixRows = 0;
if (isMatrixVariable)
{
nMatrixRows = getNMatrixRows(currentItem.type);
if (nMatrixRows == 3)
{
nMatrixRows = 4;
}
requiredAlignment = nMatrixRows * componentSizeBytes;
}
else
if (nComponents == 1)
{
DE_ASSERT( (baseType == BaseType::F32) ||
(baseType == BaseType::F64) ||
(baseType == BaseType::I16) ||
(baseType == BaseType::I32) ||
(baseType == BaseType::I64) ||
(baseType == BaseType::I8) ||
(baseType == BaseType::U16) ||
(baseType == BaseType::U32) ||
(baseType == BaseType::U64) ||
(baseType == BaseType::U8) );
requiredAlignment = componentSizeBytes;
}
else
if (nComponents == 2)
{
requiredAlignment = 2 * componentSizeBytes;
}
else
{
requiredAlignment = 4 * componentSizeBytes;
}
bufferProps.bufferOffset = de::roundUp(nBytesConsumed, requiredAlignment * 2);
if (isMatrixVariable)
{
nBytesConsumed = bufferProps.bufferOffset + currentItem.arraySize * bufferProps.arrayStride;
}
else
{
nBytesConsumed = bufferProps.bufferOffset + currentItem.arraySize * componentSizeBytes * ((nComponents == 3) ? 4 : nComponents);
}
}
}
void setExplicitSTD430OffsetElementOffsets( StructItem& inputStruct,
const bool& updateInputBufferProps)
{
return setSTD430MatrixElementOffsets(inputStruct, updateInputBufferProps);
}
void setExplicitSTD430OffsetMatrixElementOffsets( StructItem& inputStruct,
const bool& updateInputBufferProps)
{
return setSTD430MatrixElementOffsets(inputStruct, updateInputBufferProps);
}
void setSTD430ArrayStrides( StructItem& inputStruct,
const bool& updateInputBufferProps)
{
for (auto& currentItem : inputStruct.items)
{
const auto baseType = getBaseType (currentItem.type);
auto& bufferProps = (updateInputBufferProps) ? currentItem.inputBufferProps : currentItem.resultBufferProps;
const auto componentSizeBytes = getComponentSizeBytes (baseType);
const auto isMatrixVariable = isMatrix (currentItem.type);
const auto nComponents = getNComponents (currentItem.type);
deUint32 requiredStride = 0;
if (isMatrixVariable)
{
auto nMatrixColumns = getNMatrixColumns (currentItem.type);
auto nMatrixRows = getNMatrixRows (currentItem.type);
if (nMatrixRows == 3)
{
nMatrixRows = 4;
}
requiredStride = nMatrixRows * nMatrixColumns * componentSizeBytes;
}
else
{
requiredStride = componentSizeBytes * ((nComponents == 3) ? 4
: nComponents);
}
bufferProps.arrayStride = requiredStride;
}
}
void setSTD430BufferOffsets(StructItem& inputStruct,
const bool& updateInputBufferProps)
{
deUint32 nBytesConsumed = 0;
for (auto& currentItem : inputStruct.items)
{
const auto baseType = getBaseType (currentItem.type);
auto& bufferProps = (updateInputBufferProps) ? currentItem.inputBufferProps : currentItem.resultBufferProps;
const auto componentSizeBytes = getComponentSizeBytes (baseType);
const auto isMatrixVariable = isMatrix (currentItem.type);
const auto nComponents = getNComponents (currentItem.type);
deUint32 requiredAlignment = 0;
deUint32 nMatrixRows = 0;
if (isMatrixVariable)
{
nMatrixRows = getNMatrixRows(currentItem.type);
if (nMatrixRows == 3)
{
nMatrixRows = 4;
}
requiredAlignment = nMatrixRows * componentSizeBytes;
}
else
if (nComponents == 1)
{
DE_ASSERT( (baseType == BaseType::F32) ||
(baseType == BaseType::F64) ||
(baseType == BaseType::I16) ||
(baseType == BaseType::I32) ||
(baseType == BaseType::I64) ||
(baseType == BaseType::I8) ||
(baseType == BaseType::U16) ||
(baseType == BaseType::U32) ||
(baseType == BaseType::U64) ||
(baseType == BaseType::U8) );
requiredAlignment = componentSizeBytes;
}
else
if (nComponents == 2)
{
requiredAlignment = 2 * componentSizeBytes;
}
else
{
requiredAlignment = 4 * componentSizeBytes;
}
bufferProps.bufferOffset = de::roundUp(nBytesConsumed, requiredAlignment);
if (isMatrixVariable)
{
nBytesConsumed = bufferProps.bufferOffset + currentItem.arraySize * bufferProps.arrayStride;
}
else
{
nBytesConsumed = bufferProps.bufferOffset + currentItem.arraySize * componentSizeBytes * ((nComponents == 3) ? 4 : nComponents);
}
}
}
void setScalarArrayStrides( StructItem& inputStruct,
const bool& updateInputBufferProps)
{
for (auto& currentItem : inputStruct.items)
{
const auto baseType = getBaseType (currentItem.type);
auto& bufferProps = (updateInputBufferProps) ? currentItem.inputBufferProps : currentItem.resultBufferProps;
const auto componentSizeBytes = getComponentSizeBytes (baseType);
const auto isMatrixVariable = isMatrix (currentItem.type);
const auto nComponents = getNComponents (currentItem.type);
if (isMatrixVariable)
{
auto nMatrixColumns = getNMatrixColumns (currentItem.type);
auto nMatrixRows = getNMatrixRows (currentItem.type);
bufferProps.arrayStride = nMatrixRows * nMatrixColumns * componentSizeBytes;
}
else
{
bufferProps.arrayStride = componentSizeBytes * nComponents;
}
}
}
void setScalarBufferOffsets(StructItem& inputStruct,
const bool& updateInputBufferProps)
{
deUint32 nBytesConsumed = 0;
for (auto& currentItem : inputStruct.items)
{
const auto baseType = getBaseType (currentItem.type);
auto& bufferProps = (updateInputBufferProps) ? currentItem.inputBufferProps : currentItem.resultBufferProps;
const auto componentSizeBytes = getComponentSizeBytes (baseType);
const auto isMatrixVariable = isMatrix (currentItem.type);
const auto nComponents = getNComponents (currentItem.type);
bufferProps.bufferOffset = de::roundUp(nBytesConsumed, componentSizeBytes);
if (isMatrixVariable)
{
nBytesConsumed = bufferProps.bufferOffset + currentItem.arraySize * bufferProps.arrayStride;
}
else
{
nBytesConsumed = bufferProps.bufferOffset + currentItem.arraySize * componentSizeBytes * nComponents;
}
}
}
void setScalarMatrixElementOffsets( StructItem& inputStruct,
const bool& updateInputBufferProps)
{
for (auto& currentVariable : inputStruct.items)
{
if (isMatrix(currentVariable.type))
{
auto& bufferProps = (updateInputBufferProps) ? currentVariable.inputBufferProps : currentVariable.resultBufferProps;
const auto componentSizeBytes = getComponentSizeBytes(getBaseType(currentVariable.type) );
deUint32 currentMatrixElementOffset = 0;
const auto nMatrixColumns = getNMatrixColumns (currentVariable.type);
const auto nMatrixRows = getNMatrixRows (currentVariable.type);
for (deUint32 nMatrixColumn = 0; nMatrixColumn < nMatrixColumns; ++nMatrixColumn)
{
currentMatrixElementOffset = de::roundUp( nMatrixRows * componentSizeBytes * nMatrixColumn,
componentSizeBytes);
for (deUint32 nMatrixRow = 0; nMatrixRow < nMatrixRows; ++nMatrixRow)
{
bufferProps.matrixElementStartOffsets.push_back(currentMatrixElementOffset);
currentMatrixElementOffset += componentSizeBytes;
}
}
}
}
}
void setSTD430MatrixElementOffsets( StructItem& inputStruct,
const bool& updateInputBufferProps)
{
for (auto& currentVariable : inputStruct.items)
{
if (isMatrix(currentVariable.type))
{
auto& bufferProps = (updateInputBufferProps) ? currentVariable.inputBufferProps : currentVariable.resultBufferProps;
const auto componentSizeBytes = getComponentSizeBytes(getBaseType(currentVariable.type) );
deUint32 currentMatrixElementOffset = 0;
auto nMatrixColumns = getNMatrixColumns (currentVariable.type);
auto nMatrixRows = getNMatrixRows (currentVariable.type);
if (currentVariable.matrixOrder == MatrixMajorOrder::COLUMN_MAJOR)
{
for (deUint32 nMatrixColumn = 0; nMatrixColumn < nMatrixColumns; ++nMatrixColumn)
{
currentMatrixElementOffset = de::roundUp( static_cast<deUint32>(nMatrixRows * componentSizeBytes * nMatrixColumn),
static_cast<deUint32>(((nMatrixRows == 3) ? 4 : nMatrixRows) * componentSizeBytes));
for (deUint32 nMatrixRow = 0; nMatrixRow < nMatrixRows; ++nMatrixRow)
{
bufferProps.matrixElementStartOffsets.push_back(currentMatrixElementOffset);
currentMatrixElementOffset += componentSizeBytes;
}
}
}
else
{
// TODO
DE_ASSERT(false);
}
}
}
}
// Private variables
const tcu::UVec3 m_gridSizeXYZ;
const TestType m_testType;
const std::vector<VariableType> m_varTypesToTest;
deUint32 m_resultBufferSize;
deUint32 m_shaderRecordSize;
StructItem m_testItems;
std::map<ShaderGroups, std::vector<deUint8> > m_shaderGroupToRecordDataMap;
std::map<VkShaderStageFlagBits, deUint32> m_shaderStageToResultBufferOffset;
std::unique_ptr<GridASProvider> m_asProviderPtr;
std::unique_ptr<TopLevelAccelerationStructure> m_tlPtr;
};
class RecursiveTracesTest : public TestBase
{
public:
RecursiveTracesTest( const GeometryType& geometryType,
const AccelerationStructureLayout& asStructureLayout,
const deUint32& depthToUse)
: m_asStructureLayout (asStructureLayout),
m_geometryType (geometryType),
m_depthToUse (depthToUse),
m_nRaysToTest (512),
m_maxResultBufferSizePermitted (512 * 1024768)
{
const auto nItemsExpectedPerRay = static_cast<deUint32>((1 << (m_depthToUse + 0)) - 1);
const auto nItemsExpectedPerRayInclRgen = static_cast<deUint32>((1 << (m_depthToUse + 1)) - 1);
m_nResultItemsExpected = nItemsExpectedPerRayInclRgen * m_nRaysToTest;
m_nCHitInvocationsExpected = nItemsExpectedPerRay * m_nRaysToTest;
m_nMissInvocationsExpected = nItemsExpectedPerRay * m_nRaysToTest;
{
const deUint32 nPreambleBytes = sizeof(deUint32) * 3;
const deUint32 resultItemSize = sizeof(deUint32) * 4;
m_nMaxResultItemsPermitted = (m_maxResultBufferSizePermitted - nPreambleBytes) / resultItemSize;
}
}
~RecursiveTracesTest()
{
/* Stub */
}
std::vector<std::string> getAHitShaderCollectionShaderNames() const final
{
return m_ahitShaderNameVec;
}
std::vector<std::string> getCHitShaderCollectionShaderNames() const final
{
return m_chitShaderNameVec;
}
tcu::UVec3 getDispatchSize() const final
{
DE_ASSERT(m_nRaysToTest != 0);
return tcu::UVec3(m_nRaysToTest, 1u, 1u);
}
std::vector<std::string> getIntersectionShaderCollectionShaderNames() const final
{
const auto nIntersectionShaders = ( (m_geometryType == GeometryType::AABB) ||
(m_geometryType == GeometryType::AABB_AND_TRIANGLES) ) ? m_depthToUse
: 0;
return std::vector<std::string>(nIntersectionShaders,
{"intersection0"});
}
deUint32 getMaxRecursionDepthUsed() const final
{
return m_depthToUse;
}
std::vector<std::string> getMissShaderCollectionShaderNames() const final
{
return m_missShaderNameVec;
}
deUint32 getResultBufferSize() const final
{
DE_ASSERT(m_depthToUse < 30); //< due to how nItemsExpectedPerRay is stored.
DE_ASSERT(m_nRaysToTest != 0);
/* NOTE: A single item is generated by rgen shader stage which is invoked once per each initial ray.
*
* Each ray at level N generates two result items.
*
* Thus, for a single initial traced ray, we need sum(2^depth)=2^(depth+1)-1 items.
*/
const auto nItemsExpectedPerRay = static_cast<deUint32>((1 << (m_depthToUse + 1)) - 1);
const auto nResultItemsExpected = de::min(nItemsExpectedPerRay * m_nRaysToTest, m_nMaxResultItemsPermitted);
const auto resultItemSize = static_cast<deUint32>(sizeof(deUint32) * 4 /* nOriginRay, stage, depth, parentResultItem */);
return static_cast<deUint32>(sizeof(deUint32) * 3 /* nItemsRegistered, nCHitInvocations, nMissInvocations */) + nResultItemsExpected * resultItemSize;
}
VkSpecializationInfo* getSpecializationInfoPtr(const VkShaderStageFlagBits& shaderStage) final
{
VkSpecializationInfo* resultPtr = nullptr;
if (shaderStage == VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR ||
shaderStage == VK_SHADER_STAGE_MISS_BIT_KHR)
{
resultPtr = &m_specializationInfo;
}
return resultPtr;
}
std::vector<TopLevelAccelerationStructure*> getTLASPtrVecToBind() const final
{
DE_ASSERT(m_tlPtr != nullptr);
return {m_tlPtr.get() };
}
bool init( vkt::Context& /* context */,
RayTracingProperties* /* rtPropsPtr */) final
{
m_specializationEntry.constantID = 1;
m_specializationEntry.offset = 0;
m_specializationEntry.size = sizeof(deUint32);
m_specializationInfo.dataSize = sizeof(deUint32);
m_specializationInfo.mapEntryCount = 1;
m_specializationInfo.pData = &m_depthToUse;
m_specializationInfo.pMapEntries = &m_specializationEntry;
return true;
}
void initAS(vkt::Context& context,
RayTracingProperties* /* rtPropertiesPtr */,
VkCommandBuffer commandBuffer) final
{
std::unique_ptr<GridASProvider> asProviderPtr(
new GridASProvider( tcu::Vec3 (0, 0, 0), /* gridStartXYZ */
tcu::Vec3 (1, 1, 1), /* gridCellSizeXYZ */
tcu::UVec3(1, 1, 1),
tcu::Vec3 (2, 0, 2), /* gridInterCellDeltaXYZ */
m_geometryType)
);
m_tlPtr = asProviderPtr->createTLAS( context,
m_asStructureLayout,
commandBuffer,
0, /* bottomLevelGeometryFlags */
nullptr, /* optASPropertyProviderPtr */
nullptr); /* optASFeedbackPtr */
}
void initPrograms(SourceCollections& programCollection) const final
{
const auto nLocationsPerPayload = 3; /* 3 scalar uints */
const vk::ShaderBuildOptions buildOptions( programCollection.usedVulkanVersion,
vk::SPIRV_VERSION_1_4,
0u, /* flags */
true); /* allowSpirv14 */
std::vector<std::string> rayPayloadDefinitionVec (m_depthToUse);
std::vector<std::string> rayPayloadInDefinitionVec(m_depthToUse);
for (deUint32 nLevel = 0; nLevel < m_depthToUse; ++nLevel)
{
rayPayloadDefinitionVec.at(nLevel) =
"layout(location = " + de::toString(nLocationsPerPayload * nLevel) + ") rayPayloadEXT block\n"
"{\n"
" uint currentDepth;\n"
" uint currentNOriginRay;\n"
" uint currentResultItem;\n"
"};\n";
rayPayloadInDefinitionVec.at(nLevel) =
"layout(location = " + de::toString(nLocationsPerPayload * nLevel) + ") rayPayloadInEXT block\n"
"{\n"
" uint parentDepth;\n"
" uint parentNOriginRay;\n"
" uint parentResultItem;\n"
"};\n";
}
const std::string constantVariableDefinition =
"layout(constant_id = 1) const uint MAX_RECURSIVE_DEPTH = " + de::toString(m_depthToUse) + ";\n";
const char* resultBufferDefinition =
"struct ResultData\n"
"{\n"
" uint nOriginRay;\n"
" uint shaderStage;\n"
" uint depth;\n"
" uint callerResultItem;\n"
"};\n"
"\n"
"layout(set = 0, binding = 0, std430) buffer result\n"
"{\n"
" uint nItemsStored;\n"
" uint nCHitInvocations;\n"
" uint nMissInvocations;\n"
" ResultData resultItems[];\n"
"};\n";
{
m_ahitShaderNameVec.resize(m_depthToUse);
for (deUint32 nLevel = 0; nLevel < m_depthToUse; ++nLevel)
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
+ de::toString (resultBufferDefinition)
+ rayPayloadInDefinitionVec.at (nLevel) +
"\n"
"void main()\n"
"{\n"
/* Stub - don't care */
"}\n";
m_ahitShaderNameVec.at(nLevel) = std::string("ahit") + de::toString(nLevel);
programCollection.glslSources.add(m_ahitShaderNameVec.at(nLevel) ) << glu::AnyHitSource(css.str() ) << buildOptions;
}
}
{
m_chitShaderNameVec.resize(m_depthToUse);
for (deUint32 nLevel = 0; nLevel < m_depthToUse; ++nLevel)
{
std::stringstream css;
const bool shouldTraceRays = (nLevel != (m_depthToUse - 1) );
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"layout(set = 0, binding = 1) uniform accelerationStructureEXT accelerationStructure;\n"
"\n"
+ constantVariableDefinition
+ de::toString(resultBufferDefinition)
+ de::toString(rayPayloadInDefinitionVec.at(nLevel) );
if (shouldTraceRays)
{
css << rayPayloadDefinitionVec.at(nLevel + 1);
}
css <<
"\n"
"void main()\n"
"{\n"
" uint nItem = atomicAdd(nItemsStored, 1);\n"
"\n"
" atomicAdd(nCHitInvocations, 1);\n"
"\n"
" if (nItem < " + de::toString(m_nMaxResultItemsPermitted) + ")\n"
" {\n"
" resultItems[nItem].callerResultItem = parentResultItem;\n"
" resultItems[nItem].depth = parentDepth;\n"
" resultItems[nItem].nOriginRay = parentNOriginRay;\n"
" resultItems[nItem].shaderStage = 1;\n"
" }\n"
"\n";
if (shouldTraceRays)
{
css <<
" if (parentDepth < MAX_RECURSIVE_DEPTH - 1)\n"
" {\n"
" currentDepth = parentDepth + 1;\n"
" currentNOriginRay = parentNOriginRay;\n"
" currentResultItem = nItem;\n"
"\n"
" vec3 cellStartXYZ = vec3(0.0, 0.0, 0.0);\n"
" vec3 cellEndXYZ = cellStartXYZ + vec3(1.0);\n"
" vec3 targetHit = mix(cellStartXYZ, cellEndXYZ, vec3(0.5) );\n"
" vec3 targetMiss = targetHit + vec3(0, 10, 0);\n"
" vec3 origin = targetHit - vec3(1, 0, 0);\n"
" vec3 directionHit = normalize(targetHit - origin);\n"
" vec3 directionMiss = normalize(targetMiss - origin);\n"
" uint rayFlags = 0;\n"
" uint cullMask = 0xFF;\n"
" float tmin = 0.001;\n"
" float tmax = 5.0;\n"
"\n"
" traceRayEXT(accelerationStructure, rayFlags, cullMask, " + de::toString(nLevel + 1) + ", 0, 0, origin, tmin, directionHit, tmax, " + de::toString(nLocationsPerPayload * (nLevel + 1) ) + ");\n"
" traceRayEXT(accelerationStructure, rayFlags, cullMask, " + de::toString(nLevel + 1) + ", 0, 0, origin, tmin, directionMiss, tmax, " + de::toString(nLocationsPerPayload * (nLevel + 1) ) + ");\n"
" }\n"
"\n";
}
css << "}\n";
m_chitShaderNameVec.at(nLevel) = std::string("chit") + de::toString(nLevel);
programCollection.glslSources.add(m_chitShaderNameVec.at(nLevel) ) << glu::ClosestHitSource(css.str() ) << buildOptions;
}
}
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"void main()\n"
"{\n"
" reportIntersectionEXT(0.95f, 0);\n"
"}\n";
// There is stack caching code that assumes it knows which shader groups are what, but that doesn't apply to
// this test. The other hit group shaders don't hit this issue because they don't use the canonical name, so
// de-canonicalize the name to work around that
programCollection.glslSources.add("intersection0") << glu::IntersectionSource(css.str() ) << buildOptions;
}
{
m_missShaderNameVec.resize(m_depthToUse);
for (deUint32 nLevel = 0; nLevel < m_depthToUse; ++nLevel)
{
std::stringstream css;
const bool shouldTraceRays = (nLevel != (m_depthToUse - 1) );
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"layout(set = 0, binding = 1) uniform accelerationStructureEXT accelerationStructure;\n"
"\n"
+ constantVariableDefinition
+ de::toString(resultBufferDefinition)
+ de::toString(rayPayloadInDefinitionVec.at(nLevel) );
if (shouldTraceRays)
{
css << rayPayloadDefinitionVec.at(nLevel + 1);
}
css <<
"\n"
"void main()\n"
"{\n"
" uint nItem = atomicAdd(nItemsStored, 1);\n"
"\n"
" atomicAdd(nMissInvocations, 1);\n"
"\n"
" if (nItem < " + de::toString(m_nMaxResultItemsPermitted) + ")\n"
" {\n"
" resultItems[nItem].depth = parentDepth;\n"
" resultItems[nItem].nOriginRay = parentNOriginRay;\n"
" resultItems[nItem].callerResultItem = parentResultItem;\n"
" resultItems[nItem].shaderStage = 2;\n"
" }\n"
"\n";
if (shouldTraceRays)
{
css <<
" if (parentDepth < MAX_RECURSIVE_DEPTH - 1)\n"
" {\n"
" currentDepth = parentDepth + 1;\n"
" currentNOriginRay = parentNOriginRay;\n"
" currentResultItem = nItem;\n"
"\n"
" vec3 cellStartXYZ = vec3(0.0, 0.0, 0.0);\n"
" vec3 cellEndXYZ = cellStartXYZ + vec3(1.0);\n"
" vec3 targetHit = mix(cellStartXYZ, cellEndXYZ, vec3(0.5) );\n"
" vec3 targetMiss = targetHit + vec3(0, 10, 0);\n"
" vec3 origin = targetHit - vec3(1, 0, 0);\n"
" vec3 directionHit = normalize(targetHit - origin);\n"
" vec3 directionMiss = normalize(targetMiss - origin);\n"
"\n"
" uint rayFlags = 0;\n"
" uint cullMask = 0xFF;\n"
" float tmin = 0.001;\n"
" float tmax = 5.0;\n"
"\n"
" traceRayEXT(accelerationStructure, rayFlags, cullMask, " + de::toString(nLevel + 1) + ", 0, 0, origin, tmin, directionHit, tmax, " + de::toString(nLocationsPerPayload * (nLevel + 1) ) + ");\n"
" traceRayEXT(accelerationStructure, rayFlags, cullMask, " + de::toString(nLevel + 1) + ", 0, 0, origin, tmin, directionMiss, tmax, " + de::toString(nLocationsPerPayload * (nLevel + 1) ) + ");\n"
" }\n";
}
css << "}\n";
m_missShaderNameVec.at(nLevel) = "miss" + de::toString(nLevel);
programCollection.glslSources.add(m_missShaderNameVec.at(nLevel)) << glu::MissSource(css.str() ) << buildOptions;
}
}
{
const std::string rayPayloadDefinition = ((m_depthToUse == 0u) ? "" : rayPayloadDefinitionVec.at(0));
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"layout(set = 0, binding = 1) uniform accelerationStructureEXT accelerationStructure;\n"
"\n"
+ de::toString(resultBufferDefinition)
+ rayPayloadDefinition +
"void main()\n"
"{\n"
" uint nInvocation = gl_LaunchIDEXT.z * gl_LaunchSizeEXT.x * gl_LaunchSizeEXT.y + gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x;\n"
" uint rayFlags = 0;\n"
" float tmin = 0.001;\n"
" float tmax = 9.0;\n"
"\n"
" uint cullMask = 0xFF;\n"
" vec3 cellStartXYZ = vec3(0.0, 0.0, 0.0);\n"
" vec3 cellEndXYZ = cellStartXYZ + vec3(1.0);\n"
" vec3 targetHit = mix(cellStartXYZ, cellEndXYZ, vec3(0.5) );\n"
" vec3 targetMiss = targetHit + vec3(0, 10, 0);\n"
" vec3 origin = targetHit - vec3(1, 0, 0);\n"
" vec3 directionHit = normalize(targetHit - origin);\n"
" vec3 directionMiss = normalize(targetMiss - origin);\n"
"\n"
" uint nItem = atomicAdd(nItemsStored, 1);\n"
"\n"
" if (nItem < " + de::toString(m_nMaxResultItemsPermitted) + ")\n"
" {\n"
" resultItems[nItem].callerResultItem = 0xFFFFFFFF;\n"
" resultItems[nItem].depth = 0;\n"
" resultItems[nItem].nOriginRay = nInvocation;\n"
" resultItems[nItem].shaderStage = 3;\n"
" }\n"
"\n"
+ ((m_depthToUse == 0u) ? "" :
" currentDepth = 0;\n"
" currentNOriginRay = nInvocation;\n"
" currentResultItem = nItem;\n"
"\n"
" traceRayEXT(accelerationStructure, rayFlags, cullMask, 0, 0, 0, origin, tmin, directionHit, tmax, 0);\n"
" traceRayEXT(accelerationStructure, rayFlags, cullMask, 0, 0, 0, origin, tmin, directionMiss, tmax, 0);\n"
) +
"}\n";
programCollection.glslSources.add("rgen") << glu::RaygenSource(css.str() ) << buildOptions;
}
}
void resetTLAS() final
{
m_tlPtr.reset();
}
bool verifyResultBuffer (const void* resultDataPtr) const final
{
const deUint32* resultU32Ptr = reinterpret_cast<const deUint32*>(resultDataPtr);
bool result = false;
auto nItemsStored = *resultU32Ptr;
const auto nCHitInvocations = *(resultU32Ptr + 1);
const auto nMissInvocations = *(resultU32Ptr + 2);
const bool doFullCheck = (m_nResultItemsExpected < m_nMaxResultItemsPermitted);
struct ResultItem
{
deUint32 depth;
deUint32 nOriginRay;
deUint32 nParentNode;
VkShaderStageFlagBits stage;
ResultItem* childCHitNodePtr;
ResultItem* childMissNodePtr;
ResultItem()
: depth (0xFFFFFFFFu),
nOriginRay (0xFFFFFFFFu),
nParentNode (0xFFFFFFFFu),
stage (VK_SHADER_STAGE_ALL),
childCHitNodePtr (nullptr),
childMissNodePtr (nullptr)
{
/* Stub */
}
};
std::map<deUint32, ResultItem*> nItemToResultItemPtrMap;
std::map<deUint32, std::vector<std::unique_ptr<ResultItem> > > nRayToResultItemPtrVecMap;
std::map<deUint32, std::map<deUint32, std::vector<ResultItem*> > > nRayToNLevelToResultItemPtrVecMap;
if (doFullCheck)
{
if (nItemsStored != m_nResultItemsExpected)
{
goto end;
}
}
else
{
// Test shaders always use an atomic add to obtain a unique index, at which they should write the result item.
// Hence, the value we read back from the result buffer's preamble does not actually indicate how many items
// are available for reading, since a partial (!= full) check implies our result buffer only contains a fraction
// of all expected items (since more items would simply not fit in).
//
// Make sure to use a correct value in subsequent checks.
if (nItemsStored < m_nResultItemsExpected)
{
goto end;
}
nItemsStored = m_nMaxResultItemsPermitted;
}
if (nCHitInvocations != m_nCHitInvocationsExpected)
{
goto end;
}
if (nMissInvocations != m_nMissInvocationsExpected)
{
goto end;
}
/* Convert an array of result items, stored in undefined order, to a representation we can easily verify */
for (deUint32 nItem = 0; nItem < nItemsStored; ++nItem)
{
const deUint32* currentItemU32Ptr = resultU32Ptr + 3 /* nItemsRegistered, nCHitInvocations, nMissInvocations*/ + 4 /* items per result item */ * nItem;
std::unique_ptr<ResultItem> resultItemPtr;
resultItemPtr.reset(new ResultItem() );
resultItemPtr->depth = *(currentItemU32Ptr + 2);
resultItemPtr->nOriginRay = *(currentItemU32Ptr + 0);
resultItemPtr->nParentNode = *(currentItemU32Ptr + 3);
switch (*(currentItemU32Ptr + 1) )
{
case 1: resultItemPtr->stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; break;
case 2: resultItemPtr->stage = VK_SHADER_STAGE_MISS_BIT_KHR; break;
case 3: resultItemPtr->stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; break;
default:
{
/* This should never happen */
DE_ASSERT(false);
goto end;
}
}
if (resultItemPtr->depth >= m_depthToUse && m_depthToUse > 0u)
{
DE_ASSERT(resultItemPtr->depth < m_depthToUse);
goto end;
}
if (resultItemPtr->nOriginRay >= m_nRaysToTest)
{
DE_ASSERT(resultItemPtr->nOriginRay < m_nRaysToTest);
goto end;
}
nItemToResultItemPtrMap[nItem] = resultItemPtr.get();
nRayToNLevelToResultItemPtrVecMap [resultItemPtr->nOriginRay][resultItemPtr->depth].push_back (resultItemPtr.get () );
nRayToResultItemPtrVecMap [resultItemPtr->nOriginRay].push_back (std::move (resultItemPtr) );
}
if (doFullCheck)
{
for (const auto& iterator1 : nRayToNLevelToResultItemPtrVecMap)
{
const auto& currentNLevelToResultItemPtrVecMap = iterator1.second;
deUint32 nRayGenShaderResultItemsFound = 0;
for (const auto& iterator2 : currentNLevelToResultItemPtrVecMap)
{
const auto& currentResultItemPtrVec = iterator2.second;
for (const auto& currentResultItemPtr : currentResultItemPtrVec)
{
if (currentResultItemPtr->stage == VK_SHADER_STAGE_RAYGEN_BIT_KHR)
{
if (currentResultItemPtr->nParentNode != 0xFFFFFFFF)
{
DE_ASSERT(currentResultItemPtr->nParentNode == 0xFFFFFFFF);
goto end;
}
nRayGenShaderResultItemsFound++;
}
else
if (currentResultItemPtr->stage == VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR)
{
DE_ASSERT(currentResultItemPtr->nParentNode < nItemsStored);
auto parentNodePtr = nItemToResultItemPtrMap.at(currentResultItemPtr->nParentNode);
if (parentNodePtr->childCHitNodePtr != nullptr)
{
DE_ASSERT(parentNodePtr->childCHitNodePtr == nullptr);
goto end;
}
parentNodePtr->childCHitNodePtr = currentResultItemPtr;
}
else
{
DE_ASSERT(currentResultItemPtr->stage == VK_SHADER_STAGE_MISS_BIT_KHR);
DE_ASSERT(currentResultItemPtr->nParentNode < nItemsStored);
auto parentNodePtr = nItemToResultItemPtrMap.at(currentResultItemPtr->nParentNode);
if (parentNodePtr->childMissNodePtr != nullptr)
{
DE_ASSERT(parentNodePtr->childMissNodePtr == nullptr);
goto end;
}
parentNodePtr->childMissNodePtr = currentResultItemPtr;
}
}
}
if (nRayGenShaderResultItemsFound != 1)
{
DE_ASSERT(nRayGenShaderResultItemsFound == 1);
goto end;
}
}
}
// 1. Verify all nodes that are not leaves have both child nodes attached, and that leaf nodes do not have any children assigned.
if (doFullCheck)
{
for (const auto& iterator1 : nRayToNLevelToResultItemPtrVecMap)
{
const auto& currentNLevelToResultItemPtrVecMap = iterator1.second;
for (const auto& iterator2 : currentNLevelToResultItemPtrVecMap)
{
const auto& currentNLevel = iterator2.first;
const auto& currentResultItemPtrVec = iterator2.second;
for (const auto& currentResultItemPtr : currentResultItemPtrVec)
{
if ( currentResultItemPtr->stage == VK_SHADER_STAGE_RAYGEN_BIT_KHR ||
currentNLevel != m_depthToUse - 1)
{
if (currentResultItemPtr->childCHitNodePtr == nullptr && m_depthToUse > 0u)
{
DE_ASSERT(currentResultItemPtr->childCHitNodePtr != nullptr);
goto end;
}
if (currentResultItemPtr->childMissNodePtr == nullptr && m_depthToUse > 0u)
{
DE_ASSERT(currentResultItemPtr->childMissNodePtr != nullptr);
goto end;
}
}
else
{
if (currentResultItemPtr->childCHitNodePtr != nullptr)
{
DE_ASSERT(currentResultItemPtr->childCHitNodePtr == nullptr);
goto end;
}
if (currentResultItemPtr->childMissNodePtr != nullptr)
{
DE_ASSERT(currentResultItemPtr->childMissNodePtr == nullptr);
goto end;
}
}
}
}
}
}
// 2. Verify depth level is correct for each node.
for (const auto& iterator1 : nRayToNLevelToResultItemPtrVecMap)
{
const auto& currentNLevelToResultItemPtrVecMap = iterator1.second;
for (const auto& iterator2 : currentNLevelToResultItemPtrVecMap)
{
const auto& currentNLevel = iterator2.first;
const auto& currentResultItemPtrVec = iterator2.second;
for (const auto& currentResultItemPtr : currentResultItemPtrVec)
{
if (currentResultItemPtr->stage == VK_SHADER_STAGE_RAYGEN_BIT_KHR)
{
if (currentResultItemPtr->depth != 0)
{
DE_ASSERT(currentResultItemPtr->depth == 0);
goto end;
}
}
else
if (currentResultItemPtr->depth != currentNLevel)
{
DE_ASSERT(currentResultItemPtr->depth == currentNLevel);
goto end;
}
}
}
}
// 3. Verify child node ptrs point to nodes that are assigned correct shader stage.
for (const auto& iterator : nItemToResultItemPtrMap)
{
const auto& currentResultItemPtr = iterator.second;
if (currentResultItemPtr->childCHitNodePtr != nullptr &&
currentResultItemPtr->childCHitNodePtr->stage != VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR)
{
DE_ASSERT(currentResultItemPtr->childCHitNodePtr->stage == VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
goto end;
}
if (currentResultItemPtr->childMissNodePtr != nullptr &&
currentResultItemPtr->childMissNodePtr->stage != VK_SHADER_STAGE_MISS_BIT_KHR)
{
DE_ASSERT(currentResultItemPtr->childMissNodePtr->stage= VK_SHADER_STAGE_MISS_BIT_KHR);
goto end;
}
}
// 4. Verify nodes hold correct ray index.
for (const auto& iterator : nRayToResultItemPtrVecMap)
{
const auto& currentNRay = iterator.first;
for (const auto& currentResultItemPtr : iterator.second)
{
if (currentResultItemPtr->nOriginRay != currentNRay)
{
DE_ASSERT(currentResultItemPtr->nOriginRay == currentNRay);
goto end;
}
}
}
// 5. Verify child nodes are assigned correct depth levels.
for (const auto& iterator1 : nRayToNLevelToResultItemPtrVecMap)
{
const auto& currentNLevelToResultItemPtrVecMap = iterator1.second;
for (const auto& iterator2 : currentNLevelToResultItemPtrVecMap)
{
const auto& currentNLevel = iterator2.first;
const auto& currentResultItemPtrVec = iterator2.second;
for (const auto& currentResultItemPtr : currentResultItemPtrVec)
{
const auto expectedChildNodeDepth = (currentResultItemPtr->stage == VK_SHADER_STAGE_RAYGEN_BIT_KHR) ? 0
: currentResultItemPtr->depth + 1;
if (currentResultItemPtr->depth != currentNLevel)
{
DE_ASSERT(currentResultItemPtr->depth == currentNLevel);
goto end;
}
if (currentResultItemPtr->childCHitNodePtr != nullptr &&
currentResultItemPtr->childCHitNodePtr->depth != expectedChildNodeDepth)
{
DE_ASSERT(currentResultItemPtr->childCHitNodePtr->depth == expectedChildNodeDepth);
goto end;
}
if (currentResultItemPtr->childMissNodePtr != nullptr &&
currentResultItemPtr->childMissNodePtr->depth != expectedChildNodeDepth)
{
DE_ASSERT(currentResultItemPtr->childMissNodePtr->depth == expectedChildNodeDepth);
goto end;
}
}
}
}
// 6. Verify that RT shader stages were invoked for all anticipated recursion levels.
if (doFullCheck)
{
for (const auto& iterator1 : nRayToNLevelToResultItemPtrVecMap)
{
for (deUint32 nLevel = 0;
nLevel < m_depthToUse;
nLevel ++)
{
if (iterator1.second.find(nLevel) == iterator1.second.end())
{
DE_ASSERT(false);
goto end;
}
}
}
}
result = true;
end:
return result;
}
private:
const AccelerationStructureLayout m_asStructureLayout;
const GeometryType m_geometryType;
deUint32 m_depthToUse;
deUint32 m_nMaxResultItemsPermitted;
const deUint32 m_nRaysToTest;
std::unique_ptr<TopLevelAccelerationStructure> m_tlPtr;
VkSpecializationInfo m_specializationInfo;
VkSpecializationMapEntry m_specializationEntry;
mutable std::vector<std::string> m_ahitShaderNameVec;
mutable std::vector<std::string> m_chitShaderNameVec;
mutable std::vector<std::string> m_missShaderNameVec;
deUint32 m_nCHitInvocationsExpected;
deUint32 m_nMissInvocationsExpected;
deUint32 m_nResultItemsExpected;
const deUint32 m_maxResultBufferSizePermitted;
};
// Test the return value of reportIntersectionEXT
class ReportIntersectionResultTest : public TestBase
{
public:
ReportIntersectionResultTest(const AccelerationStructureLayout& asLayout,
const GeometryType& geometryType)
: m_asLayout(asLayout)
, m_geometryType(geometryType)
, m_gridSizeXYZ(tcu::UVec3(4, 4, 1))
, m_nRaysToTrace(16)
{
}
std::vector<std::string> getCHitShaderCollectionShaderNames() const final
{
return {};
}
tcu::UVec3 getDispatchSize() const final
{
return m_gridSizeXYZ;
}
deUint32 getResultBufferSize() const final
{
return static_cast<deUint32>(2u * sizeof(deUint32) * m_nRaysToTrace);
}
std::vector<TopLevelAccelerationStructure*> getTLASPtrVecToBind() const final
{
return { m_tlPtr.get() };
}
void resetTLAS() final
{
m_tlPtr.reset();
}
void initAS(vkt::Context& context,
RayTracingProperties* /* rtPropertiesPtr */,
VkCommandBuffer commandBuffer) final
{
m_asProviderPtr.reset(
new GridASProvider(tcu::Vec3(0, 0, 0), // gridStartXYZ
tcu::Vec3(1, 1, 1), // gridCellSizeXYZ
m_gridSizeXYZ,
tcu::Vec3(2.0f, 2.0f, 2.0f), // gridInterCellDeltaXYZ
m_geometryType)
);
m_tlPtr = m_asProviderPtr->createTLAS(context,
m_asLayout,
commandBuffer,
0u,
nullptr, // optASPropertyProviderPtr
nullptr); // optASFedbackPtr
}
void initPrograms(SourceCollections& programCollection) const final
{
const vk::ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
const std::string hitPropertiesDefinition =
"struct HitProperties\n"
"{\n"
" uint nHitsRejected;\n"
" uint nHitsAccepteded;\n"
"};\n";
const std::string hitPropertiesDeclaration =
"layout(set = 0, binding = 0, std430) buffer result\n"
"{\n"
" HitProperties rayToHitProps[" + de::toString(m_nRaysToTrace) + "];\n"
"};\n";
programCollection.glslSources.add("ahit") << glu::AnyHitSource(std::string() +
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"hitAttributeEXT vec3 dummyAttribute;\n"
"\n"
+ hitPropertiesDefinition +
"\n"
"layout(location = 0) rayPayloadInEXT dummy { vec3 dummyVec;};\n"
+ hitPropertiesDeclaration +
"\n"
"void main()\n"
"{\n"
" uint nRay = gl_LaunchIDEXT.z * gl_LaunchSizeEXT.x * gl_LaunchSizeEXT.y + gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x;\n"
" if ((gl_RayTmaxEXT > 0.6) && (gl_RayTmaxEXT < 0.8))\n"
" {\n"
" atomicAdd(rayToHitProps[nRay].nHitsRejected, 1);\n"
" ignoreIntersectionEXT;\n" // reportIntersectionEXT should return false
" }\n"
" else if ((gl_RayTmaxEXT > 0.1) && (gl_RayTmaxEXT < 0.3))\n"
" {\n"
" atomicAdd(rayToHitProps[nRay].nHitsAccepteded, 1);\n"
" }\n"
"}\n")
<< buildOptions;
programCollection.glslSources.add("intersection") << glu::IntersectionSource(
"#version 460 core\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"hitAttributeEXT vec3 hitAttribute;\n"
"\n"
"void main()\n"
"{\n"
" bool resultThatShouldBeRejected = reportIntersectionEXT(0.7f, 0);\n"
" if (resultThatShouldBeRejected)\n"
" reportIntersectionEXT(0.7f, 0);\n"
" else\n"
" {\n"
" bool resultThatShouldBeAccepted = reportIntersectionEXT(0.2f, 0);\n"
" if (!resultThatShouldBeAccepted)\n"
" reportIntersectionEXT(0.2f, 0);\n"
" }\n"
"}\n")
<< buildOptions;
programCollection.glslSources.add("miss") << glu::MissSource(std::string() +
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
+ hitPropertiesDefinition +
"layout(location = 0) rayPayloadInEXT vec3 dummy;\n"
+ hitPropertiesDeclaration +
"\n"
"void main()\n"
"{\n"
"}\n")
<< buildOptions;
programCollection.glslSources.add("rgen") << glu::RaygenSource(
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
+ hitPropertiesDefinition +
"layout(location = 0) rayPayloadEXT vec3 dummy;\n"
"layout(set = 0, binding = 1) uniform accelerationStructureEXT topLevelAS;\n"
"\n"
"void main()\n"
"{\n"
" uint rayFlags = 0;\n"
" uint cullMask = 0xFF;\n"
" float tmin = 0.001;\n"
" float tmax = 9.0;\n"
" vec3 origin = vec3(4, 4, 4);\n"
" vec3 target = vec3(float(gl_LaunchIDEXT.x * 2) + 0.5f, float(gl_LaunchIDEXT.y * 2) + 0.5f, float(gl_LaunchIDEXT.z * 2) + 0.5f);\n"
" vec3 direct = normalize(target - origin);\n"
"\n"
" traceRayEXT(topLevelAS, rayFlags, cullMask, 0, 0, 0, origin, tmin, direct, tmax, 0);\n"
"}\n")
<< buildOptions;
}
bool verifyResultBuffer(const void* resultDataPtr) const final
{
for (deUint32 nRay = 0; nRay < m_nRaysToTrace; ++nRay)
{
const deUint32* rayProps = reinterpret_cast<const deUint32*>(resultDataPtr) + 2 * nRay;
if ((rayProps[0] != 1) || (rayProps[1] != 1))
return false;
}
return true;
}
private:
const AccelerationStructureLayout m_asLayout;
const GeometryType m_geometryType;
const tcu::UVec3 m_gridSizeXYZ;
const deUint32 m_nRaysToTrace;
std::unique_ptr<GridASProvider> m_asProviderPtr;
std::unique_ptr<TopLevelAccelerationStructure> m_tlPtr;
};
class RayPayloadInTest : public TestBase
{
public:
RayPayloadInTest(const GeometryType& geometryType,
const AccelerationStructureLayout& asStructureLayout)
: m_asStructureLayout(asStructureLayout),
m_geometryType(geometryType),
m_gridSizeXYZ(tcu::UVec3(512, 1, 1)),
m_nRayPayloadU32s(512)
{
}
~RayPayloadInTest()
{
/* Stub */
}
tcu::UVec3 getDispatchSize() const final
{
DE_ASSERT(m_gridSizeXYZ[0] != 0);
DE_ASSERT(m_gridSizeXYZ[1] != 0);
DE_ASSERT(m_gridSizeXYZ[2] != 0);
return tcu::UVec3(m_gridSizeXYZ[0], m_gridSizeXYZ[1], m_gridSizeXYZ[2]);
}
deUint32 getResultBufferSize() const final
{
DE_ASSERT(m_gridSizeXYZ[0] != 0);
DE_ASSERT(m_gridSizeXYZ[1] != 0);
DE_ASSERT(m_gridSizeXYZ[2] != 0);
DE_ASSERT(m_nRayPayloadU32s != 0);
const auto nRays = m_gridSizeXYZ[0] * m_gridSizeXYZ[1] * m_gridSizeXYZ[2];
DE_ASSERT(nRays != 0);
DE_ASSERT((nRays % 2) == 0);
const auto nMissShaderInvocationsExpected = nRays / 2;
const auto nAHitShaderInvocationsExpected = nRays / 2;
const auto nCHitShaderInvocationsExpected = nAHitShaderInvocationsExpected;
const auto nResultStoresExpected = nMissShaderInvocationsExpected + nAHitShaderInvocationsExpected + nCHitShaderInvocationsExpected;
return static_cast<deUint32>((1 /* nItems */ + m_nRayPayloadU32s * nResultStoresExpected) * sizeof(deUint32));
}
VkSpecializationInfo* getSpecializationInfoPtr(const VkShaderStageFlagBits& shaderStage) final
{
VkSpecializationInfo* resultPtr = nullptr;
if (shaderStage == VK_SHADER_STAGE_MISS_BIT_KHR ||
shaderStage == VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR ||
shaderStage == VK_SHADER_STAGE_ANY_HIT_BIT_KHR ||
shaderStage == VK_SHADER_STAGE_RAYGEN_BIT_KHR)
{
resultPtr = &m_specializationInfo;
}
return resultPtr;
}
std::vector<TopLevelAccelerationStructure*> getTLASPtrVecToBind() const final
{
DE_ASSERT(m_tlPtr != nullptr);
return { m_tlPtr.get() };
}
bool init( vkt::Context& /* context */,
RayTracingProperties* /* rtPropertiesPtr */) final
{
m_specializationInfoMapEntry.constantID = 1;
m_specializationInfoMapEntry.offset = 0;
m_specializationInfoMapEntry.size = sizeof(deUint32);
m_specializationInfo.dataSize = sizeof(deUint32);
m_specializationInfo.mapEntryCount = 1;
m_specializationInfo.pData = reinterpret_cast<const void*>(&m_nRayPayloadU32s);
m_specializationInfo.pMapEntries = &m_specializationInfoMapEntry;
return true;
}
void resetTLAS() final
{
m_tlPtr.reset();
}
void initAS(vkt::Context& context,
RayTracingProperties* /* rtPropertiesPtr */,
VkCommandBuffer commandBuffer) final
{
std::unique_ptr<GridASProvider> asProviderPtr(
new GridASProvider(tcu::Vec3(0, 0, 0), /* gridStartXYZ */
tcu::Vec3(1, 1, 1), /* gridCellSizeXYZ */
m_gridSizeXYZ,
tcu::Vec3(6, 0, 0), /* gridInterCellDeltaXYZ */
m_geometryType)
);
m_tlPtr = asProviderPtr->createTLAS(context,
m_asStructureLayout,
commandBuffer,
VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR,
nullptr,
nullptr);
}
void initPrograms(SourceCollections& programCollection) const final
{
const vk::ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion,
vk::SPIRV_VERSION_1_4,
0u, /* flags */
true); /* allowSpirv14 */
const char* constantDefinitions =
"layout(constant_id = 1) const uint N_UINTS_IN_RAY_PAYLOAD = 1;\n";
const char* rayPayloadDefinition =
"\n"
"layout(location = 0) rayPayloadEXT block\n"
"{\n"
" uint values[N_UINTS_IN_RAY_PAYLOAD];\n"
"};\n"
"\n";
const char* rayPayloadInDefinition =
"\n"
"layout(location = 0) rayPayloadInEXT block\n"
"{\n"
" uint values[N_UINTS_IN_RAY_PAYLOAD];\n"
"};\n"
"\n";
const char* resultBufferDefinition =
"layout(set = 0, binding = 0, std430) buffer result\n"
"{\n"
" uint nItemsStored;\n"
" uint resultValues[];\n"
"};\n";
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
+ de::toString(constantDefinitions)
+ de::toString(resultBufferDefinition)
+ de::toString(rayPayloadInDefinition) +
"\n"
"void main()\n"
"{\n"
" uint nItem = atomicAdd(nItemsStored, 1);\n"
"\n"
" for (uint nUint = 0; nUint < N_UINTS_IN_RAY_PAYLOAD; ++nUint)\n"
" {\n"
" resultValues[nItem * N_UINTS_IN_RAY_PAYLOAD + nUint] = values[nUint];\n"
" }\n"
"}\n";
programCollection.glslSources.add("ahit") << glu::AnyHitSource(css.str()) << buildOptions;
}
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
+ de::toString(constantDefinitions)
+ de::toString(resultBufferDefinition)
+ de::toString(rayPayloadInDefinition) +
"\n"
"void main()\n"
"{\n"
" uint nItem = atomicAdd(nItemsStored, 1);\n"
"\n"
" for (uint nUint = 0; nUint < N_UINTS_IN_RAY_PAYLOAD; ++nUint)\n"
" {\n"
" resultValues[nItem * N_UINTS_IN_RAY_PAYLOAD + nUint] = values[nUint];\n"
" }\n"
"}\n";
programCollection.glslSources.add("chit") << glu::ClosestHitSource(css.str()) << buildOptions;
}
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"void main()\n"
"{\n"
" reportIntersectionEXT(0.95f, 0);\n"
"}\n";
programCollection.glslSources.add("intersection") << glu::IntersectionSource(css.str()) << buildOptions;
}
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
+ de::toString(constantDefinitions)
+ de::toString(resultBufferDefinition)
+ de::toString(rayPayloadInDefinition) +
"\n"
"void main()\n"
"{\n"
" uint nItem = atomicAdd(nItemsStored, 1);\n"
"\n"
" for (uint nUint = 0; nUint < N_UINTS_IN_RAY_PAYLOAD; ++nUint)\n"
" {\n"
" resultValues[nItem * N_UINTS_IN_RAY_PAYLOAD + nUint] = values[nUint];\n"
" }\n"
"}\n";
programCollection.glslSources.add("miss") << glu::MissSource(css.str()) << buildOptions;
}
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"layout(set = 0, binding = 1) uniform accelerationStructureEXT accelerationStructure;\n"
"\n"
+ de::toString(constantDefinitions)
+ de::toString(rayPayloadDefinition) +
"void main()\n"
"{\n"
" uint nInvocation = gl_LaunchIDEXT.z * gl_LaunchSizeEXT.x * gl_LaunchSizeEXT.y + gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x;\n"
" uint rayFlags = 0;\n"
" float tmin = 0.001;\n"
" float tmax = 2.1;\n"
"\n"
" uint cullMask = 0xFF;\n"
" vec3 cellStartXYZ = vec3(nInvocation * 3.0, 0.0, 0.0);\n"
" vec3 cellEndXYZ = cellStartXYZ + vec3(1.0);\n"
" vec3 target = mix(cellStartXYZ, cellEndXYZ, vec3(0.5) );\n"
" vec3 origin = target - vec3(0, 2, 0);\n"
" vec3 direct = normalize(target - origin);\n"
"\n"
" for (uint nUint = 0; nUint < N_UINTS_IN_RAY_PAYLOAD; ++nUint)\n"
" {\n"
" values[nUint] = (1 + nUint);\n"
" }\n"
"\n"
" traceRayEXT(accelerationStructure, rayFlags, cullMask, 0, 0, 0, origin, tmin, direct, tmax, 0);\n"
"}\n";
programCollection.glslSources.add("rgen") << glu::RaygenSource(css.str()) << buildOptions;
}
}
bool verifyResultBuffer(const void* resultDataPtr) const final
{
const deUint32* resultU32Ptr = reinterpret_cast<const deUint32*>(resultDataPtr);
bool result = false;
const auto nItemsStored = *resultU32Ptr;
const auto nRays = m_gridSizeXYZ[0] * m_gridSizeXYZ[1] * m_gridSizeXYZ[2];
const auto nMissShaderInvocationsExpected = nRays / 2;
const auto nAHitShaderInvocationsExpected = nRays / 2;
const auto nCHitShaderInvocationsExpected = nAHitShaderInvocationsExpected;
const auto nResultStoresExpected = nMissShaderInvocationsExpected + nAHitShaderInvocationsExpected + nCHitShaderInvocationsExpected;
if (nItemsStored != nResultStoresExpected)
{
goto end;
}
for (deUint32 nItem = 0; nItem < nItemsStored; ++nItem)
{
const auto resultItemDataPtr = resultU32Ptr + 1 /* nItemsStored */ + nItem * m_nRayPayloadU32s;
for (deUint32 nValue = 0; nValue < m_nRayPayloadU32s; ++nValue)
{
if (resultItemDataPtr[nValue] != (1 + nValue))
{
goto end;
}
}
}
result = true;
end:
return result;
}
private:
const AccelerationStructureLayout m_asStructureLayout;
const GeometryType m_geometryType;
const tcu::UVec3 m_gridSizeXYZ;
deUint32 m_nRayPayloadU32s;
std::unique_ptr<TopLevelAccelerationStructure> m_tlPtr;
VkSpecializationInfo m_specializationInfo;
VkSpecializationMapEntry m_specializationInfoMapEntry;
};
class TerminationTest : public TestBase
{
public:
enum class Mode
{
IGNORE_ANY_HIT_STATICALLY,
IGNORE_ANY_HIT_DYNAMICALLY,
TERMINATE_ANY_HIT_STATICALLY,
TERMINATE_ANY_HIT_DYNAMICALLY,
TERMINATE_INTERSECTION_STATICALLY,
TERMINATE_INTERSECTION_DYNAMICALLY,
UNKNOWN
};
static Mode getModeFromTestType(const TestType& testType)
{
Mode result = Mode::UNKNOWN;
switch (testType)
{
case TestType::IGNORE_ANY_HIT_DYNAMICALLY: result = Mode::IGNORE_ANY_HIT_DYNAMICALLY; break;
case TestType::IGNORE_ANY_HIT_STATICALLY: result = Mode::IGNORE_ANY_HIT_STATICALLY; break;
case TestType::TERMINATE_ANY_HIT_DYNAMICALLY: result = Mode::TERMINATE_ANY_HIT_DYNAMICALLY; break;
case TestType::TERMINATE_ANY_HIT_STATICALLY: result = Mode::TERMINATE_ANY_HIT_STATICALLY; break;
case TestType::TERMINATE_INTERSECTION_DYNAMICALLY: result = Mode::TERMINATE_INTERSECTION_DYNAMICALLY; break;
case TestType::TERMINATE_INTERSECTION_STATICALLY: result = Mode::TERMINATE_INTERSECTION_STATICALLY; break;
default:
{
DE_ASSERT(false && "This should never happen");
}
}
return result;
}
TerminationTest(const Mode& mode)
:m_mode(mode)
{
/* Stub */
}
~TerminationTest()
{
/* Stub */
}
std::vector<std::string> getCHitShaderCollectionShaderNames() const final
{
return {};
}
tcu::UVec3 getDispatchSize() const final
{
return tcu::UVec3(1, 1, 1);
}
std::vector<deUint8> getResultBufferStartData() const final
{
auto resultU8Vec = std::vector<deUint8> (getResultBufferSize () );
auto resultU32DataPtr = reinterpret_cast<deUint32*> (resultU8Vec.data () );
memset( resultU8Vec.data(),
0,
resultU8Vec.size() );
if (m_mode == Mode::IGNORE_ANY_HIT_DYNAMICALLY ||
m_mode == Mode::TERMINATE_ANY_HIT_DYNAMICALLY)
{
resultU32DataPtr[2] = 1;
}
else
if (m_mode == Mode::TERMINATE_INTERSECTION_DYNAMICALLY)
{
resultU32DataPtr[3] = 1;
}
return resultU8Vec;
}
deUint32 getResultBufferSize() const final
{
const deUint32 nExtraUints = ( m_mode == Mode::IGNORE_ANY_HIT_DYNAMICALLY ||
m_mode == Mode::TERMINATE_ANY_HIT_DYNAMICALLY ||
m_mode == Mode::TERMINATE_INTERSECTION_DYNAMICALLY) ? 1
: 0;
const deUint32 nResultUints = ( m_mode == Mode::TERMINATE_INTERSECTION_DYNAMICALLY ||
m_mode == Mode::TERMINATE_INTERSECTION_STATICALLY) ? 3
: 2;
return static_cast<deUint32>(sizeof(deUint32) ) * (nExtraUints + nResultUints);
}
std::vector<TopLevelAccelerationStructure*> getTLASPtrVecToBind() const final
{
return {m_tlPtr.get() };
}
void resetTLAS() final
{
m_tlPtr.reset();
}
void initAS(vkt::Context& context,
RayTracingProperties* /* rtPropertiesPtr */,
VkCommandBuffer commandBuffer) final
{
if (m_mode == Mode::TERMINATE_INTERSECTION_DYNAMICALLY ||
m_mode == Mode::TERMINATE_INTERSECTION_STATICALLY)
{
const tcu::Vec3 gridCellSizeXYZ = tcu::Vec3 ( 2, 1, 1);
const tcu::Vec3 gridInterCellDeltaXYZ = tcu::Vec3 ( 3, 3, 3);
const tcu::UVec3 gridSizeXYZ = tcu::UVec3( 1, 1, 1);
const tcu::Vec3 gridStartXYZ = tcu::Vec3 (-1, -1, -1);
m_asProviderPtr.reset(
new GridASProvider( gridStartXYZ,
gridCellSizeXYZ,
gridSizeXYZ,
gridInterCellDeltaXYZ,
GeometryType::AABB)
);
}
else
{
m_asProviderPtr.reset(
new TriASProvider()
);
}
m_tlPtr = m_asProviderPtr->createTLAS( context,
AccelerationStructureLayout::ONE_TL_ONE_BL_ONE_GEOMETRY,
commandBuffer,
VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR,
nullptr, /* optASPropertyProviderPtr */
nullptr); /* optASFedbackPtr */
}
void initPrograms(SourceCollections& programCollection) const final
{
const vk::ShaderBuildOptions buildOptions( programCollection.usedVulkanVersion,
vk::SPIRV_VERSION_1_4,
0u, /* flags */
true); /* allowSpirv14 */
const std::string resultBufferSizeString = de::toString(getResultBufferSize() / sizeof(deUint32) );
{
std::string aHitShader;
switch (m_mode)
{
case Mode::IGNORE_ANY_HIT_DYNAMICALLY:
{
aHitShader =
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"hitAttributeEXT vec3 dummyAttribute;\n"
"\n"
"layout(location = 0) rayPayloadInEXT dummy { vec3 dummyVec;};\n"
"layout(set = 0, binding = 0, std430) buffer result\n"
"{\n"
" uint resultData[" + resultBufferSizeString + "];\n"
"};\n"
"\n"
"void ignoreIntersectionWrapper()\n"
"{\n"
" ignoreIntersectionEXT;\n"
"}\n"
"\n"
"void main()\n"
"{\n"
"\n"
" if (resultData[2] == 1)\n"
" {\n"
" ignoreIntersectionWrapper();\n"
" }\n"
"\n"
" resultData[0] = 1;\n"
"}\n";
break;
}
case Mode::IGNORE_ANY_HIT_STATICALLY:
{
aHitShader =
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"hitAttributeEXT vec3 dummyAttribute;\n"
"\n"
"layout(location = 0) rayPayloadInEXT dummy { vec3 dummyVec;};\n"
"layout(set = 0, binding = 0, std430) buffer result\n"
"{\n"
" uint resultData[" + resultBufferSizeString + "];\n"
"};\n"
"\n"
"void ignoreIntersectionWrapper()\n"
"{\n"
" ignoreIntersectionEXT;\n"
"}\n"
"\n"
"void main()\n"
"{\n"
" ignoreIntersectionWrapper();\n"
"\n"
" resultData[0] = 1;\n"
"}\n";
break;
}
case Mode::TERMINATE_ANY_HIT_DYNAMICALLY:
{
aHitShader =
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"hitAttributeEXT vec3 dummyAttribute;\n"
"\n"
"layout(location = 0) rayPayloadInEXT dummy { vec3 dummyVec;};\n"
"layout(set = 0, binding = 0, std430) buffer result\n"
"{\n"
" uint resultData[" + resultBufferSizeString + "];\n"
"};\n"
"\n"
"void terminateRayWrapper()\n"
"{\n"
" terminateRayEXT;\n"
"}\n"
"\n"
"void main()\n"
"{\n"
" if (resultData[2] == 1)\n"
" {\n"
" terminateRayWrapper();\n"
" }\n"
"\n"
" resultData[0] = 1;\n"
"}\n";
break;
}
case Mode::TERMINATE_ANY_HIT_STATICALLY:
case Mode::TERMINATE_INTERSECTION_STATICALLY:
{
aHitShader =
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"hitAttributeEXT vec3 dummyAttribute;\n"
"\n"
"layout(location = 0) rayPayloadInEXT dummy { vec3 dummyVec;};\n"
"layout(set = 0, binding = 0, std430) buffer result\n"
"{\n"
" uint resultData[" + resultBufferSizeString + "];\n"
"};\n"
"\n"
"void terminateRayWrapper()\n"
"{\n"
" terminateRayEXT;\n"
"}\n"
"\n"
"void main()\n"
"{\n"
" terminateRayWrapper();\n"
"\n"
" resultData[0] = 1;\n"
"}\n";
break;
}
case Mode::TERMINATE_INTERSECTION_DYNAMICALLY:
{
aHitShader =
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"hitAttributeEXT vec3 dummyAttribute;\n"
"\n"
"layout(location = 0) rayPayloadInEXT dummy { vec3 dummyVec;};\n"
"layout(set = 0, binding = 0, std430) buffer result\n"
"{\n"
" uint resultData[" + resultBufferSizeString + "];\n"
"};\n"
"\n"
"void terminateRayWrapper()\n"
"{\n"
" terminateRayEXT;\n"
"}\n"
"\n"
"void main()\n"
"{\n"
" if (resultData[3] == 1)\n"
" {\n"
" terminateRayWrapper();\n"
" }\n"
"\n"
" resultData[0] = 1;\n"
"}\n";
break;
}
default:
{
DE_ASSERT(false);
}
}
programCollection.glslSources.add("ahit") << glu::AnyHitSource(aHitShader) << buildOptions;
}
if (m_mode == Mode::TERMINATE_INTERSECTION_DYNAMICALLY ||
m_mode == Mode::TERMINATE_INTERSECTION_STATICALLY)
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"hitAttributeEXT vec3 hitAttribute;\n"
"\n"
"layout(set = 0, binding = 0, std430) buffer result\n"
"{\n"
" uint resultData[4];\n"
"};\n"
"\n"
"void generateIntersection()\n"
"{\n"
" reportIntersectionEXT(0.95f, 0);\n"
"}\n"
"\n"
"void main()\n"
"{\n";
if (m_mode == Mode::TERMINATE_INTERSECTION_DYNAMICALLY)
{
css << " if (resultData[3] == 1)\n"
" {\n";
}
css << " generateIntersection();\n";
if (m_mode == Mode::TERMINATE_INTERSECTION_DYNAMICALLY)
{
css << " }\n";
}
css <<
"\n"
" resultData[2] = 1;\n"
"}\n";
programCollection.glslSources.add("intersection") << glu::IntersectionSource(css.str() ) << buildOptions;
}
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"layout(location = 0) rayPayloadInEXT vec3 dummy;\n"
"layout(set = 0, binding = 0, std430) buffer result\n"
"{\n"
" uint resultData[2];\n"
"};\n"
"\n"
"void main()\n"
"{\n"
" resultData[1] = 1;\n"
"}\n";
programCollection.glslSources.add("miss") << glu::MissSource(css.str() ) << buildOptions;
}
{
std::stringstream css;
css <<
"#version 460 core\n"
"\n"
"#extension GL_EXT_ray_tracing : require\n"
"\n"
"layout(location = 0) rayPayloadEXT vec3 dummy;\n"
"layout(set = 0, binding = 1) uniform accelerationStructureEXT topLevelAS;\n"
"\n"
"void main()\n"
"{\n"
" uint nInvocation = gl_LaunchIDEXT.z * gl_LaunchSizeEXT.x * gl_LaunchSizeEXT.y + gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x;\n"
" uint rayFlags = 0;\n"
" uint cullMask = 0xFF;\n"
" float tmin = 0.001;\n"
" float tmax = 9.0;\n"
" vec3 origin = vec3(-1, -1, -1);\n"
" vec3 target = vec3(0.0, 0.5, 0);\n"
" vec3 direct = normalize(target - origin);\n"
"\n"
" traceRayEXT(topLevelAS, rayFlags, cullMask, 0, 0, 0, origin, tmin, direct, tmax, 0);\n"
"}\n";
programCollection.glslSources.add("rgen") << glu::RaygenSource(css.str() ) << buildOptions;
}
}
bool verifyResultBuffer (const void* resultDataPtr) const final
{
const deUint32* resultU32DataPtr = reinterpret_cast<const deUint32*>(resultDataPtr);
bool result = false;
switch (m_mode)
{
case Mode::IGNORE_ANY_HIT_DYNAMICALLY:
case Mode::IGNORE_ANY_HIT_STATICALLY:
{
if (resultU32DataPtr[0] != 0 ||
resultU32DataPtr[1] != 1)
{
goto end;
}
result = true;
break;
}
case Mode::TERMINATE_ANY_HIT_DYNAMICALLY:
case Mode::TERMINATE_ANY_HIT_STATICALLY:
{
if (resultU32DataPtr[0] != 0 ||
resultU32DataPtr[1] != 0)
{
goto end;
}
result = true;
break;
}
case Mode::TERMINATE_INTERSECTION_DYNAMICALLY:
case Mode::TERMINATE_INTERSECTION_STATICALLY:
{
if (resultU32DataPtr[0] != 0 ||
resultU32DataPtr[1] != 0 ||
resultU32DataPtr[2] != 0)
{
goto end;
}
result = true;
break;
}
default:
{
TCU_FAIL("This should never be reached");
}
}
end:
return result;
}
private:
std::unique_ptr<ASProviderBase> m_asProviderPtr;
const Mode m_mode;
std::unique_ptr<TopLevelAccelerationStructure> m_tlPtr;
};
/* Generic misc test instance */
class RayTracingMiscTestInstance : public TestInstance
{
public:
RayTracingMiscTestInstance ( Context& context,
const CaseDef& data,
TestBase* testPtr);
~RayTracingMiscTestInstance ( void);
tcu::TestStatus iterate (void);
protected:
void checkSupport(void) const;
de::MovePtr<BufferWithMemory> runTest (void);
private:
CaseDef m_data;
de::MovePtr<RayTracingProperties> m_rayTracingPropsPtr;
TestBase* m_testPtr;
};
RayTracingMiscTestInstance::RayTracingMiscTestInstance (Context& context,
const CaseDef& data,
TestBase* testPtr)
: vkt::TestInstance (context)
, m_data (data)
, m_rayTracingPropsPtr (makeRayTracingProperties(context.getInstanceInterface(),
context.getPhysicalDevice()))
, m_testPtr (testPtr)
{
m_testPtr->init(m_context, m_rayTracingPropsPtr.get());
}
RayTracingMiscTestInstance::~RayTracingMiscTestInstance(void)
{
/* Stub */
}
void RayTracingMiscTestInstance::checkSupport(void) const
{
if (m_testPtr->getResultBufferSize() > m_context.getDeviceVulkan11Properties().maxMemoryAllocationSize)
TCU_THROW(NotSupportedError, "VkPhysicalDeviceVulkan11Properties::maxMemoryAllocationSize too small, allocation might fail");
}
de::MovePtr<BufferWithMemory> RayTracingMiscTestInstance::runTest(void)
{
const DeviceInterface& deviceInterface = m_context.getDeviceInterface ();
const VkDevice deviceVk = m_context.getDevice ();
const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
const VkQueue queueVk = m_context.getUniversalQueue ();
Allocator& allocator = m_context.getDefaultAllocator ();
de::MovePtr<BufferWithMemory> resultBufferPtr;
// Determine group indices
const auto ahitCollectionShaderNameVec = m_testPtr->getAHitShaderCollectionShaderNames ();
const auto chitCollectionShaderNameVec = m_testPtr->getCHitShaderCollectionShaderNames ();
const auto intersectionCollectionShaderNameVec = m_testPtr->getIntersectionShaderCollectionShaderNames ();
const auto missCollectionShaderNameVec = m_testPtr->getMissShaderCollectionShaderNames ();
const deUint32 nRaygenGroups = 1;
const deUint32 nMissGroups = static_cast<deUint32>(missCollectionShaderNameVec.size() );
const deUint32 nHitGroups = de::max(
de::max( static_cast<deUint32>(ahitCollectionShaderNameVec.size() ),
static_cast<deUint32>(chitCollectionShaderNameVec.size() ) ),
static_cast<deUint32>(intersectionCollectionShaderNameVec.size() ));
const deUint32 raygenGroupIndex = 0;
const deUint32 missGroupIndex = nRaygenGroups;
const deUint32 hitGroupIndex = missGroupIndex + nMissGroups;
const auto callableShaderCollectionNames = m_testPtr->getCallableShaderCollectionNames ();
auto& collection = m_context.getBinaryCollection ();
const auto resultBufferSize = m_testPtr->getResultBufferSize ();
const Move<VkDescriptorSetLayout> descriptorSetLayoutPtr = DescriptorSetLayoutBuilder()
.addSingleBinding( VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
ALL_RAY_TRACING_STAGES)
.addArrayBinding( VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR,
m_testPtr->getASBindingArraySize(),
ALL_RAY_TRACING_STAGES)
.build ( deviceInterface,
deviceVk);
const Move<VkDescriptorPool> descriptorPoolPtr = DescriptorPoolBuilder()
.addType( VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
.addType( VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR,
m_testPtr->getASBindingArraySize() )
.build ( deviceInterface,
deviceVk,
VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
1u); /* maxSets */
const Move<VkDescriptorSet> descriptorSetPtr = makeDescriptorSet(deviceInterface,
deviceVk,
*descriptorPoolPtr,
*descriptorSetLayoutPtr);
const Move<VkPipelineLayout> pipelineLayoutPtr = m_testPtr->getPipelineLayout( deviceInterface,
deviceVk,
descriptorSetLayoutPtr.get() );
const Move<VkCommandPool> cmdPoolPtr = createCommandPool(deviceInterface,
deviceVk,
0, /* pCreateInfo */
queueFamilyIndex);
const Move<VkCommandBuffer> cmdBufferPtr = allocateCommandBuffer(deviceInterface,
deviceVk,
*cmdPoolPtr,
VK_COMMAND_BUFFER_LEVEL_PRIMARY);
Move<VkPipeline> pipelineVkPtr;
de::MovePtr<RayTracingPipeline> rayTracingPipelinePtr = de::newMovePtr<RayTracingPipeline>();
{
Move<VkShaderModule> raygenShader = createShaderModule( deviceInterface,
deviceVk,
collection.get("rgen"),
0); /* flags */
rayTracingPipelinePtr->addShader( VK_SHADER_STAGE_RAYGEN_BIT_KHR,
makeVkSharedPtr(raygenShader),
raygenGroupIndex,
m_testPtr->getSpecializationInfoPtr(VK_SHADER_STAGE_RAYGEN_BIT_KHR) );
}
{
for (deUint32 nMissShaderName = 0;
nMissShaderName < static_cast<deUint32>(missCollectionShaderNameVec.size() );
nMissShaderName ++)
{
const auto& currentMissShaderName = missCollectionShaderNameVec.at(nMissShaderName);
Move<VkShaderModule> missShader = createShaderModule( deviceInterface,
deviceVk,
collection.get(currentMissShaderName),
0); /* flags */
rayTracingPipelinePtr->addShader( VK_SHADER_STAGE_MISS_BIT_KHR,
makeVkSharedPtr(missShader),
missGroupIndex + nMissShaderName,
m_testPtr->getSpecializationInfoPtr(VK_SHADER_STAGE_MISS_BIT_KHR) );
}
}
{
for (deUint32 nAHitShaderName = 0;
nAHitShaderName < static_cast<deUint32>(ahitCollectionShaderNameVec.size() );
nAHitShaderName ++)
{
const auto& currentAHitShaderName = ahitCollectionShaderNameVec.at(nAHitShaderName);
Move<VkShaderModule> anyHitShader = createShaderModule( deviceInterface,
deviceVk,
collection.get(currentAHitShaderName),
0); /* flags */
rayTracingPipelinePtr->addShader( VK_SHADER_STAGE_ANY_HIT_BIT_KHR,
makeVkSharedPtr(anyHitShader),
hitGroupIndex + nAHitShaderName,
m_testPtr->getSpecializationInfoPtr(VK_SHADER_STAGE_ANY_HIT_BIT_KHR) );
}
for (deUint32 nCHitShaderName = 0;
nCHitShaderName < static_cast<deUint32>(chitCollectionShaderNameVec.size() );
nCHitShaderName ++)
{
const auto& currentCHitShaderName = chitCollectionShaderNameVec.at(nCHitShaderName);
Move<VkShaderModule> closestHitShader = createShaderModule( deviceInterface,
deviceVk,
collection.get(currentCHitShaderName),
0); /* flags */
rayTracingPipelinePtr->addShader( VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,
makeVkSharedPtr(closestHitShader),
hitGroupIndex + nCHitShaderName,
m_testPtr->getSpecializationInfoPtr(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR) );
}
if (m_data.geometryType == GeometryType::AABB ||
m_data.geometryType == GeometryType::AABB_AND_TRIANGLES)
{
for (deUint32 nIntersectionShaderName = 0;
nIntersectionShaderName < static_cast<deUint32>(intersectionCollectionShaderNameVec.size() );
nIntersectionShaderName ++)
{
const auto& currentIntersectionShaderName = intersectionCollectionShaderNameVec.at(nIntersectionShaderName);
Move<VkShaderModule> intersectionShader = createShaderModule( deviceInterface,
deviceVk,
collection.get(currentIntersectionShaderName),
0); /* flags */
rayTracingPipelinePtr->addShader( VK_SHADER_STAGE_INTERSECTION_BIT_KHR,
makeVkSharedPtr(intersectionShader),
hitGroupIndex + nIntersectionShaderName,
m_testPtr->getSpecializationInfoPtr(VK_SHADER_STAGE_INTERSECTION_BIT_KHR) );
}
}
for (deUint32 nCallableShader = 0; nCallableShader < static_cast<deUint32>(callableShaderCollectionNames.size() ); ++nCallableShader)
{
const auto& currentCallableShaderName = callableShaderCollectionNames.at ( nCallableShader);
Move<VkShaderModule> callableShader = createShaderModule ( deviceInterface,
deviceVk,
collection.get(currentCallableShaderName),
0); /* flags */
rayTracingPipelinePtr->addShader( VK_SHADER_STAGE_CALLABLE_BIT_KHR,
makeVkSharedPtr(callableShader),
static_cast<deUint32>(ShaderGroups::FIRST_CALLABLE_GROUP) + nCallableShader,
m_testPtr->getSpecializationInfoPtr(VK_SHADER_STAGE_CALLABLE_BIT_KHR) );
}
if (m_testPtr->usesDynamicStackSize() )
{
rayTracingPipelinePtr->addDynamicState(VK_DYNAMIC_STATE_RAY_TRACING_PIPELINE_STACK_SIZE_KHR);
}
rayTracingPipelinePtr->setMaxRecursionDepth(m_testPtr->getMaxRecursionDepthUsed() );
pipelineVkPtr = rayTracingPipelinePtr->createPipeline( deviceInterface,
deviceVk,
*pipelineLayoutPtr);
}
/* Cache shader stack size info */
{
VkDeviceSize ahitShaderStackSize = 0;
VkDeviceSize callableShaderStackSize = 0;
VkDeviceSize chitShaderStackSize = 0;
VkDeviceSize isectShaderStackSize = 0;
VkDeviceSize missShaderStackSize = 0;
VkDeviceSize raygenShaderStackSize = 0;
raygenShaderStackSize = deviceInterface.getRayTracingShaderGroupStackSizeKHR(deviceVk,
*pipelineVkPtr,
static_cast<deUint32>(ShaderGroups::RAYGEN_GROUP),
VK_SHADER_GROUP_SHADER_GENERAL_KHR);
if (collection.contains("ahit"))
{
ahitShaderStackSize = deviceInterface.getRayTracingShaderGroupStackSizeKHR( deviceVk,
*pipelineVkPtr,
static_cast<deUint32>(ShaderGroups::HIT_GROUP),
VK_SHADER_GROUP_SHADER_ANY_HIT_KHR);
}
if (collection.contains("chit") )
{
chitShaderStackSize = deviceInterface.getRayTracingShaderGroupStackSizeKHR( deviceVk,
*pipelineVkPtr,
static_cast<deUint32>(ShaderGroups::HIT_GROUP),
VK_SHADER_GROUP_SHADER_CLOSEST_HIT_KHR);
}
if (m_data.geometryType == GeometryType::AABB ||
m_data.geometryType == GeometryType::AABB_AND_TRIANGLES)
{
if (collection.contains("intersection") )
{
isectShaderStackSize = deviceInterface.getRayTracingShaderGroupStackSizeKHR( deviceVk,
*pipelineVkPtr,
static_cast<deUint32>(ShaderGroups::HIT_GROUP),
VK_SHADER_GROUP_SHADER_INTERSECTION_KHR);
}
}
if (nMissGroups > 0u)
{
missShaderStackSize = deviceInterface.getRayTracingShaderGroupStackSizeKHR( deviceVk,
*pipelineVkPtr,
static_cast<deUint32>(ShaderGroups::MISS_GROUP),
VK_SHADER_GROUP_SHADER_GENERAL_KHR);
}
for (deUint32 nCallableShader = 0; nCallableShader < static_cast<deUint32>(callableShaderCollectionNames.size() ); ++nCallableShader)
{
callableShaderStackSize += deviceInterface.getRayTracingShaderGroupStackSizeKHR( deviceVk,
*pipelineVkPtr,
static_cast<deUint32>(ShaderGroups::FIRST_CALLABLE_GROUP) + nCallableShader,
VK_SHADER_GROUP_SHADER_GENERAL_KHR);
}
m_testPtr->onShaderStackSizeDiscovered( raygenShaderStackSize,
ahitShaderStackSize,
chitShaderStackSize,
missShaderStackSize,
callableShaderStackSize,
isectShaderStackSize);
}
auto callableShaderBindingTablePtr = de::MovePtr<BufferWithMemory>();
if (callableShaderCollectionNames.size() != 0)
{
callableShaderBindingTablePtr = rayTracingPipelinePtr->createShaderBindingTable( deviceInterface,
deviceVk,
*pipelineVkPtr,
allocator,
m_rayTracingPropsPtr->getShaderGroupHandleSize (),
m_rayTracingPropsPtr->getShaderGroupBaseAlignment (),
static_cast<deUint32> (ShaderGroups::FIRST_CALLABLE_GROUP),
static_cast<deUint32> (callableShaderCollectionNames.size() ), /* groupCount */
0u, /* additionalBufferCreateFlags */
0u, /* additionalBufferUsageFlags */
MemoryRequirement::Any,
0u, /* opaqueCaptureAddress */
0u, /* shaderBindingTableOffset */
m_testPtr->getShaderRecordSize(ShaderGroups::FIRST_CALLABLE_GROUP) );
}
const auto raygenShaderBindingTablePtr = rayTracingPipelinePtr->createShaderBindingTable( deviceInterface,
deviceVk,
*pipelineVkPtr,
allocator,
m_rayTracingPropsPtr->getShaderGroupHandleSize (),
m_rayTracingPropsPtr->getShaderGroupBaseAlignment (),
raygenGroupIndex,
nRaygenGroups, /* groupCount */
0u, /* additionalBufferCreateFlags */
0u, /* additionalBufferUsageFlags */
MemoryRequirement::Any,
0u, /* opaqueCaptureAddress */
0u); /* shaderBindingTableOffset */
auto missShaderBindingTablePtr = de::MovePtr<BufferWithMemory>();
if (nMissGroups > 0u)
{
const void* missShaderBindingGroupShaderRecordDataPtr = m_testPtr->getShaderRecordData( ShaderGroups::MISS_GROUP);
missShaderBindingTablePtr = rayTracingPipelinePtr->createShaderBindingTable( deviceInterface,
deviceVk,
*pipelineVkPtr,
allocator,
m_rayTracingPropsPtr->getShaderGroupHandleSize (),
m_rayTracingPropsPtr->getShaderGroupBaseAlignment (),
missGroupIndex,
nMissGroups, /* groupCount */
0u, /* additionalBufferCreateFlags */
0u, /* additionalBufferUsageFlags */
MemoryRequirement::Any,
0u, /* opaqueCaptureAddress */
0u, /* shaderBindingTableOffset */
m_testPtr->getShaderRecordSize(ShaderGroups::MISS_GROUP),
&missShaderBindingGroupShaderRecordDataPtr);
}
auto hitShaderBindingTablePtr = de::MovePtr<BufferWithMemory>();
if (nHitGroups > 0u)
{
const void* hitShaderBindingGroupShaderRecordDataPtr = m_testPtr->getShaderRecordData( ShaderGroups::HIT_GROUP);
hitShaderBindingTablePtr = rayTracingPipelinePtr->createShaderBindingTable( deviceInterface,
deviceVk,
*pipelineVkPtr,
allocator,
m_rayTracingPropsPtr->getShaderGroupHandleSize (),
m_rayTracingPropsPtr->getShaderGroupBaseAlignment (),
hitGroupIndex,
nHitGroups, /* groupCount */
0u, /* additionalBufferCreateFlags */
0u, /* additionalBufferUsageFlags */
MemoryRequirement::Any,
0u, /* opaqueCaptureAddress */
0u, /* shaderBindingTableOffset */
m_testPtr->getShaderRecordSize(ShaderGroups::HIT_GROUP),
&hitShaderBindingGroupShaderRecordDataPtr);
}
{
const auto resultBufferCreateInfo = makeBufferCreateInfo ( resultBufferSize,
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
const auto resultBufferDataVec = m_testPtr->getResultBufferStartData ();
resultBufferPtr = de::MovePtr<BufferWithMemory>(
new BufferWithMemory( deviceInterface,
deviceVk,
allocator,
resultBufferCreateInfo,
MemoryRequirement::HostVisible));
if (resultBufferDataVec.size() > 0)
{
DE_ASSERT(static_cast<deUint32>(resultBufferDataVec.size() ) == resultBufferSize);
memcpy( resultBufferPtr->getAllocation().getHostPtr(),
resultBufferDataVec.data(),
resultBufferDataVec.size() );
flushAlloc(deviceInterface, deviceVk, resultBufferPtr->getAllocation());
}
}
beginCommandBuffer( deviceInterface,
*cmdBufferPtr,
0u /* flags */);
{
m_testPtr->initAS( m_context,
m_rayTracingPropsPtr.get(),
*cmdBufferPtr);
std::vector<TopLevelAccelerationStructure*> tlasPtrVec = m_testPtr->getTLASPtrVecToBind();
std::vector<VkAccelerationStructureKHR> tlasVkVec;
for (auto& currentTLASPtr : tlasPtrVec)
{
tlasVkVec.push_back(*currentTLASPtr->getPtr() );
}
if (m_testPtr->getResultBufferStartData().size() == 0)
{
deviceInterface.cmdFillBuffer( *cmdBufferPtr,
**resultBufferPtr,
0, /* dstOffset */
VK_WHOLE_SIZE,
0); /* data */
{
const auto postFillBarrier = makeBufferMemoryBarrier( VK_ACCESS_TRANSFER_WRITE_BIT, /* srcAccessMask */
VK_ACCESS_SHADER_WRITE_BIT, /* dstAccessMask */
**resultBufferPtr,
0, /* offset */
VK_WHOLE_SIZE);
cmdPipelineBufferMemoryBarrier( deviceInterface,
*cmdBufferPtr,
VK_PIPELINE_STAGE_TRANSFER_BIT, /* srcStageMask */
VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, /* dstStageMask */
&postFillBarrier);
}
}
{
VkWriteDescriptorSetAccelerationStructureKHR accelerationStructureWriteDescriptorSet =
{
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR, // VkStructureType sType;
DE_NULL, // const void* pNext;
static_cast<deUint32>(tlasVkVec.size() ), // deUint32 accelerationStructureCount;
tlasVkVec.data(), // const VkAccelerationStructureKHR* pAccelerationStructures;
};
const auto descriptorResultBufferInfo = makeDescriptorBufferInfo( **resultBufferPtr,
0, /* offset */
resultBufferSize);
DescriptorSetUpdateBuilder()
.writeSingle( *descriptorSetPtr,
DescriptorSetUpdateBuilder::Location::binding(0u),
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
&descriptorResultBufferInfo)
.writeArray( *descriptorSetPtr,
DescriptorSetUpdateBuilder::Location::binding(1u),
VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR,
static_cast<deUint32>(tlasVkVec.size() ),
&accelerationStructureWriteDescriptorSet)
.update ( deviceInterface,
deviceVk);
}
deviceInterface.cmdBindDescriptorSets( *cmdBufferPtr,
VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR,
*pipelineLayoutPtr,
0, /* firstSet */
1, /* descriptorSetCount */
&descriptorSetPtr.get(),
0, /* dynamicOffsetCount */
DE_NULL); /* pDynamicOffsets */
deviceInterface.cmdBindPipeline(*cmdBufferPtr,
VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR,
*pipelineVkPtr);
{
const auto preTraceMemoryBarrier = makeMemoryBarrier(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, /* srcAccessMask */
VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR); /* dstAccessMask */
cmdPipelineMemoryBarrier( deviceInterface,
*cmdBufferPtr,
VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, /* srcStageMask */
VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, /* dstStageMask */
&preTraceMemoryBarrier);
}
{
const auto nTraceRaysInvocationsNeeded = m_testPtr->getNTraceRayInvocationsNeeded();
const auto handleSize = m_rayTracingPropsPtr->getShaderGroupHandleSize();
const auto missStride = de::roundUp(handleSize + m_testPtr->getShaderRecordSize(ShaderGroups::MISS_GROUP), handleSize);
const auto hitStride = de::roundUp(handleSize + m_testPtr->getShaderRecordSize(ShaderGroups::HIT_GROUP), handleSize);
const auto callStride = de::roundUp(handleSize + m_testPtr->getShaderRecordSize(ShaderGroups::FIRST_CALLABLE_GROUP), handleSize);
const auto raygenShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress( deviceInterface,
deviceVk,
raygenShaderBindingTablePtr->get(),
0 /* offset */),
handleSize,
handleSize);
const auto missShaderBindingTableRegion = ((nMissGroups > 0u) ? makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress( deviceInterface,
deviceVk,
missShaderBindingTablePtr->get(),
0 /* offset */),
missStride,
missStride * nMissGroups)
: makeStridedDeviceAddressRegionKHR(DE_NULL,
0, /* stride */
0 /* size */));
const auto hitShaderBindingTableRegion = ((nHitGroups > 0u) ? makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress( deviceInterface,
deviceVk,
hitShaderBindingTablePtr->get(),
0 /* offset */),
hitStride,
hitStride * nHitGroups)
: makeStridedDeviceAddressRegionKHR(DE_NULL,
0, /* stride */
0 /* size */));
const auto callableShaderBindingTableRegion = (callableShaderCollectionNames.size() > 0) ? makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress( deviceInterface,
deviceVk,
callableShaderBindingTablePtr->get(),
0 /* offset */),
callStride, /* stride */
callStride * static_cast<deUint32>(callableShaderCollectionNames.size() ) )
: makeStridedDeviceAddressRegionKHR(DE_NULL,
0, /* stride */
0 /* size */);
if (m_testPtr->usesDynamicStackSize() )
{
deviceInterface.cmdSetRayTracingPipelineStackSizeKHR( *cmdBufferPtr,
m_testPtr->getDynamicStackSize(m_testPtr->getMaxRecursionDepthUsed()) );
}
for (deUint32 nInvocation = 0; nInvocation < nTraceRaysInvocationsNeeded; ++nInvocation)
{
m_testPtr->onBeforeCmdTraceRays(nInvocation,
m_context,
*cmdBufferPtr,
*pipelineLayoutPtr);
cmdTraceRays( deviceInterface,
*cmdBufferPtr,
&raygenShaderBindingTableRegion,
&missShaderBindingTableRegion,
&hitShaderBindingTableRegion,
&callableShaderBindingTableRegion,
m_testPtr->getDispatchSize()[0],
m_testPtr->getDispatchSize()[1],
m_testPtr->getDispatchSize()[2]);
}
}
{
const auto postTraceMemoryBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, /* srcAccessMask */
VK_ACCESS_HOST_READ_BIT); /* dstAccessMask */
cmdPipelineMemoryBarrier( deviceInterface,
*cmdBufferPtr,
VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, /* srcStageMask */
VK_PIPELINE_STAGE_HOST_BIT, /* dstStageMask */
&postTraceMemoryBarrier);
}
}
endCommandBuffer(deviceInterface,
*cmdBufferPtr);
submitCommandsAndWait( deviceInterface,
deviceVk,
queueVk,
cmdBufferPtr.get() );
invalidateMappedMemoryRange(deviceInterface,
deviceVk,
resultBufferPtr->getAllocation().getMemory(),
resultBufferPtr->getAllocation().getOffset(),
VK_WHOLE_SIZE);
m_testPtr->resetTLAS();
return resultBufferPtr;
}
tcu::TestStatus RayTracingMiscTestInstance::iterate (void)
{
checkSupport();
const de::MovePtr<BufferWithMemory> bufferGPUPtr = runTest();
const deUint32* bufferGPUDataPtr = (deUint32*) bufferGPUPtr->getAllocation().getHostPtr();
const bool result = m_testPtr->verifyResultBuffer(bufferGPUDataPtr);
if (result)
return tcu::TestStatus::pass("Pass");
else
return tcu::TestStatus::fail("Fail");
}
void nullMissSupport (Context& context)
{
context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
context.requireDeviceFunctionality("VK_KHR_buffer_device_address");
context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
}
void nullMissPrograms (vk::SourceCollections& programCollection)
{
const vk::ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
std::ostringstream rgen;
std::ostringstream chit;
rgen
<< "#version 460\n"
<< "#extension GL_EXT_ray_tracing : require\n"
<< "layout(location=0) rayPayloadEXT vec3 unused;\n"
<< "layout(set=0, binding=0) uniform accelerationStructureEXT topLevelAS;\n"
<< "layout(set=0, binding=1) buffer OutputBuffer { float val; } outBuffer;\n"
<< "\n"
<< "void main()\n"
<< "{\n"
<< " uint rayFlags = 0u;\n"
<< " uint cullMask = 0xFFu;\n"
<< " float tmin = 0.0;\n"
<< " float tmax = 9.0;\n"
<< " vec3 origin = vec3(0.0, 0.0, 0.0);\n"
<< " vec3 direct = vec3(0.0, 0.0, 1.0);\n"
<< " traceRayEXT(topLevelAS, rayFlags, cullMask, 0, 0, 0, origin, tmin, direct, tmax, 0);\n"
<< "}\n"
;
chit
<< "#version 460\n"
<< "#extension GL_EXT_ray_tracing : require\n"
<< "layout(location=0) rayPayloadInEXT vec3 unused;\n"
<< "layout(set=0, binding=0) uniform accelerationStructureEXT topLevelAS;\n"
<< "layout(set=0, binding=1) buffer OutputBuffer { float val; } outBuffer;\n"
<< "\n"
<< "void main()\n"
<< "{\n"
<< " outBuffer.val = 1.0;\n"
<< "}\n"
;
programCollection.glslSources.add("rgen") << glu::RaygenSource(updateRayTracingGLSL(rgen.str())) << buildOptions;
programCollection.glslSources.add("chit") << glu::ClosestHitSource(updateRayTracingGLSL(chit.str())) << buildOptions;
}
// Creates an empty shader binding table with a zeroed-out shader group handle.
de::MovePtr<BufferWithMemory> createEmptySBT (const DeviceInterface& vkd, VkDevice device, Allocator& alloc, deUint32 shaderGroupHandleSize)
{
const auto sbtSize = static_cast<VkDeviceSize>(shaderGroupHandleSize);
const auto sbtFlags = (VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT);
const auto sbtInfo = makeBufferCreateInfo(sbtSize, sbtFlags);
const auto sbtReqs = (MemoryRequirement::HostVisible | MemoryRequirement::DeviceAddress);
auto sbtBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(vkd, device, alloc, sbtInfo, sbtReqs));
auto& sbtAlloc = sbtBuffer->getAllocation();
void* sbtData = sbtAlloc.getHostPtr();
deMemset(sbtData, 0, static_cast<size_t>(sbtSize));
flushAlloc(vkd, device, sbtAlloc);
return sbtBuffer;
}
tcu::TestStatus nullMissInstance (Context& context)
{
const auto& vki = context.getInstanceInterface();
const auto physDev = context.getPhysicalDevice();
const auto& vkd = context.getDeviceInterface();
const auto device = context.getDevice();
auto& alloc = context.getDefaultAllocator();
const auto qIndex = context.getUniversalQueueFamilyIndex();
const auto queue = context.getUniversalQueue();
const auto stages = (VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
// Command pool and buffer.
const auto cmdPool = makeCommandPool(vkd, device, qIndex);
const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
const auto cmdBuffer = cmdBufferPtr.get();
beginCommandBuffer(vkd, cmdBuffer);
// Build acceleration structures.
auto topLevelAS = makeTopLevelAccelerationStructure();
auto bottomLevelAS = makeBottomLevelAccelerationStructure();
std::vector<tcu::Vec3> triangle;
triangle.reserve(3u);
triangle.emplace_back( 0.0f, 1.0f, 10.0f);
triangle.emplace_back(-1.0f, -1.0f, 10.0f);
triangle.emplace_back( 1.0f, -1.0f, 10.0f);
bottomLevelAS->addGeometry(triangle, true/*triangles*/);
bottomLevelAS->createAndBuild(vkd, device, cmdBuffer, alloc);
de::SharedPtr<BottomLevelAccelerationStructure> blasSharedPtr (bottomLevelAS.release());
topLevelAS->setInstanceCount(1);
topLevelAS->addInstance(blasSharedPtr);
topLevelAS->createAndBuild(vkd, device, cmdBuffer, alloc);
// Create output buffer.
const auto bufferSize = static_cast<VkDeviceSize>(sizeof(float));
const auto bufferCreateInfo = makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
BufferWithMemory buffer (vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible);
auto& bufferAlloc = buffer.getAllocation();
// Fill output buffer with an initial value.
deMemset(bufferAlloc.getHostPtr(), 0, sizeof(float));
flushAlloc(vkd, device, bufferAlloc);
// Descriptor set layout and pipeline layout.
DescriptorSetLayoutBuilder setLayoutBuilder;
setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, stages);
setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, stages);
const auto setLayout = setLayoutBuilder.build(vkd, device);
const auto pipelineLayout = makePipelineLayout(vkd, device, setLayout.get());
// Descriptor pool and set.
DescriptorPoolBuilder poolBuilder;
poolBuilder.addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR);
poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
const auto descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
const auto descriptorSet = makeDescriptorSet(vkd, device, descriptorPool.get(), setLayout.get());
// Update descriptor set.
{
const VkWriteDescriptorSetAccelerationStructureKHR accelDescInfo =
{
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR,
nullptr,
1u,
topLevelAS.get()->getPtr(),
};
const auto bufferDescInfo = makeDescriptorBufferInfo(buffer.get(), 0ull, VK_WHOLE_SIZE);
DescriptorSetUpdateBuilder updateBuilder;
updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &accelDescInfo);
updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &bufferDescInfo);
updateBuilder.update(vkd, device);
}
// Shader modules.
auto rgenModule = createShaderModule(vkd, device, context.getBinaryCollection().get("rgen"), 0);
auto chitModule = createShaderModule(vkd, device, context.getBinaryCollection().get("chit"), 0);
// Get some ray tracing properties.
deUint32 shaderGroupHandleSize = 0u;
deUint32 shaderGroupBaseAlignment = 1u;
{
const auto rayTracingPropertiesKHR = makeRayTracingProperties(vki, physDev);
shaderGroupHandleSize = rayTracingPropertiesKHR->getShaderGroupHandleSize();
shaderGroupBaseAlignment = rayTracingPropertiesKHR->getShaderGroupBaseAlignment();
}
// Create raytracing pipeline and shader binding tables.
Move<VkPipeline> pipeline;
de::MovePtr<BufferWithMemory> raygenSBT;
de::MovePtr<BufferWithMemory> missSBT;
de::MovePtr<BufferWithMemory> hitSBT;
de::MovePtr<BufferWithMemory> callableSBT;
VkStridedDeviceAddressRegionKHR raygenSBTRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
VkStridedDeviceAddressRegionKHR missSBTRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
VkStridedDeviceAddressRegionKHR hitSBTRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
VkStridedDeviceAddressRegionKHR callableSBTRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
{
const auto rayTracingPipeline = de::newMovePtr<RayTracingPipeline>();
rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, rgenModule, 0u);
rayTracingPipeline->addShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, chitModule, 1u);
pipeline = rayTracingPipeline->createPipeline(vkd, device, pipelineLayout.get());
raygenSBT = rayTracingPipeline->createShaderBindingTable(vkd, device, pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 0u, 1u);
raygenSBTRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, raygenSBT->get(), 0ull), shaderGroupHandleSize, shaderGroupHandleSize);
hitSBT = rayTracingPipeline->createShaderBindingTable(vkd, device, pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 1u, 1u);
hitSBTRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, hitSBT->get(), 0ull), shaderGroupHandleSize, shaderGroupHandleSize);
// Critical for the test: the miss shader binding table buffer is empty and contains a zero'ed out shader group handle.
missSBT = createEmptySBT(vkd, device, alloc, shaderGroupHandleSize);
missSBTRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, missSBT->get(), 0ull), shaderGroupHandleSize, shaderGroupHandleSize);
}
// Trace rays.
vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.get());
vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr);
vkd.cmdTraceRaysKHR(cmdBuffer, &raygenSBTRegion, &missSBTRegion, &hitSBTRegion, &callableSBTRegion, 1u, 1u, 1u);
// Barrier for the output buffer just in case (no writes should take place).
const auto bufferBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &bufferBarrier, 0u, nullptr, 0u, nullptr);
endCommandBuffer(vkd, cmdBuffer);
submitCommandsAndWait(vkd, device, queue, cmdBuffer);
// Read value back from the buffer. No write should have taken place.
float bufferValue = 0.0f;
invalidateAlloc(vkd, device, bufferAlloc);
deMemcpy(&bufferValue, bufferAlloc.getHostPtr(), sizeof(bufferValue));
if (bufferValue != 0.0f)
TCU_FAIL("Unexpected value found in buffer: " + de::toString(bufferValue));
return tcu::TestStatus::pass("Pass");
}
} // anonymous
class RayTracingTestCase : public TestCase
{
public:
RayTracingTestCase ( tcu::TestContext& context,
const char* name,
const char* desc,
const CaseDef data);
~RayTracingTestCase ( void);
virtual void checkSupport (Context& context) const final;
virtual TestInstance* createInstance (Context& context) const final;
void initPrograms (SourceCollections& programCollection) const final;
private:
CaseDef m_data;
mutable std::unique_ptr<TestBase> m_testPtr;
};
RayTracingTestCase::RayTracingTestCase (tcu::TestContext& context,
const char* name,
const char* desc,
const CaseDef data)
: vkt::TestCase ( context,
name,
desc)
, m_data ( data)
{
/* Stub */
}
RayTracingTestCase::~RayTracingTestCase (void)
{
}
void RayTracingTestCase::checkSupport(Context& context) const
{
context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
context.requireDeviceFunctionality("VK_KHR_buffer_device_address");
context.requireDeviceFunctionality("VK_KHR_deferred_host_operations");
context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
const VkPhysicalDeviceAccelerationStructureFeaturesKHR& accelerationStructureFeaturesKHR = context.getAccelerationStructureFeatures ();
const VkPhysicalDeviceRayTracingPipelineFeaturesKHR& rayTracingPipelineFeaturesKHR = context.getRayTracingPipelineFeatures ();
const auto& rayTracingPipelinePropertiesKHR = context.getRayTracingPipelineProperties ();
if (rayTracingPipelineFeaturesKHR.rayTracingPipeline == DE_FALSE)
{
TCU_THROW(NotSupportedError, "VkPhysicalDeviceRayTracingPipelineFeaturesKHR::rayTracingPipeline is false");
}
if (accelerationStructureFeaturesKHR.accelerationStructure == DE_FALSE)
{
TCU_THROW(NotSupportedError, "VkPhysicalDeviceAccelerationStructureFeaturesKHR::accelerationStructure is false");
}
if (ShaderRecordBlockTest::isTest(m_data.type) )
{
if (ShaderRecordBlockTest::isExplicitScalarOffsetTest (m_data.type) ||
ShaderRecordBlockTest::isScalarLayoutTest (m_data.type))
{
context.requireDeviceFunctionality("VK_EXT_scalar_block_layout");
}
if (ShaderRecordBlockTest::usesF64(m_data.type))
{
context.requireDeviceCoreFeature(vkt::DeviceCoreFeature::DEVICE_CORE_FEATURE_SHADER_FLOAT64);
}
if (ShaderRecordBlockTest::usesI8(m_data.type) ||
ShaderRecordBlockTest::usesU8(m_data.type) )
{
if (context.get8BitStorageFeatures().storageBuffer8BitAccess == VK_FALSE)
{
TCU_THROW(NotSupportedError, "storageBuffer8BitAccess feature is unavailable");
}
}
if (ShaderRecordBlockTest::usesI16(m_data.type) ||
ShaderRecordBlockTest::usesU16(m_data.type) )
{
context.requireDeviceCoreFeature(vkt::DeviceCoreFeature::DEVICE_CORE_FEATURE_SHADER_INT16);
}
if (ShaderRecordBlockTest::usesI64(m_data.type) ||
ShaderRecordBlockTest::usesU64(m_data.type) )
{
context.requireDeviceCoreFeature(vkt::DeviceCoreFeature::DEVICE_CORE_FEATURE_SHADER_INT64);
}
}
if (static_cast<deUint32>(m_data.type) >= static_cast<deUint32>(TestType::RECURSIVE_TRACES_1) &&
static_cast<deUint32>(m_data.type) <= static_cast<deUint32>(TestType::RECURSIVE_TRACES_29) )
{
const auto nLevels = static_cast<deUint32>(m_data.type) - static_cast<deUint32>(TestType::RECURSIVE_TRACES_1) + 1;
if (rayTracingPipelinePropertiesKHR.maxRayRecursionDepth < nLevels)
{
TCU_THROW(NotSupportedError, "Cannot use an unsupported ray recursion depth.");
}
}
}
void RayTracingTestCase::initPrograms(SourceCollections& programCollection) const
{
switch (m_data.type)
{
case TestType::AABBS_AND_TRIS_IN_ONE_TL:
{
m_testPtr.reset(
new AABBTriTLTest(m_data.geometryType, m_data.asLayout)
);
m_testPtr->initPrograms(programCollection);
break;
}
case TestType::AS_STRESS_TEST:
{
m_testPtr.reset(
new ASStressTest(m_data.geometryType, m_data.asLayout)
);
m_testPtr->initPrograms(programCollection);
break;
}
case TestType::CALLABLE_SHADER_STRESS_DYNAMIC_TEST:
case TestType::CALLABLE_SHADER_STRESS_TEST:
{
const bool useDynamicStackSize = (m_data.type == TestType::CALLABLE_SHADER_STRESS_DYNAMIC_TEST);
m_testPtr.reset(
new CallableShaderStressTest(m_data.geometryType, m_data.asLayout, useDynamicStackSize)
);
m_testPtr->initPrograms(programCollection);
break;
}
case TestType::CULL_MASK:
case TestType::CULL_MASK_EXTRA_BITS:
{
m_testPtr.reset(
new CullMaskTest(m_data.asLayout, m_data.geometryType, (m_data.type == TestType::CULL_MASK_EXTRA_BITS) )
);
m_testPtr->initPrograms(programCollection);
break;
}
case TestType::MAX_RAY_HIT_ATTRIBUTE_SIZE:
{
m_testPtr.reset(
new MAXRayHitAttributeSizeTest(m_data.geometryType, m_data.asLayout)
);
m_testPtr->initPrograms(programCollection);
break;
}
case TestType::MAX_RT_INVOCATIONS_SUPPORTED:
{
m_testPtr.reset(
new MAXRTInvocationsSupportedTest(m_data.geometryType, m_data.asLayout)
);
m_testPtr->initPrograms(programCollection);
break;
}
case TestType::NO_DUPLICATE_ANY_HIT:
{
m_testPtr.reset(
new NoDuplicateAnyHitTest(m_data.asLayout, m_data.geometryType)
);
m_testPtr->initPrograms(programCollection);
break;
}
case TestType::RECURSIVE_TRACES_0:
case TestType::RECURSIVE_TRACES_1:
case TestType::RECURSIVE_TRACES_2:
case TestType::RECURSIVE_TRACES_3:
case TestType::RECURSIVE_TRACES_4:
case TestType::RECURSIVE_TRACES_5:
case TestType::RECURSIVE_TRACES_6:
case TestType::RECURSIVE_TRACES_7:
case TestType::RECURSIVE_TRACES_8:
case TestType::RECURSIVE_TRACES_9:
case TestType::RECURSIVE_TRACES_10:
case TestType::RECURSIVE_TRACES_11:
case TestType::RECURSIVE_TRACES_12:
case TestType::RECURSIVE_TRACES_13:
case TestType::RECURSIVE_TRACES_14:
case TestType::RECURSIVE_TRACES_15:
case TestType::RECURSIVE_TRACES_16:
case TestType::RECURSIVE_TRACES_17:
case TestType::RECURSIVE_TRACES_18:
case TestType::RECURSIVE_TRACES_19:
case TestType::RECURSIVE_TRACES_20:
case TestType::RECURSIVE_TRACES_21:
case TestType::RECURSIVE_TRACES_22:
case TestType::RECURSIVE_TRACES_23:
case TestType::RECURSIVE_TRACES_24:
case TestType::RECURSIVE_TRACES_25:
case TestType::RECURSIVE_TRACES_26:
case TestType::RECURSIVE_TRACES_27:
case TestType::RECURSIVE_TRACES_28:
case TestType::RECURSIVE_TRACES_29:
{
const auto nLevels = ((m_data.type == TestType::RECURSIVE_TRACES_0)
? 0u
: (static_cast<deUint32>(m_data.type) - static_cast<deUint32>(TestType::RECURSIVE_TRACES_1) + 1));
m_testPtr.reset(
new RecursiveTracesTest(m_data.geometryType, m_data.asLayout, nLevels)
);
m_testPtr->initPrograms(programCollection);
break;
}
case TestType::REPORT_INTERSECTION_RESULT:
{
m_testPtr.reset(
new ReportIntersectionResultTest(m_data.asLayout, m_data.geometryType)
);
m_testPtr->initPrograms(programCollection);
break;
}
case TestType::RAY_PAYLOAD_IN:
{
m_testPtr.reset(
new RayPayloadInTest(m_data.geometryType, m_data.asLayout)
);
m_testPtr->initPrograms(programCollection);
break;
}
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_1:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_2:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_3:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_4:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_5:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_6:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_1:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_2:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_3:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_4:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_5:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_6:
case TestType::SHADER_RECORD_BLOCK_SCALAR_1:
case TestType::SHADER_RECORD_BLOCK_SCALAR_2:
case TestType::SHADER_RECORD_BLOCK_SCALAR_3:
case TestType::SHADER_RECORD_BLOCK_SCALAR_4:
case TestType::SHADER_RECORD_BLOCK_SCALAR_5:
case TestType::SHADER_RECORD_BLOCK_SCALAR_6:
case TestType::SHADER_RECORD_BLOCK_STD430_1:
case TestType::SHADER_RECORD_BLOCK_STD430_2:
case TestType::SHADER_RECORD_BLOCK_STD430_3:
case TestType::SHADER_RECORD_BLOCK_STD430_4:
case TestType::SHADER_RECORD_BLOCK_STD430_5:
case TestType::SHADER_RECORD_BLOCK_STD430_6:
{
m_testPtr.reset(
new ShaderRecordBlockTest( m_data.type,
ShaderRecordBlockTest::getVarsToTest(m_data.type) )
);
m_testPtr->initPrograms(programCollection);
break;
}
case TestType::IGNORE_ANY_HIT_DYNAMICALLY:
case TestType::IGNORE_ANY_HIT_STATICALLY:
case TestType::TERMINATE_ANY_HIT_DYNAMICALLY:
case TestType::TERMINATE_ANY_HIT_STATICALLY:
case TestType::TERMINATE_INTERSECTION_DYNAMICALLY:
case TestType::TERMINATE_INTERSECTION_STATICALLY:
{
m_testPtr.reset(
new TerminationTest(TerminationTest::getModeFromTestType(m_data.type) )
);
m_testPtr->initPrograms(programCollection);
break;
}
default:
{
deAssertFail( "This location should never be reached",
__FILE__,
__LINE__);
}
}
}
TestInstance* RayTracingTestCase::createInstance (Context& context) const
{
switch (m_data.type)
{
case TestType::AABBS_AND_TRIS_IN_ONE_TL:
{
if (m_testPtr == nullptr)
{
m_testPtr.reset(
new AABBTriTLTest(m_data.geometryType, m_data.asLayout)
);
}
break;
}
case TestType::AS_STRESS_TEST:
{
if (m_testPtr == nullptr)
{
m_testPtr.reset(
new ASStressTest(m_data.geometryType, m_data.asLayout)
);
}
break;
}
case TestType::CALLABLE_SHADER_STRESS_DYNAMIC_TEST:
case TestType::CALLABLE_SHADER_STRESS_TEST:
{
if (m_testPtr == nullptr)
{
const bool useDynamicStackSize = (m_data.type == TestType::CALLABLE_SHADER_STRESS_DYNAMIC_TEST);
m_testPtr.reset(
new CallableShaderStressTest(m_data.geometryType, m_data.asLayout, useDynamicStackSize)
);
}
break;
}
case TestType::CULL_MASK:
case TestType::CULL_MASK_EXTRA_BITS:
{
if (m_testPtr == nullptr)
{
m_testPtr.reset(
new CullMaskTest(m_data.asLayout, m_data.geometryType, (m_data.type == TestType::CULL_MASK_EXTRA_BITS) )
);
}
break;
}
case TestType::MAX_RAY_HIT_ATTRIBUTE_SIZE:
{
if (m_testPtr == nullptr)
{
m_testPtr.reset(
new MAXRayHitAttributeSizeTest(m_data.geometryType, m_data.asLayout)
);
}
break;
}
case TestType::MAX_RT_INVOCATIONS_SUPPORTED:
{
if (m_testPtr == nullptr)
{
m_testPtr.reset(
new MAXRTInvocationsSupportedTest(m_data.geometryType, m_data.asLayout)
);
}
break;
}
case TestType::NO_DUPLICATE_ANY_HIT:
{
if (m_testPtr == nullptr)
{
m_testPtr.reset(
new NoDuplicateAnyHitTest(m_data.asLayout, m_data.geometryType)
);
}
break;
}
case TestType::RECURSIVE_TRACES_0:
case TestType::RECURSIVE_TRACES_1:
case TestType::RECURSIVE_TRACES_2:
case TestType::RECURSIVE_TRACES_3:
case TestType::RECURSIVE_TRACES_4:
case TestType::RECURSIVE_TRACES_5:
case TestType::RECURSIVE_TRACES_6:
case TestType::RECURSIVE_TRACES_7:
case TestType::RECURSIVE_TRACES_8:
case TestType::RECURSIVE_TRACES_9:
case TestType::RECURSIVE_TRACES_10:
case TestType::RECURSIVE_TRACES_11:
case TestType::RECURSIVE_TRACES_12:
case TestType::RECURSIVE_TRACES_13:
case TestType::RECURSIVE_TRACES_14:
case TestType::RECURSIVE_TRACES_15:
case TestType::RECURSIVE_TRACES_16:
case TestType::RECURSIVE_TRACES_17:
case TestType::RECURSIVE_TRACES_18:
case TestType::RECURSIVE_TRACES_19:
case TestType::RECURSIVE_TRACES_20:
case TestType::RECURSIVE_TRACES_21:
case TestType::RECURSIVE_TRACES_22:
case TestType::RECURSIVE_TRACES_23:
case TestType::RECURSIVE_TRACES_24:
case TestType::RECURSIVE_TRACES_25:
case TestType::RECURSIVE_TRACES_26:
case TestType::RECURSIVE_TRACES_27:
case TestType::RECURSIVE_TRACES_28:
case TestType::RECURSIVE_TRACES_29:
{
const auto nLevels = ((m_data.type == TestType::RECURSIVE_TRACES_0)
? 0u
: (static_cast<deUint32>(m_data.type) - static_cast<deUint32>(TestType::RECURSIVE_TRACES_1) + 1));
if (m_testPtr == nullptr)
{
m_testPtr.reset(
new RecursiveTracesTest(m_data.geometryType, m_data.asLayout, nLevels)
);
}
break;
}
case TestType::REPORT_INTERSECTION_RESULT:
{
if (m_testPtr == nullptr)
{
m_testPtr.reset(
new ReportIntersectionResultTest(m_data.asLayout, m_data.geometryType)
);
}
break;
}
case TestType::RAY_PAYLOAD_IN:
{
if (m_testPtr == nullptr)
{
m_testPtr.reset(
new RayPayloadInTest(m_data.geometryType, m_data.asLayout)
);
}
break;
}
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_1:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_2:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_3:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_4:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_5:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_6:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_1:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_2:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_3:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_4:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_5:
case TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_6:
case TestType::SHADER_RECORD_BLOCK_SCALAR_1:
case TestType::SHADER_RECORD_BLOCK_SCALAR_2:
case TestType::SHADER_RECORD_BLOCK_SCALAR_3:
case TestType::SHADER_RECORD_BLOCK_SCALAR_4:
case TestType::SHADER_RECORD_BLOCK_SCALAR_5:
case TestType::SHADER_RECORD_BLOCK_SCALAR_6:
case TestType::SHADER_RECORD_BLOCK_STD430_1:
case TestType::SHADER_RECORD_BLOCK_STD430_2:
case TestType::SHADER_RECORD_BLOCK_STD430_3:
case TestType::SHADER_RECORD_BLOCK_STD430_4:
case TestType::SHADER_RECORD_BLOCK_STD430_5:
case TestType::SHADER_RECORD_BLOCK_STD430_6:
{
if (m_testPtr == nullptr)
{
m_testPtr.reset(
new ShaderRecordBlockTest( m_data.type,
ShaderRecordBlockTest::getVarsToTest(m_data.type))
);
}
break;
}
case TestType::IGNORE_ANY_HIT_DYNAMICALLY:
case TestType::IGNORE_ANY_HIT_STATICALLY:
case TestType::TERMINATE_ANY_HIT_DYNAMICALLY:
case TestType::TERMINATE_ANY_HIT_STATICALLY:
case TestType::TERMINATE_INTERSECTION_DYNAMICALLY:
case TestType::TERMINATE_INTERSECTION_STATICALLY:
{
if (m_testPtr == nullptr)
{
m_testPtr.reset(
new TerminationTest(TerminationTest::getModeFromTestType(m_data.type) )
);
}
break;
}
default:
{
deAssertFail( "This location should never be reached",
__FILE__,
__LINE__);
}
}
auto newTestInstancePtr = new RayTracingMiscTestInstance( context,
m_data,
m_testPtr.get () );
return newTestInstancePtr;
}
tcu::TestCaseGroup* createMiscTests (tcu::TestContext& testCtx)
{
de::MovePtr<tcu::TestCaseGroup> miscGroupPtr(
new tcu::TestCaseGroup(
testCtx,
"misc",
"Miscellaneous ray-tracing tests"));
for (auto currentGeometryType = GeometryType::FIRST; currentGeometryType != GeometryType::COUNT; currentGeometryType = static_cast<GeometryType>(static_cast<deUint32>(currentGeometryType) + 1) )
{
for (auto currentASLayout = AccelerationStructureLayout::FIRST; currentASLayout != AccelerationStructureLayout::COUNT; currentASLayout = static_cast<AccelerationStructureLayout>(static_cast<deUint32>(currentASLayout) + 1) )
{
for (deUint32 nIteration = 0; nIteration < 2; ++nIteration)
{
const auto testType = (nIteration == 0) ? TestType::CALLABLE_SHADER_STRESS_DYNAMIC_TEST
: TestType::CALLABLE_SHADER_STRESS_TEST;
const std::string newTestCaseName = "callableshaderstress_" +
de::toString(getSuffixForASLayout(currentASLayout) ) +
"_" +
de::toString(getSuffixForGeometryType(currentGeometryType) ) +
"_" +
((testType == TestType::CALLABLE_SHADER_STRESS_DYNAMIC_TEST) ? "dynamic"
: "static");
auto newTestCasePtr = new RayTracingTestCase( testCtx,
newTestCaseName.data(),
"Verifies that the maximum ray hit attribute size property reported by the implementation is actually supported.",
CaseDef{testType, currentGeometryType, currentASLayout});
miscGroupPtr->addChild(newTestCasePtr);
}
}
}
for (auto currentGeometryType = GeometryType::FIRST; currentGeometryType != GeometryType::COUNT; currentGeometryType = static_cast<GeometryType>(static_cast<deUint32>(currentGeometryType) + 1) )
{
const std::string newTestCaseName = "AS_stresstest_" + de::toString(getSuffixForGeometryType(currentGeometryType) );
auto newTestCasePtr = new RayTracingTestCase( testCtx,
newTestCaseName.data(),
"Verifies raygen shader invocations can simultaneously access as many AS instances as reported",
CaseDef{TestType::AS_STRESS_TEST, currentGeometryType, AccelerationStructureLayout::ONE_TL_MANY_BLS_ONE_GEOMETRY});
miscGroupPtr->addChild(newTestCasePtr);
}
for (auto currentGeometryType = GeometryType::FIRST; currentGeometryType != GeometryType::COUNT; currentGeometryType = static_cast<GeometryType>(static_cast<deUint32>(currentGeometryType) + 1) )
{
for (int nUseExtraCullMaskBits = 0; nUseExtraCullMaskBits < 2 /* false, true */; ++nUseExtraCullMaskBits)
{
const std::string newTestCaseName = "cullmask_" + de::toString(getSuffixForGeometryType(currentGeometryType) ) + de::toString((nUseExtraCullMaskBits) ? "_extrabits" : "");
const auto testType = (nUseExtraCullMaskBits == 0) ? TestType::CULL_MASK
: TestType::CULL_MASK_EXTRA_BITS;
auto newTestCasePtr = new RayTracingTestCase( testCtx,
newTestCaseName.data(),
"Verifies cull mask works as specified",
CaseDef{testType, currentGeometryType, AccelerationStructureLayout::ONE_TL_MANY_BLS_ONE_GEOMETRY});
miscGroupPtr->addChild(newTestCasePtr);
}
}
for (auto currentGeometryType = GeometryType::FIRST; currentGeometryType != GeometryType::COUNT; currentGeometryType = static_cast<GeometryType>(static_cast<deUint32>(currentGeometryType) + 1) )
{
const std::string newTestCaseName = "maxrtinvocations_" + de::toString(getSuffixForGeometryType(currentGeometryType) );
auto newTestCasePtr = new RayTracingTestCase( testCtx,
newTestCaseName.data(),
"Verifies top-level acceleration structures built of AABB and triangle bottom-level AS instances work as expected",
CaseDef{TestType::MAX_RT_INVOCATIONS_SUPPORTED, currentGeometryType, AccelerationStructureLayout::ONE_TL_ONE_BL_ONE_GEOMETRY});
miscGroupPtr->addChild(newTestCasePtr);
}
for (auto currentGeometryType = GeometryType::FIRST; currentGeometryType != GeometryType::COUNT; currentGeometryType = static_cast<GeometryType>(static_cast<deUint32>(currentGeometryType) + 1) )
{
for (auto currentASLayout = AccelerationStructureLayout::FIRST; currentASLayout != AccelerationStructureLayout::COUNT; currentASLayout = static_cast<AccelerationStructureLayout>(static_cast<deUint32>(currentASLayout) + 1) )
{
const std::string newTestCaseName = "NO_DUPLICATE_ANY_HIT_" + de::toString(getSuffixForASLayout(currentASLayout) ) + "_" + de::toString(getSuffixForGeometryType(currentGeometryType) );
auto newTestCasePtr = new RayTracingTestCase( testCtx,
newTestCaseName.data(),
"Verifies the NO_DUPLICATE_ANY_HIT flag is adhered to when tracing rays",
CaseDef{TestType::NO_DUPLICATE_ANY_HIT, currentGeometryType, currentASLayout});
miscGroupPtr->addChild(newTestCasePtr);
}
}
{
auto newTestCasePtr = new RayTracingTestCase( testCtx,
"mixedPrimTL",
"Verifies top-level acceleration structures built of AABB and triangle bottom-level AS instances work as expected",
CaseDef{TestType::AABBS_AND_TRIS_IN_ONE_TL, GeometryType::AABB_AND_TRIANGLES, AccelerationStructureLayout::ONE_TL_MANY_BLS_MANY_GEOMETRIES_WITH_VARYING_PRIM_TYPES});
miscGroupPtr->addChild(newTestCasePtr);
}
for (auto currentASLayout = AccelerationStructureLayout::FIRST; currentASLayout != AccelerationStructureLayout::COUNT; currentASLayout = static_cast<AccelerationStructureLayout>(static_cast<deUint32>(currentASLayout) + 1) )
{
const std::string newTestCaseName = "maxrayhitattributesize_" + de::toString(getSuffixForASLayout(currentASLayout) );
auto newTestCasePtr = new RayTracingTestCase( testCtx,
newTestCaseName.data(),
"Verifies that the maximum ray hit attribute size property reported by the implementation is actually supported.",
CaseDef{TestType::MAX_RAY_HIT_ATTRIBUTE_SIZE, GeometryType::AABB, AccelerationStructureLayout::ONE_TL_ONE_BL_ONE_GEOMETRY});
miscGroupPtr->addChild(newTestCasePtr);
}
{
auto newTestCasePtr = new RayTracingTestCase(testCtx,
"report_intersection_result",
"Test the return value of reportIntersectionEXT",
CaseDef{TestType::REPORT_INTERSECTION_RESULT, GeometryType::AABB, AccelerationStructureLayout::ONE_TL_ONE_BL_ONE_GEOMETRY});
miscGroupPtr->addChild(newTestCasePtr);
}
for (auto currentGeometryType = GeometryType::FIRST; currentGeometryType != GeometryType::COUNT; currentGeometryType = static_cast<GeometryType>(static_cast<deUint32>(currentGeometryType) + 1) )
{
const std::string newTestCaseName = "raypayloadin_" + de::toString(getSuffixForGeometryType(currentGeometryType) );
auto newTestCasePtr = new RayTracingTestCase( testCtx,
newTestCaseName.data(),
"Verifies that relevant shader stages can correctly read large ray payloads provided by raygen shader stage.",
CaseDef{TestType::RAY_PAYLOAD_IN, currentGeometryType, AccelerationStructureLayout::ONE_TL_ONE_BL_ONE_GEOMETRY});
miscGroupPtr->addChild(newTestCasePtr);
}
{
auto newTestCaseSTD430_1Ptr = new RayTracingTestCase( testCtx,
"shaderRecordSTD430_1",
"Tests usage of various variables inside a shader record block using std430 layout",
CaseDef(TestType::SHADER_RECORD_BLOCK_STD430_1) );
auto newTestCaseSTD430_2Ptr = new RayTracingTestCase( testCtx,
"shaderRecordSTD430_2",
"Tests usage of various variables inside a shader record block using std430 layout",
CaseDef(TestType::SHADER_RECORD_BLOCK_STD430_2) );
auto newTestCaseSTD430_3Ptr = new RayTracingTestCase( testCtx,
"shaderRecordSTD430_3",
"Tests usage of various variables inside a shader record block using std430 layout",
CaseDef(TestType::SHADER_RECORD_BLOCK_STD430_3) );
auto newTestCaseSTD430_4Ptr = new RayTracingTestCase( testCtx,
"shaderRecordSTD430_4",
"Tests usage of various variables inside a shader record block using std430 layout",
CaseDef(TestType::SHADER_RECORD_BLOCK_STD430_4) );
auto newTestCaseSTD430_5Ptr = new RayTracingTestCase( testCtx,
"shaderRecordSTD430_5",
"Tests usage of various variables inside a shader record block using std430 layout",
CaseDef(TestType::SHADER_RECORD_BLOCK_STD430_5) );
auto newTestCaseSTD430_6Ptr = new RayTracingTestCase( testCtx,
"shaderRecordSTD430_6",
"Tests usage of various variables inside a shader record block using std430 layout",
CaseDef(TestType::SHADER_RECORD_BLOCK_STD430_6) );
auto newTestCaseScalar_1Ptr = new RayTracingTestCase( testCtx,
"shaderRecordScalar_1",
"Tests usage of various variables inside a shader record block using scalar layout",
CaseDef(TestType::SHADER_RECORD_BLOCK_SCALAR_1) );
auto newTestCaseScalar_2Ptr = new RayTracingTestCase( testCtx,
"shaderRecordScalar_2",
"Tests usage of various variables inside a shader record block using scalar layout",
CaseDef(TestType::SHADER_RECORD_BLOCK_SCALAR_2) );
auto newTestCaseScalar_3Ptr = new RayTracingTestCase( testCtx,
"shaderRecordScalar_3",
"Tests usage of various variables inside a shader record block using scalar layout",
CaseDef(TestType::SHADER_RECORD_BLOCK_SCALAR_3) );
auto newTestCaseScalar_4Ptr = new RayTracingTestCase( testCtx,
"shaderRecordScalar_4",
"Tests usage of various variables inside a shader record block using scalar layout",
CaseDef(TestType::SHADER_RECORD_BLOCK_SCALAR_4) );
auto newTestCaseScalar_5Ptr = new RayTracingTestCase( testCtx,
"shaderRecordScalar_5",
"Tests usage of various variables inside a shader record block using scalar layout",
CaseDef(TestType::SHADER_RECORD_BLOCK_SCALAR_5) );
auto newTestCaseScalar_6Ptr = new RayTracingTestCase( testCtx,
"shaderRecordScalar_6",
"Tests usage of various variables inside a shader record block using scalar layout",
CaseDef(TestType::SHADER_RECORD_BLOCK_SCALAR_6) );
auto newTestCaseExplicitScalarOffset_1Ptr = new RayTracingTestCase( testCtx,
"shaderRecordExplicitScalarOffset_1",
"Tests usage of various variables inside a shader record block using scalar layout and explicit offset qualifiers",
CaseDef(TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_1) );
auto newTestCaseExplicitScalarOffset_2Ptr = new RayTracingTestCase( testCtx,
"shaderRecordExplicitScalarOffset_2",
"Tests usage of various variables inside a shader record block using scalar layout and explicit offset qualifiers",
CaseDef(TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_2) );
auto newTestCaseExplicitScalarOffset_3Ptr = new RayTracingTestCase( testCtx,
"shaderRecordExplicitScalarOffset_3",
"Tests usage of various variables inside a shader record block using scalar layout and explicit offset qualifiers",
CaseDef(TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_3) );
auto newTestCaseExplicitScalarOffset_4Ptr = new RayTracingTestCase( testCtx,
"shaderRecordExplicitScalarOffset_4",
"Tests usage of various variables inside a shader record block using scalar layout and explicit offset qualifiers",
CaseDef(TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_4) );
auto newTestCaseExplicitScalarOffset_5Ptr = new RayTracingTestCase( testCtx,
"shaderRecordExplicitScalarOffset_5",
"Tests usage of various variables inside a shader record block using scalar layout and explicit offset qualifiers",
CaseDef(TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_5) );
auto newTestCaseExplicitScalarOffset_6Ptr = new RayTracingTestCase( testCtx,
"shaderRecordExplicitScalarOffset_6",
"Tests usage of various variables inside a shader record block using scalar layout and explicit offset qualifiers",
CaseDef(TestType::SHADER_RECORD_BLOCK_EXPLICIT_SCALAR_OFFSET_6) );
auto newTestCaseExplicitSTD430Offset_1Ptr = new RayTracingTestCase( testCtx,
"shaderRecordExplicitSTD430Offset_1",
"Tests usage of various variables inside a shader record block using std430 layout and explicit offset qualifiers",
CaseDef(TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_1) );
auto newTestCaseExplicitSTD430Offset_2Ptr = new RayTracingTestCase( testCtx,
"shaderRecordExplicitSTD430Offset_2",
"Tests usage of various variables inside a shader record block using std430 layout and explicit offset qualifiers",
CaseDef(TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_2) );
auto newTestCaseExplicitSTD430Offset_3Ptr = new RayTracingTestCase( testCtx,
"shaderRecordExplicitSTD430Offset_3",
"Tests usage of various variables inside a shader record block using std430 layout and explicit offset qualifiers",
CaseDef(TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_3) );
auto newTestCaseExplicitSTD430Offset_4Ptr = new RayTracingTestCase( testCtx,
"shaderRecordExplicitSTD430Offset_4",
"Tests usage of various variables inside a shader record block using std430 layout and explicit offset qualifiers",
CaseDef(TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_4) );
auto newTestCaseExplicitSTD430Offset_5Ptr = new RayTracingTestCase( testCtx,
"shaderRecordExplicitSTD430Offset_5",
"Tests usage of various variables inside a shader record block using std430 layout and explicit offset qualifiers",
CaseDef(TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_5) );
auto newTestCaseExplicitSTD430Offset_6Ptr = new RayTracingTestCase( testCtx,
"shaderRecordExplicitSTD430Offset_6",
"Tests usage of various variables inside a shader record block using std430 layout and explicit offset qualifiers",
CaseDef(TestType::SHADER_RECORD_BLOCK_EXPLICIT_STD430_OFFSET_6) );
miscGroupPtr->addChild(newTestCaseSTD430_1Ptr);
miscGroupPtr->addChild(newTestCaseSTD430_2Ptr);
miscGroupPtr->addChild(newTestCaseSTD430_3Ptr);
miscGroupPtr->addChild(newTestCaseSTD430_4Ptr);
miscGroupPtr->addChild(newTestCaseSTD430_5Ptr);
miscGroupPtr->addChild(newTestCaseSTD430_6Ptr);
miscGroupPtr->addChild(newTestCaseScalar_1Ptr);
miscGroupPtr->addChild(newTestCaseScalar_2Ptr);
miscGroupPtr->addChild(newTestCaseScalar_3Ptr);
miscGroupPtr->addChild(newTestCaseScalar_4Ptr);
miscGroupPtr->addChild(newTestCaseScalar_5Ptr);
miscGroupPtr->addChild(newTestCaseScalar_6Ptr);
miscGroupPtr->addChild(newTestCaseExplicitScalarOffset_1Ptr);
miscGroupPtr->addChild(newTestCaseExplicitScalarOffset_2Ptr);
miscGroupPtr->addChild(newTestCaseExplicitScalarOffset_3Ptr);
miscGroupPtr->addChild(newTestCaseExplicitScalarOffset_4Ptr);
miscGroupPtr->addChild(newTestCaseExplicitScalarOffset_5Ptr);
miscGroupPtr->addChild(newTestCaseExplicitScalarOffset_6Ptr);
miscGroupPtr->addChild(newTestCaseExplicitSTD430Offset_1Ptr);
miscGroupPtr->addChild(newTestCaseExplicitSTD430Offset_2Ptr);
miscGroupPtr->addChild(newTestCaseExplicitSTD430Offset_3Ptr);
miscGroupPtr->addChild(newTestCaseExplicitSTD430Offset_4Ptr);
miscGroupPtr->addChild(newTestCaseExplicitSTD430Offset_5Ptr);
miscGroupPtr->addChild(newTestCaseExplicitSTD430Offset_6Ptr);
}
for (auto currentGeometryType = GeometryType::FIRST; currentGeometryType != GeometryType::COUNT; currentGeometryType = static_cast<GeometryType>(static_cast<deUint32>(currentGeometryType) + 1) )
{
const std::string newTestCaseName = "recursiveTraces_" + de::toString(getSuffixForGeometryType(currentGeometryType) ) + "_";
// 0 recursion levels.
{
auto newTestCasePtr = new RayTracingTestCase( testCtx,
(newTestCaseName + "0").data(),
"Verifies that relevant shader stages can correctly read large ray payloads provided by raygen shader stage.",
CaseDef{TestType::RECURSIVE_TRACES_0, currentGeometryType, AccelerationStructureLayout::ONE_TL_ONE_BL_ONE_GEOMETRY});
miscGroupPtr->addChild(newTestCasePtr);
}
// TODO: for (deUint32 nLevels = 1; nLevels <= 29; ++nLevels)
for (deUint32 nLevels = 1; nLevels <= 15; ++nLevels)
{
auto newTestCasePtr = new RayTracingTestCase( testCtx,
(newTestCaseName + de::toString(nLevels) ).data(),
"Verifies that relevant shader stages can correctly read large ray payloads provided by raygen shader stage.",
CaseDef{static_cast<TestType>(static_cast<deUint32>(TestType::RECURSIVE_TRACES_1) + (nLevels - 1) ), currentGeometryType, AccelerationStructureLayout::ONE_TL_ONE_BL_ONE_GEOMETRY});
miscGroupPtr->addChild(newTestCasePtr);
}
}
{
auto newTestCase1Ptr = new RayTracingTestCase( testCtx,
"OpIgnoreIntersectionKHR_AnyHitStatically",
"Verifies that OpIgnoreIntersectionKHR works as per spec (static invocations).",
CaseDef{static_cast<TestType>(static_cast<deUint32>(TestType::IGNORE_ANY_HIT_STATICALLY) ), GeometryType::TRIANGLES, AccelerationStructureLayout::COUNT});
auto newTestCase2Ptr = new RayTracingTestCase( testCtx,
"OpIgnoreIntersectionKHR_AnyHitDynamically",
"Verifies that OpIgnoreIntersectionKHR works as per spec (dynamic invocations).",
CaseDef{static_cast<TestType>(static_cast<deUint32>(TestType::IGNORE_ANY_HIT_DYNAMICALLY) ), GeometryType::TRIANGLES, AccelerationStructureLayout::COUNT});
auto newTestCase3Ptr = new RayTracingTestCase( testCtx,
"OpTerminateRayKHR_AnyHitStatically",
"Verifies that OpTerminateRayKHR works as per spec (static invocations).",
CaseDef{static_cast<TestType>(static_cast<deUint32>(TestType::TERMINATE_ANY_HIT_STATICALLY) ), GeometryType::TRIANGLES, AccelerationStructureLayout::COUNT});
auto newTestCase4Ptr = new RayTracingTestCase( testCtx,
"OpTerminateRayKHR_AnyHitDynamically",
"Verifies that OpTerminateRayKHR works as per spec (dynamic invocations).",
CaseDef{static_cast<TestType>(static_cast<deUint32>(TestType::TERMINATE_ANY_HIT_DYNAMICALLY) ), GeometryType::TRIANGLES, AccelerationStructureLayout::COUNT});
auto newTestCase5Ptr = new RayTracingTestCase( testCtx,
"OpTerminateRayKHR_IntersectionStatically",
"Verifies that OpTerminateRayKHR works as per spec (static invocations).",
CaseDef{static_cast<TestType>(static_cast<deUint32>(TestType::TERMINATE_INTERSECTION_STATICALLY) ), GeometryType::AABB, AccelerationStructureLayout::COUNT});
auto newTestCase6Ptr = new RayTracingTestCase( testCtx,
"OpTerminateRayKHR_IntersectionDynamically",
"Verifies that OpTerminateRayKHR works as per spec (dynamic invocations).",
CaseDef{static_cast<TestType>(static_cast<deUint32>(TestType::TERMINATE_INTERSECTION_DYNAMICALLY) ), GeometryType::AABB, AccelerationStructureLayout::COUNT});
miscGroupPtr->addChild(newTestCase1Ptr);
miscGroupPtr->addChild(newTestCase2Ptr);
miscGroupPtr->addChild(newTestCase3Ptr);
miscGroupPtr->addChild(newTestCase4Ptr);
miscGroupPtr->addChild(newTestCase5Ptr);
miscGroupPtr->addChild(newTestCase6Ptr);
}
{
addFunctionCaseWithPrograms(miscGroupPtr.get(), "null_miss", "", nullMissSupport, nullMissPrograms, nullMissInstance);
}
return miscGroupPtr.release();
}
} // RayTracing
} // vkt