blob: 2491f45dfa982f7fcee5aaabbe127b78c8acce48 [file] [log] [blame]
/*------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2021 The Khronos Group Inc.
* Copyright (c) 2021 Valve Corporation.
*
* 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 Dynamic State tests mixing it with compute and transfer.
*//*--------------------------------------------------------------------*/
#include "vktDynamicStateComputeTests.hpp"
#include "vktCustomInstancesDevices.hpp"
#include "vkBufferWithMemory.hpp"
#include "vkObjUtil.hpp"
#include "vkCmdUtil.hpp"
#include "vkBarrierUtil.hpp"
#include "vkBuilderUtil.hpp"
#include "vkTypeUtil.hpp"
#include "tcuCommandLine.hpp"
#include "tcuVector.hpp"
#include <vector>
#include <string>
#include <functional>
#include <map>
#include <sstream>
#include <cstring>
#include <iterator>
#include <numeric>
#include <memory>
namespace vkt
{
namespace DynamicState
{
namespace
{
using namespace vk;
// Additional objects needed to set a given dynamic state that need to exist beyond the state-setting call. Empty by default.
struct DynamicStateData
{
virtual ~DynamicStateData() {}
};
// A vertex buffer and graphics pipeline are needed for vkCmdBindVertexBuffers2EXT().
struct BindVertexBuffersData : public DynamicStateData
{
private:
using BufferPtr = de::MovePtr<BufferWithMemory>;
using RenderPassPtr = Move<VkRenderPass>;
using LayoutPtr = Move<VkPipelineLayout>;
using ModulePtr = Move<VkShaderModule>;
using PipelinePtr = Move<VkPipeline>;
static constexpr deUint32 kWidth = 16u;
static constexpr deUint32 kHeight = 16u;
VkExtent3D getExtent (void)
{
return makeExtent3D(kWidth, kHeight, 1u);
}
public:
BindVertexBuffersData(Context& ctx, VkDevice device)
: m_vertexBuffer ()
, m_dataSize (0u)
, m_vertexBufferSize (0ull)
, m_renderPass ()
, m_pipelineLayout ()
, m_vertexShader ()
, m_graphicsPipeline ()
{
const auto& vki = ctx.getInstanceInterface();
const auto phyDev = ctx.getPhysicalDevice();
const auto& vkd = ctx.getDeviceInterface();
auto& alloc = ctx.getDefaultAllocator();
// Vertex buffer.
tcu::Vec4 vertex (0.f, 0.f, 0.f, 1.f);
m_dataSize = sizeof(vertex);
m_vertexBufferSize = de::roundUp(static_cast<VkDeviceSize>(m_dataSize), getPhysicalDeviceProperties(vki, phyDev).limits.nonCoherentAtomSize);
const auto bufferInfo = makeBufferCreateInfo(m_vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
m_vertexBuffer = BufferPtr(new BufferWithMemory(vkd, device, alloc, bufferInfo, MemoryRequirement::HostVisible));
auto& bufferAlloc = m_vertexBuffer->getAllocation();
deMemcpy(bufferAlloc.getHostPtr(), &vertex, m_dataSize);
flushAlloc(vkd, device, bufferAlloc);
// Empty render pass.
m_renderPass = makeRenderPass(vkd, device);
// Empty pipeline layout.
m_pipelineLayout = makePipelineLayout(vkd, device);
// Passthrough vertex shader.
m_vertexShader = createShaderModule(vkd, device, ctx.getBinaryCollection().get("vert"), 0u);
const auto extent = getExtent();
const std::vector<VkViewport> viewports (1, makeViewport(extent));
const std::vector<VkRect2D> scissors (1, makeRect2D(extent));
const VkDynamicState state = VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT;
const VkPipelineDynamicStateCreateInfo dynamicStateInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
nullptr, // const void* pNext;
0u, // VkPipelineDynamicStateCreateFlags flags;
1u, // deUint32 dynamicStateCount;
&state, // const VkDynamicState* pDynamicStates;
};
// Graphics pipeline.
m_graphicsPipeline = makeGraphicsPipeline(vkd, device, m_pipelineLayout.get(),
m_vertexShader.get(), DE_NULL, DE_NULL, DE_NULL, DE_NULL,
m_renderPass.get(), viewports, scissors, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0u, 0u,
nullptr, nullptr, nullptr, nullptr, nullptr, &dynamicStateInfo);
}
const BufferWithMemory* getVertexBuffer () const
{
return m_vertexBuffer.get();
}
size_t getDataSize () const
{
return m_dataSize;
}
VkPipeline getPipeline () const
{
return m_graphicsPipeline.get();
}
virtual ~BindVertexBuffersData() {}
private:
BufferPtr m_vertexBuffer;
size_t m_dataSize;
VkDeviceSize m_vertexBufferSize;
RenderPassPtr m_renderPass;
LayoutPtr m_pipelineLayout;
ModulePtr m_vertexShader;
PipelinePtr m_graphicsPipeline;
};
// Function that records a state-setting command in the given command buffer.
using RecordStateFunction = std::function<void(const DeviceInterface*, VkCommandBuffer, const DynamicStateData*)>;
// State-setting functions
void setViewport (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
{
const VkViewport viewport =
{
0.0f, // float x;
0.0f, // float y;
1.0f, // float width;
1.0f, // float height;
0.0f, // float minDepth;
1.0f, // float maxDepth;
};
vkd->cmdSetViewport(cmdBuffer, 0u, 1u, &viewport);
}
void setScissor (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
{
const VkRect2D scissor =
{
{ 0, 0 }, // VkOffset2D offset;
{ 1u, 1u }, // VkExtent2D extent;
};
vkd->cmdSetScissor(cmdBuffer, 0u, 1u, &scissor);
}
void setLineWidth (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
{
vkd->cmdSetLineWidth(cmdBuffer, 1.0f);
}
void setDepthBias (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
{
vkd->cmdSetDepthBias(cmdBuffer, 0.0f, 0.0f, 0.0f);
}
void setBlendConstants (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
{
const float blendConstants[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
vkd->cmdSetBlendConstants(cmdBuffer, blendConstants);
}
void setDepthBounds (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
{
vkd->cmdSetDepthBounds(cmdBuffer, 0.0f, 1.0f);
}
void setStencilCompareMask (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
{
vkd->cmdSetStencilCompareMask(cmdBuffer, VK_STENCIL_FACE_FRONT_AND_BACK, 0xFFu);
}
void setStencilWriteMask (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
{
vkd->cmdSetStencilWriteMask(cmdBuffer, VK_STENCIL_FACE_FRONT_AND_BACK, 0xFFu);
}
void setStencilReference (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
{
vkd->cmdSetStencilReference(cmdBuffer, VK_STENCIL_FACE_FRONT_AND_BACK, 0xFFu);
}
void setDiscardRectangle (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
{
const VkRect2D rectangle =
{
{ 0, 0 }, // VkOffset2D offset;
{ 1u, 1u }, // VkExtent2D extent;
};
vkd->cmdSetDiscardRectangleEXT(cmdBuffer, 0u, 1u, &rectangle);
}
void setSampleLocations (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
{
const VkSampleLocationEXT locations[] =
{
{ 0.5f, 0.5f },
{ 0.5f, 1.5f },
{ 1.5f, 0.5f },
{ 1.5f, 1.5f },
};
const VkSampleLocationsInfoEXT info =
{
VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT, // VkStructureType sType;
nullptr, // const void* pNext;
VK_SAMPLE_COUNT_4_BIT, // VkSampleCountFlagBits sampleLocationsPerPixel;
{ 1u, 1u }, // VkExtent2D sampleLocationGridSize;
4u, // deUint32 sampleLocationsCount;
locations, // const VkSampleLocationEXT* pSampleLocations;
};
vkd->cmdSetSampleLocationsEXT(cmdBuffer, &info);
}
#ifndef CTS_USES_VULKANSC
void setRTPipelineStatckSize (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
{
vkd->cmdSetRayTracingPipelineStackSizeKHR(cmdBuffer, 4096u);
}
#endif // CTS_USES_VULKANSC
void setFragmentShadingRage (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
{
const VkExtent2D fragmentSize = { 1u, 1u };
const VkFragmentShadingRateCombinerOpKHR combinerOps[2] =
{
VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR,
VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR,
};
vkd->cmdSetFragmentShadingRateKHR(cmdBuffer, &fragmentSize, combinerOps);
}
void setLineStipple (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
{
vkd->cmdSetLineStippleEXT(cmdBuffer, 1u, 1u);
}
void setCullMode (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
{
#ifndef CTS_USES_VULKANSC
vkd->cmdSetCullMode(cmdBuffer, VK_CULL_MODE_FRONT_AND_BACK);
#else
vkd->cmdSetCullModeEXT(cmdBuffer, VK_CULL_MODE_FRONT_AND_BACK);
#endif // CTS_USES_VULKANSC
}
void setFrontFace (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
{
#ifndef CTS_USES_VULKANSC
vkd->cmdSetFrontFace(cmdBuffer, VK_FRONT_FACE_COUNTER_CLOCKWISE);
#else
vkd->cmdSetFrontFaceEXT(cmdBuffer, VK_FRONT_FACE_COUNTER_CLOCKWISE);
#endif // CTS_USES_VULKANSC
}
void setPrimitiveTopology (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
{
#ifndef CTS_USES_VULKANSC
vkd->cmdSetPrimitiveTopology(cmdBuffer, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
#else
vkd->cmdSetPrimitiveTopologyEXT(cmdBuffer, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
#endif // CTS_USES_VULKANSC
}
void setViewportWithCount (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
{
const VkViewport viewport =
{
0.0f, // float x;
0.0f, // float y;
1.0f, // float width;
1.0f, // float height;
0.0f, // float minDepth;
1.0f, // float maxDepth;
};
#ifndef CTS_USES_VULKANSC
vkd->cmdSetViewportWithCount(cmdBuffer, 1u, &viewport);
#else
vkd->cmdSetViewportWithCountEXT(cmdBuffer, 1u, &viewport);
#endif // CTS_USES_VULKANSC
}
void setScissorWithCount (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
{
const VkRect2D scissor =
{
{ 0, 0 }, // VkOffset2D offset;
{ 1u, 1u }, // VkExtent2D extent;
};
#ifndef CTS_USES_VULKANSC
vkd->cmdSetScissorWithCount(cmdBuffer, 1u, &scissor);
#else
vkd->cmdSetScissorWithCountEXT(cmdBuffer, 1u, &scissor);
#endif // CTS_USES_VULKANSC
}
void bindVertexBuffers (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData* data)
{
const auto bindData = dynamic_cast<const BindVertexBuffersData*>(data);
DE_ASSERT(bindData != nullptr);
const auto vertexBuffer = bindData->getVertexBuffer();
const auto dataSize = static_cast<VkDeviceSize>(bindData->getDataSize());
const auto bufferOffset = vertexBuffer->getAllocation().getOffset();
const auto stride = static_cast<VkDeviceSize>(0);
const auto pipeline = bindData->getPipeline();
vkd->cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
#ifndef CTS_USES_VULKANSC
vkd->cmdBindVertexBuffers2(cmdBuffer, 0u, 1u, &vertexBuffer->get(), &bufferOffset, &dataSize, &stride);
#else
vkd->cmdBindVertexBuffers2EXT(cmdBuffer, 0u, 1u, &vertexBuffer->get(), &bufferOffset, &dataSize, &stride);
#endif // CTS_USES_VULKANSC
}
void setDepthTestEnable (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
{
#ifndef CTS_USES_VULKANSC
vkd->cmdSetDepthTestEnable(cmdBuffer, VK_TRUE);
#else
vkd->cmdSetDepthTestEnableEXT(cmdBuffer, VK_TRUE);
#endif // CTS_USES_VULKANSC
}
void setDepthWriteEnable (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
{
#ifndef CTS_USES_VULKANSC
vkd->cmdSetDepthWriteEnable(cmdBuffer, VK_TRUE);
#else
vkd->cmdSetDepthWriteEnableEXT(cmdBuffer, VK_TRUE);
#endif // CTS_USES_VULKANSC
}
void setDepthCompareOp (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
{
#ifndef CTS_USES_VULKANSC
vkd->cmdSetDepthCompareOp(cmdBuffer, VK_COMPARE_OP_LESS);
#else
vkd->cmdSetDepthCompareOpEXT(cmdBuffer, VK_COMPARE_OP_LESS);
#endif // CTS_USES_VULKANSC
}
void setDepthBoundsTestEnable (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
{
#ifndef CTS_USES_VULKANSC
vkd->cmdSetDepthBoundsTestEnable(cmdBuffer, VK_TRUE);
#else
vkd->cmdSetDepthBoundsTestEnableEXT(cmdBuffer, VK_TRUE);
#endif // CTS_USES_VULKANSC
}
void setStencilTestEnable (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
{
#ifndef CTS_USES_VULKANSC
vkd->cmdSetStencilTestEnable(cmdBuffer, VK_TRUE);
#else
vkd->cmdSetStencilTestEnableEXT(cmdBuffer, VK_TRUE);
#endif // CTS_USES_VULKANSC
}
void setStencilOp (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
{
#ifndef CTS_USES_VULKANSC
vkd->cmdSetStencilOp(cmdBuffer, VK_STENCIL_FACE_FRONT_AND_BACK, VK_STENCIL_OP_ZERO, VK_STENCIL_OP_INCREMENT_AND_CLAMP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_ALWAYS);
#else
vkd->cmdSetStencilOpEXT(cmdBuffer, VK_STENCIL_FACE_FRONT_AND_BACK, VK_STENCIL_OP_ZERO, VK_STENCIL_OP_INCREMENT_AND_CLAMP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_ALWAYS);
#endif // CTS_USES_VULKANSC
}
#ifndef CTS_USES_VULKANSC
void setViewportWScaling (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
{
const VkViewportWScalingNV viewport =
{
1.0f, // float xcoeff;
1.0f, // float ycoeff;
};
vkd->cmdSetViewportWScalingNV(cmdBuffer, 0u, 1u, &viewport);
}
void setViewportShadingRatePalette (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
{
const VkShadingRatePaletteEntryNV entry = VK_SHADING_RATE_PALETTE_ENTRY_NO_INVOCATIONS_NV;
const VkShadingRatePaletteNV palette =
{
1u, // deUint32 shadingRatePaletteEntryCount;
&entry, // const VkShadingRatePaletteEntryNV* pShadingRatePaletteEntries;
};
vkd->cmdSetViewportShadingRatePaletteNV(cmdBuffer, 0u, 1u, &palette);
}
void setCoarseSamplingOrder (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
{
const VkCoarseSampleLocationNV locations[2] =
{
{
0u, // deUint32 pixelX;
0u, // deUint32 pixelY;
0u, // deUint32 sample;
},
{
0u, // deUint32 pixelX;
1u, // deUint32 pixelY;
1u, // deUint32 sample;
},
};
const VkCoarseSampleOrderCustomNV order =
{
VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV, // VkShadingRatePaletteEntryNV shadingRate;
1u, // deUint32 sampleCount;
2u, // deUint32 sampleLocationCount;
locations // const VkCoarseSampleLocationNV* pSampleLocations;
};
vkd->cmdSetCoarseSampleOrderNV(cmdBuffer, VK_COARSE_SAMPLE_ORDER_TYPE_CUSTOM_NV, 1u, &order);
}
void setExclusiveScissor (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
{
const VkRect2D scissor =
{
{ 0, 0 }, // VkOffset2D offset;
{ 1u, 1u }, // VkExtent2D extent;
};
vkd->cmdSetExclusiveScissorNV(cmdBuffer, 0u, 1u, &scissor);
}
#endif // CTS_USES_VULKANSC
const VkDynamicState dynamicStateList[] =
{
VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR,
VK_DYNAMIC_STATE_LINE_WIDTH,
VK_DYNAMIC_STATE_DEPTH_BIAS,
VK_DYNAMIC_STATE_BLEND_CONSTANTS,
VK_DYNAMIC_STATE_DEPTH_BOUNDS,
VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK,
VK_DYNAMIC_STATE_STENCIL_WRITE_MASK,
VK_DYNAMIC_STATE_STENCIL_REFERENCE,
VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT,
VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT,
#ifndef CTS_USES_VULKANSC
VK_DYNAMIC_STATE_RAY_TRACING_PIPELINE_STACK_SIZE_KHR,
#endif // CTS_USES_VULKANSC
VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR,
VK_DYNAMIC_STATE_LINE_STIPPLE_EXT,
VK_DYNAMIC_STATE_CULL_MODE_EXT,
VK_DYNAMIC_STATE_FRONT_FACE_EXT,
VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT,
VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT,
VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT,
VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT,
VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT,
VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT,
VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT,
VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT,
VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT,
VK_DYNAMIC_STATE_STENCIL_OP_EXT,
#ifndef CTS_USES_VULKANSC
VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV,
VK_DYNAMIC_STATE_VIEWPORT_SHADING_RATE_PALETTE_NV,
VK_DYNAMIC_STATE_VIEWPORT_COARSE_SAMPLE_ORDER_NV,
VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_NV,
#endif // CTS_USES_VULKANSC
};
// Information about a dynamic state.
struct StateInfo
{
std::vector<std::string> requirements; // List of required functionalities.
RecordStateFunction recorder; // Function that records the state to the command buffer being used.
};
// Returns the state info for a given dynamic state.
const StateInfo& getDynamicStateInfo (VkDynamicState state)
{
// Maps a given state to its state info structure.
using StateInfoMap = std::map<VkDynamicState, StateInfo>;
static const StateInfoMap result =
{
{ VK_DYNAMIC_STATE_VIEWPORT, { {}, setViewport } },
{ VK_DYNAMIC_STATE_SCISSOR, { {}, setScissor } },
{ VK_DYNAMIC_STATE_LINE_WIDTH, { {}, setLineWidth } },
{ VK_DYNAMIC_STATE_DEPTH_BIAS, { {}, setDepthBias } },
{ VK_DYNAMIC_STATE_BLEND_CONSTANTS, { {}, setBlendConstants } },
{ VK_DYNAMIC_STATE_DEPTH_BOUNDS, { {}, setDepthBounds } },
{ VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, { {}, setStencilCompareMask } },
{ VK_DYNAMIC_STATE_STENCIL_WRITE_MASK, { {}, setStencilWriteMask } },
{ VK_DYNAMIC_STATE_STENCIL_REFERENCE, { {}, setStencilReference } },
{ VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT, { { "VK_EXT_discard_rectangles" }, setDiscardRectangle } },
{ VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT, { { "VK_EXT_sample_locations" }, setSampleLocations } },
#ifndef CTS_USES_VULKANSC
{ VK_DYNAMIC_STATE_RAY_TRACING_PIPELINE_STACK_SIZE_KHR, { { "VK_KHR_ray_tracing_pipeline" }, setRTPipelineStatckSize } },
#endif // CTS_USES_VULKANSC
{ VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR, { { "VK_KHR_fragment_shading_rate" }, setFragmentShadingRage } },
{ VK_DYNAMIC_STATE_LINE_STIPPLE_EXT, { { "VK_EXT_line_rasterization" }, setLineStipple } },
{ VK_DYNAMIC_STATE_CULL_MODE_EXT, { { "VK_EXT_extended_dynamic_state" }, setCullMode } },
{ VK_DYNAMIC_STATE_FRONT_FACE_EXT, { { "VK_EXT_extended_dynamic_state" }, setFrontFace } },
{ VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT, { { "VK_EXT_extended_dynamic_state" }, setPrimitiveTopology } },
{ VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT, { { "VK_EXT_extended_dynamic_state" }, setViewportWithCount } },
{ VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT, { { "VK_EXT_extended_dynamic_state" }, setScissorWithCount } },
{ VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT, { { "VK_EXT_extended_dynamic_state" }, bindVertexBuffers } },
{ VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT, { { "VK_EXT_extended_dynamic_state" }, setDepthTestEnable } },
{ VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT, { { "VK_EXT_extended_dynamic_state" }, setDepthWriteEnable } },
{ VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT, { { "VK_EXT_extended_dynamic_state" }, setDepthCompareOp } },
{ VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT, { { "VK_EXT_extended_dynamic_state" }, setDepthBoundsTestEnable } },
{ VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT, { { "VK_EXT_extended_dynamic_state" }, setStencilTestEnable } },
{ VK_DYNAMIC_STATE_STENCIL_OP_EXT, { { "VK_EXT_extended_dynamic_state" }, setStencilOp } },
#ifndef CTS_USES_VULKANSC
{ VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV, { { "VK_NV_clip_space_w_scaling" }, setViewportWScaling } },
{ VK_DYNAMIC_STATE_VIEWPORT_SHADING_RATE_PALETTE_NV, { { "VK_NV_shading_rate_image"}, setViewportShadingRatePalette } },
{ VK_DYNAMIC_STATE_VIEWPORT_COARSE_SAMPLE_ORDER_NV, { { "VK_NV_shading_rate_image"}, setCoarseSamplingOrder } },
{ VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_NV, { { "VK_NV_scissor_exclusive"}, setExclusiveScissor } },
#endif // CTS_USES_VULKANSC
};
const auto itr = result.find(state);
DE_ASSERT(itr != result.end());
return itr->second;
}
// Device helper: this is needed in some tests when we create custom devices.
class DeviceHelper
{
public:
virtual ~DeviceHelper () {}
virtual const DeviceInterface& getDeviceInterface (void) const = 0;
virtual VkDevice getDevice (void) const = 0;
virtual uint32_t getQueueFamilyIndex (void) const = 0;
virtual VkQueue getQueue (void) const = 0;
virtual Allocator& getAllocator (void) const = 0;
};
// This one just reuses the default device from the context.
class ContextDeviceHelper : public DeviceHelper
{
public:
ContextDeviceHelper (Context& context)
: m_deviceInterface (context.getDeviceInterface())
, m_device (context.getDevice())
, m_queueFamilyIndex (context.getUniversalQueueFamilyIndex())
, m_queue (context.getUniversalQueue())
, m_allocator (context.getDefaultAllocator())
{}
virtual ~ContextDeviceHelper () {}
const DeviceInterface& getDeviceInterface (void) const override { return m_deviceInterface; }
VkDevice getDevice (void) const override { return m_device; }
uint32_t getQueueFamilyIndex (void) const override { return m_queueFamilyIndex; }
VkQueue getQueue (void) const override { return m_queue; }
Allocator& getAllocator (void) const override { return m_allocator; }
protected:
const DeviceInterface& m_deviceInterface;
const VkDevice m_device;
const uint32_t m_queueFamilyIndex;
const VkQueue m_queue;
Allocator& m_allocator;
};
// This one creates a new device with VK_NV_shading_rate_image.
class ShadingRateImageDeviceHelper : public DeviceHelper
{
public:
ShadingRateImageDeviceHelper (Context& context)
{
const auto& vkp = context.getPlatformInterface();
const auto& vki = context.getInstanceInterface();
const auto instance = context.getInstance();
const auto physicalDevice = context.getPhysicalDevice();
const auto queuePriority = 1.0f;
// Queue index first.
m_queueFamilyIndex = context.getUniversalQueueFamilyIndex();
// Create a universal queue that supports graphics and compute.
const VkDeviceQueueCreateInfo queueParams =
{
VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkDeviceQueueCreateFlags flags;
m_queueFamilyIndex, // deUint32 queueFamilyIndex;
1u, // deUint32 queueCount;
&queuePriority // const float* pQueuePriorities;
};
const char* extensions[] =
{
"VK_NV_shading_rate_image",
};
#ifndef CTS_USES_VULKANSC
VkPhysicalDeviceShadingRateImageFeaturesNV shadingRateImageFeatures = initVulkanStructure();
VkPhysicalDeviceFeatures2 features2 = initVulkanStructure(&shadingRateImageFeatures);
vki.getPhysicalDeviceFeatures2(physicalDevice, &features2);
#endif // CTS_USES_VULKANSC
const VkDeviceCreateInfo deviceCreateInfo =
{
VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, //sType;
#ifndef CTS_USES_VULKANSC
&features2, //pNext;
#else
DE_NULL,
#endif // CTS_USES_VULKANSC
0u, //flags
1u, //queueRecordCount;
&queueParams, //pRequestedQueues;
0u, //layerCount;
nullptr, //ppEnabledLayerNames;
static_cast<uint32_t>(de::arrayLength(extensions)), // deUint32 enabledExtensionCount;
extensions, // const char* const* ppEnabledExtensionNames;
nullptr, //pEnabledFeatures;
};
m_device = createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(), vkp, instance, vki, physicalDevice, &deviceCreateInfo);
m_vkd .reset(new DeviceDriver(vkp, instance, m_device.get()));
m_queue = getDeviceQueue(*m_vkd, *m_device, m_queueFamilyIndex, 0u);
m_allocator .reset(new SimpleAllocator(*m_vkd, m_device.get(), getPhysicalDeviceMemoryProperties(vki, physicalDevice)));
}
virtual ~ShadingRateImageDeviceHelper () {}
const DeviceInterface& getDeviceInterface (void) const override { return *m_vkd; }
VkDevice getDevice (void) const override { return m_device.get(); }
uint32_t getQueueFamilyIndex (void) const override { return m_queueFamilyIndex; }
VkQueue getQueue (void) const override { return m_queue; }
Allocator& getAllocator (void) const override { return *m_allocator; }
protected:
Move<VkDevice> m_device;
std::unique_ptr<DeviceDriver> m_vkd;
deUint32 m_queueFamilyIndex;
VkQueue m_queue;
std::unique_ptr<SimpleAllocator> m_allocator;
};
std::unique_ptr<DeviceHelper> g_shadingRateDeviceHelper;
std::unique_ptr<DeviceHelper> g_contextDeviceHelper;
DeviceHelper& getDeviceHelper(Context& context, VkDynamicState dynamicState)
{
const auto& stateInfo = getDynamicStateInfo(dynamicState);
if (de::contains(stateInfo.requirements.begin(), stateInfo.requirements.end(), "VK_NV_shading_rate_image"))
{
if (!g_shadingRateDeviceHelper)
g_shadingRateDeviceHelper.reset(new ShadingRateImageDeviceHelper(context));
return *g_shadingRateDeviceHelper;
}
if (!g_contextDeviceHelper)
g_contextDeviceHelper.reset(new ContextDeviceHelper(context));
return *g_contextDeviceHelper;
}
// Returns the set of auxiliary data needed to set a given state.
de::MovePtr<DynamicStateData> getDynamicStateData (Context& ctx, VkDevice device, VkDynamicState state)
{
// Create vertex buffer for VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT.
if (state == VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT)
return de::MovePtr<DynamicStateData>(new BindVertexBuffersData(ctx, device));
// null pointer normally.
return de::MovePtr<DynamicStateData>();
}
enum class OperType { COMPUTE = 0, TRANSFER };
enum class WhenToSet { BEFORE = 0, AFTER };
// Set dynamic state before or after attempting to run a compute or transfer operation.
struct TestParams
{
OperType operationType;
WhenToSet whenToSet;
std::vector<VkDynamicState> states;
};
class DynamicStateComputeCase : public vkt::TestCase
{
public:
DynamicStateComputeCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params);
virtual ~DynamicStateComputeCase (void) {}
virtual void checkSupport (Context& context) const;
virtual void initPrograms (vk::SourceCollections& programCollection) const;
virtual TestInstance* createInstance (Context& context) const;
protected:
TestParams m_params;
};
class DynamicStateComputeInstance : public vkt::TestInstance
{
public:
DynamicStateComputeInstance (Context& context, const TestParams& params);
virtual ~DynamicStateComputeInstance (void) {}
virtual tcu::TestStatus iterate (void);
protected:
tcu::TestStatus iterateTransfer (void);
tcu::TestStatus iterateCompute (void);
TestParams m_params;
};
DynamicStateComputeCase::DynamicStateComputeCase(tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params)
: vkt::TestCase (testCtx, name, description)
, m_params (params)
{}
DynamicStateComputeInstance::DynamicStateComputeInstance (Context& context, const TestParams& params)
: vkt::TestInstance (context)
, m_params (params)
{}
void DynamicStateComputeCase::checkSupport (Context& context) const
{
// Check required functionalities.
for (const auto& state : m_params.states)
{
const auto stateInfo = getDynamicStateInfo(state);
for (const auto& functionality : stateInfo.requirements)
context.requireDeviceFunctionality(functionality);
}
}
void DynamicStateComputeCase::initPrograms (vk::SourceCollections& programCollection) const
{
if (m_params.operationType == OperType::COMPUTE)
{
std::ostringstream comp;
comp
<< "#version 450\n"
<< "\n"
<< "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
<< "\n"
<< "layout (push_constant, std430) uniform PushConstants {\n"
<< " uint valueIndex;\n"
<< "} pc;\n"
<< "\n"
<< "layout (set=0, binding=0, std430) buffer OutputBlock {\n"
<< " uint value[];\n"
<< "} ob;\n"
<< "\n"
<< "void main ()\n"
<< "{\n"
<< " ob.value[pc.valueIndex] = 1u;\n"
<< "}\n"
;
programCollection.glslSources.add("comp") << glu::ComputeSource(comp.str());
}
if (de::contains(begin(m_params.states), end(m_params.states), VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT))
{
// Passthrough vertex shader for stand-in graphics pipeline.
std::ostringstream vert;
vert
<< "#version 450\n"
<< "layout (location=0) in vec4 inVertex;\n"
<< "void main() {\n"
<< " gl_Position = inVertex;\n"
<< "}\n"
;
programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
}
}
vkt::TestInstance* DynamicStateComputeCase::createInstance (Context& context) const
{
return new DynamicStateComputeInstance(context, m_params);
}
tcu::TestStatus DynamicStateComputeInstance::iterate (void)
{
if (m_params.operationType == OperType::COMPUTE)
return iterateCompute();
else
return iterateTransfer();
}
void fillBuffer(const DeviceInterface& vkd, VkDevice device, BufferWithMemory& buffer, const std::vector<deUint32> &values)
{
auto& alloc = buffer.getAllocation();
deMemcpy(alloc.getHostPtr(), values.data(), de::dataSize(values));
flushAlloc(vkd, device, alloc);
}
tcu::TestStatus DynamicStateComputeInstance::iterateTransfer (void)
{
const auto& vki = m_context.getInstanceInterface();
const auto phyDev = m_context.getPhysicalDevice();
auto& devHelper = getDeviceHelper(m_context, m_params.states.at(0));
const auto& vkd = devHelper.getDeviceInterface();
const auto device = devHelper.getDevice();
const auto qIndex = devHelper.getQueueFamilyIndex();
const auto queue = devHelper.getQueue();
auto& alloc = devHelper.getAllocator();
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();
// Prepare two host-visible buffers for a transfer operation, with one element per dynamic state.
const deUint32 seqStart = 1611747605u;
DE_ASSERT(!m_params.states.empty());
std::vector<deUint32> srcValues(m_params.states.size());
const decltype(srcValues) dstValues(srcValues.size(), 0u);
std::iota(begin(srcValues), end(srcValues), seqStart);
const auto elemSize = static_cast<VkDeviceSize>(sizeof(decltype(srcValues)::value_type));
const auto dataSize = static_cast<VkDeviceSize>(de::dataSize(srcValues));
const auto bufferSize = de::roundUp(dataSize, getPhysicalDeviceProperties(vki, phyDev).limits.nonCoherentAtomSize);
const auto srcInfo = makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
const auto dstInfo = makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
BufferWithMemory srcBuffer (vkd, device, alloc, srcInfo, MemoryRequirement::HostVisible);
BufferWithMemory dstBuffer (vkd, device, alloc, dstInfo, MemoryRequirement::HostVisible);
// Fill source and destination buffer.
fillBuffer(vkd, device, srcBuffer, srcValues);
fillBuffer(vkd, device, dstBuffer, dstValues);
beginCommandBuffer(vkd, cmdBuffer);
// We need to preserve dynamic state data until the command buffer has run.
std::vector<de::MovePtr<DynamicStateData>> statesData;
for (size_t stateIdx = 0; stateIdx < m_params.states.size(); ++stateIdx)
{
// Get extra data needed for using the dynamic state.
const auto offset = elemSize * stateIdx;
const auto& state = m_params.states[stateIdx];
const auto stateInfo = getDynamicStateInfo(state);
statesData.push_back(getDynamicStateData(m_context, device, state));
// Record command if before.
if (m_params.whenToSet == WhenToSet::BEFORE)
stateInfo.recorder(&vkd, cmdBuffer, statesData.back().get());
// Transfer op (copy one buffer element per dynamic state).
const VkBufferCopy region = { offset, offset, elemSize };
vkd.cmdCopyBuffer(cmdBuffer, srcBuffer.get(), dstBuffer.get(), 1u, &region);
// Record command if after.
if (m_params.whenToSet == WhenToSet::AFTER)
stateInfo.recorder(&vkd, cmdBuffer, statesData.back().get());
}
const auto barrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &barrier, 0u, nullptr, 0u, nullptr);
endCommandBuffer(vkd, cmdBuffer);
submitCommandsAndWait(vkd, device, queue, cmdBuffer);
// Invalidate alloc and check destination buffer.
auto& dstBufferAlloc = dstBuffer.getAllocation();
invalidateAlloc(vkd, device, dstBufferAlloc);
decltype(srcValues) results (srcValues.size());
deMemcpy(results.data(), dstBufferAlloc.getHostPtr(), de::dataSize(srcValues));
for (size_t valueIdx = 0; valueIdx < srcValues.size(); ++valueIdx)
{
const auto& orig = srcValues[valueIdx];
const auto& res = results[valueIdx];
if (orig != res)
{
std::ostringstream msg;
msg << "Unexpected value found in destination buffer at position " << valueIdx << " (found=" << res << " expected=" << orig << ")";
TCU_FAIL(msg.str());
}
}
return tcu::TestStatus::pass("Pass");
}
tcu::TestStatus DynamicStateComputeInstance::iterateCompute (void)
{
const auto& vki = m_context.getInstanceInterface();
const auto phyDev = m_context.getPhysicalDevice();
auto& devHelper = getDeviceHelper(m_context, m_params.states.at(0));
const auto& vkd = devHelper.getDeviceInterface();
const auto device = devHelper.getDevice();
const auto qIndex = devHelper.getQueueFamilyIndex();
const auto queue = devHelper.getQueue();
auto& alloc = devHelper.getAllocator();
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();
DescriptorSetLayoutBuilder setLayoutBuilder;
setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT);
const auto setLayout = setLayoutBuilder.build(vkd, device);
// Push constants.
const deUint32 pcSize = static_cast<deUint32>(sizeof(deUint32));
const auto pcRange = makePushConstantRange(VK_SHADER_STAGE_COMPUTE_BIT, 0u, pcSize);
// Pipeline.
const VkPipelineLayoutCreateInfo layoutInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
nullptr, // const void* pNext;
0u, // VkPipelineLayoutCreateFlags flags;
1u, // deUint32 setLayoutCount;
&setLayout.get(), // const VkDescriptorSetLayout* pSetLayouts;
1u, // deUint32 pushConstantRangeCount;
&pcRange, // const VkPushConstantRange* pPushConstantRanges;
};
const auto pipelineLayout = createPipelineLayout(vkd, device, &layoutInfo);
const auto shaderModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("comp"), 0u);
const VkPipelineShaderStageCreateInfo shaderStageInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
nullptr, // const void* pNext;
0u, // VkPipelineShaderStageCreateFlags flags;
VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlagBits stage;
shaderModule.get(), // VkShaderModule module;
"main", // const char* pName;
nullptr, // const VkSpecializationInfo* pSpecializationInfo;
};
const VkComputePipelineCreateInfo pipelineInfo =
{
VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType sType;
nullptr, // const void* pNext;
0u, // VkPipelineCreateFlags flags;
shaderStageInfo, // VkPipelineShaderStageCreateInfo stage;
pipelineLayout.get(), // VkPipelineLayout layout;
DE_NULL, // VkPipeline basePipelineHandle;
0, // deInt32 basePipelineIndex;
};
const auto pipeline = createComputePipeline(vkd, device, DE_NULL, &pipelineInfo);
DE_ASSERT(!m_params.states.empty());
// Output buffer with one value per state.
std::vector<deUint32> bufferData (m_params.states.size(), 0u);
const auto dataSize (de::dataSize(bufferData));
const auto outputBufferSize = de::roundUp(static_cast<VkDeviceSize>(dataSize), getPhysicalDeviceProperties(vki, phyDev).limits.nonCoherentAtomSize);
const auto bufferCreateInfo = makeBufferCreateInfo(outputBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
BufferWithMemory outputBuffer (vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible);
auto& outputBufferAlloc = outputBuffer.getAllocation();
auto outputBufferPtr = outputBufferAlloc.getHostPtr();
deMemcpy(outputBufferPtr, bufferData.data(), dataSize);
flushAlloc(vkd, device, outputBufferAlloc);
// Descriptor set.
DescriptorPoolBuilder poolBuilder;
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());
const auto bufferInfo = makeDescriptorBufferInfo(outputBuffer.get(), 0ull, outputBufferSize);
DescriptorSetUpdateBuilder updateBuilder;
updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &bufferInfo);
updateBuilder.update(vkd, device);
// Record and submit.
beginCommandBuffer(vkd, cmdBuffer);
// We need to preserve dynamic state data until the command buffer has run.
std::vector<de::MovePtr<DynamicStateData>> statesData;
for (size_t stateIdx = 0; stateIdx < m_params.states.size(); ++stateIdx)
{
// Objects needed to set the dynamic state.
const auto& state = m_params.states[stateIdx];
const auto stateInfo = getDynamicStateInfo(state);
statesData.push_back(getDynamicStateData(m_context, device, state));
if (m_params.whenToSet == WhenToSet::BEFORE)
stateInfo.recorder(&vkd, cmdBuffer, statesData.back().get());
vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.get());
vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr);
{
// Each state will write to a different buffer position.
const deUint32 pcData = static_cast<deUint32>(stateIdx);
vkd.cmdPushConstants(cmdBuffer, pipelineLayout.get(), VK_SHADER_STAGE_COMPUTE_BIT, 0u, pcSize, &pcData);
}
vkd.cmdDispatch(cmdBuffer, 1u, 1u, 1u);
if (m_params.whenToSet == WhenToSet::AFTER)
stateInfo.recorder(&vkd, cmdBuffer, statesData.back().get());
}
// Barrier to read buffer contents.
const auto barrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &barrier, 0u, nullptr, 0u, nullptr);
endCommandBuffer(vkd, cmdBuffer);
submitCommandsAndWait(vkd, device, queue, cmdBuffer);
// Read and verify buffer contents.
invalidateAlloc(vkd, device, outputBufferAlloc);
deMemcpy(bufferData.data(), outputBufferPtr, dataSize);
for (size_t idx = 0u; idx < bufferData.size(); ++idx)
{
if (bufferData[idx] != 1u)
{
std::ostringstream msg;
msg << "Unexpected value found at buffer position " << idx << ": " << bufferData[idx];
TCU_FAIL(msg.str());
}
}
return tcu::TestStatus::pass("Pass");
}
std::string getDynamicStateBriefName (VkDynamicState state)
{
const auto fullName = de::toString(state);
const auto prefixLen = strlen("VK_DYNAMIC_STATE_");
return de::toLower(fullName.substr(prefixLen));
}
} // anonymous
tcu::TestCaseGroup* createDynamicStateComputeTests (tcu::TestContext& testCtx)
{
using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
GroupPtr mainGroup(new tcu::TestCaseGroup(testCtx, "compute_transfer", "Dynamic state mixed with compute and transfer operations"));
const struct
{
OperType operationType;
const char* name;
} operations[] =
{
{ OperType::COMPUTE, "compute" },
{ OperType::TRANSFER, "transfer" },
};
const struct
{
WhenToSet when;
const char* name;
} moments[] =
{
{ WhenToSet::BEFORE, "before" },
{ WhenToSet::AFTER, "after" },
};
// Tests with a single dynamic state.
{
GroupPtr singleStateGroup(new tcu::TestCaseGroup(testCtx, "single", "Tests using a single dynamic state"));
for (int operIdx = 0; operIdx < DE_LENGTH_OF_ARRAY(operations); ++operIdx)
{
GroupPtr operationGroup(new tcu::TestCaseGroup(testCtx, operations[operIdx].name, ""));
for (int stateIdx = 0; stateIdx < DE_LENGTH_OF_ARRAY(dynamicStateList); ++stateIdx)
{
const auto state = dynamicStateList[stateIdx];
const auto stateName = getDynamicStateBriefName(state);
GroupPtr stateGroup(new tcu::TestCaseGroup(testCtx, stateName.c_str(), ""));
for (int momentIdx = 0; momentIdx < DE_LENGTH_OF_ARRAY(moments); ++momentIdx)
{
const TestParams testParams =
{
operations[operIdx].operationType, // OperType operationType;
moments[momentIdx].when, // WhenToSet whenToSet;
std::vector<VkDynamicState>(1, state), // std::vector<VkDynamicState> state;
};
stateGroup->addChild(new DynamicStateComputeCase(testCtx, moments[momentIdx].name, "", testParams));
}
operationGroup->addChild(stateGroup.release());
}
singleStateGroup->addChild(operationGroup.release());
}
mainGroup->addChild(singleStateGroup.release());
}
// A few tests with several dynamic states.
{
GroupPtr multiStateGroup(new tcu::TestCaseGroup(testCtx, "multi", "Tests using multiple dynamic states"));
for (int operIdx = 0; operIdx < DE_LENGTH_OF_ARRAY(operations); ++operIdx)
{
GroupPtr operationGroup(new tcu::TestCaseGroup(testCtx, operations[operIdx].name, ""));
for (int momentIdx = 0; momentIdx < DE_LENGTH_OF_ARRAY(moments); ++momentIdx)
{
TestParams testParams =
{
operations[operIdx].operationType, // OperType operationType;
moments[momentIdx].when, // WhenToSet whenToSet;
std::vector<VkDynamicState>(), // std::vector<VkDynamicState> states;
};
// Use the basic states so as not to introduce extra requirements.
for (int stateIdx = 0; stateIdx < DE_LENGTH_OF_ARRAY(dynamicStateList); ++stateIdx)
{
testParams.states.push_back(dynamicStateList[stateIdx]);
if (dynamicStateList[stateIdx] == VK_DYNAMIC_STATE_STENCIL_REFERENCE)
break;
}
operationGroup->addChild(new DynamicStateComputeCase(testCtx, moments[momentIdx].name, "", testParams));
}
multiStateGroup->addChild(operationGroup.release());
}
mainGroup->addChild(multiStateGroup.release());
}
return mainGroup.release();
}
void cleanupDevice()
{
g_shadingRateDeviceHelper.reset(nullptr);
g_contextDeviceHelper.reset(nullptr);
}
} // DynamicState
} // vkt