blob: 720cae8446b6dc5de8450ba26778b432004e7177 [file] [log] [blame]
/*------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2021 The Khronos Group Inc.
* Copyright (c) 2021 Valve Corporation.
* Copyright (c) 2023 LunarG, Inc.
* Copyright (c) 2023 Nintendo
*
* 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 = RenderPassWrapper;
using LayoutPtr = Move<VkPipelineLayout>;
using ModulePtr = Move<VkShaderModule>;
using PipelinePtr = Move<VkPipeline>;
static constexpr uint32_t kWidth = 16u;
static constexpr uint32_t kHeight = 16u;
VkExtent3D getExtent(void)
{
return makeExtent3D(kWidth, kHeight, 1u);
}
public:
BindVertexBuffersData(Context &ctx, VkDevice device, PipelineConstructionType pipelineConstructionType)
: 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 = RenderPassWrapper(pipelineConstructionType, 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, // uint32_t dynamicStateCount;
&state, // const VkDynamicState* pDynamicStates;
};
// Graphics pipeline.
m_graphicsPipeline = makeGraphicsPipeline(
vkd, device, m_pipelineLayout.get(), m_vertexShader.get(), VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE,
VK_NULL_HANDLE, 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, // uint32_t 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 *)
{
#ifndef CTS_USES_VULKANSC
vkd->cmdSetLineStipple(cmdBuffer, 1u, 1u);
#else
vkd->cmdSetLineStippleEXT(cmdBuffer, 1u, 1u);
#endif // CTS_USES_VULKANSC
}
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, // uint32_t 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, // uint32_t pixelX;
0u, // uint32_t pixelY;
0u, // uint32_t sample;
},
{
0u, // uint32_t pixelX;
1u, // uint32_t pixelY;
0u, // uint32_t sample;
},
};
const VkCoarseSampleOrderCustomNV order = {
VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV, // VkShadingRatePaletteEntryNV shadingRate;
1u, // uint32_t sampleCount;
2u, // uint32_t 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_KHR_or_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;
virtual const std::vector<std::string> &getDeviceExtensions(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())
, m_extensions(context.getDeviceExtensions())
{
}
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;
}
const std::vector<std::string> &getDeviceExtensions(void) const override
{
return m_extensions;
}
protected:
const DeviceInterface &m_deviceInterface;
const VkDevice m_device;
const uint32_t m_queueFamilyIndex;
const VkQueue m_queue;
Allocator &m_allocator;
std::vector<std::string> m_extensions;
};
// 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;
nullptr, // const void* pNext;
0u, // VkDeviceQueueCreateFlags flags;
m_queueFamilyIndex, // uint32_t queueFamilyIndex;
1u, // uint32_t queueCount;
&queuePriority // const float* pQueuePriorities;
};
const char *extensions[] = {
"VK_NV_shading_rate_image",
};
m_extensions.push_back("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
nullptr,
#endif // CTS_USES_VULKANSC
0u, //flags
1u, //queueRecordCount;
&queueParams, //pRequestedQueues;
0u, //layerCount;
nullptr, //ppEnabledLayerNames;
static_cast<uint32_t>(de::arrayLength(extensions)), // uint32_t 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(), context.getUsedApiVersion(),
context.getTestContext().getCommandLine()));
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;
}
const std::vector<std::string> &getDeviceExtensions(void) const override
{
return m_extensions;
}
protected:
Move<VkDevice> m_device;
std::unique_ptr<DeviceDriver> m_vkd;
uint32_t m_queueFamilyIndex;
VkQueue m_queue;
std::unique_ptr<SimpleAllocator> m_allocator;
std::vector<std::string> m_extensions;
};
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,
PipelineConstructionType pipelineConstructionType)
{
// 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, pipelineConstructionType));
// 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 TestParams &params,
PipelineConstructionType pipelineConstructionType);
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;
PipelineConstructionType m_pipelineConstructionType;
};
class DynamicStateComputeInstance : public vkt::TestInstance
{
public:
DynamicStateComputeInstance(Context &context, const TestParams &params,
PipelineConstructionType pipelineConstructionType);
virtual ~DynamicStateComputeInstance(void)
{
}
virtual tcu::TestStatus iterate(void);
protected:
tcu::TestStatus iterateTransfer(void);
tcu::TestStatus iterateCompute(void);
TestParams m_params;
PipelineConstructionType m_pipelineConstructionType;
};
DynamicStateComputeCase::DynamicStateComputeCase(tcu::TestContext &testCtx, const std::string &name,
const TestParams &params,
PipelineConstructionType pipelineConstructionType)
: vkt::TestCase(testCtx, name)
, m_params(params)
, m_pipelineConstructionType(pipelineConstructionType)
{
}
DynamicStateComputeInstance::DynamicStateComputeInstance(Context &context, const TestParams &params,
PipelineConstructionType pipelineConstructionType)
: vkt::TestInstance(context)
, m_params(params)
, m_pipelineConstructionType(pipelineConstructionType)
{
}
void DynamicStateComputeCase::checkSupport(Context &context) const
{
checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
m_pipelineConstructionType);
// Check required functionalities.
for (const auto &state : m_params.states)
{
const auto stateInfo = getDynamicStateInfo(state);
for (const auto &functionality : stateInfo.requirements)
{
if (functionality == "VK_KHR_or_EXT_line_rasterization")
{
if (!context.isDeviceFunctionalitySupported("VK_KHR_line_rasterization") &&
!context.isDeviceFunctionalitySupported("VK_EXT_line_rasterization"))
{
TCU_THROW(NotSupportedError,
"VK_KHR_line_rasterization and VK_EXT_line_rasterization are not supported");
}
}
else
{
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, m_pipelineConstructionType);
}
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<uint32_t> &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 uint32_t seqStart = 1611747605u;
DE_ASSERT(!m_params.states.empty());
std::vector<uint32_t> 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, m_pipelineConstructionType));
// 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 uint32_t pcSize = static_cast<uint32_t>(sizeof(uint32_t));
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, // uint32_t setLayoutCount;
&setLayout.get(), // const VkDescriptorSetLayout* pSetLayouts;
1u, // uint32_t 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;
VK_NULL_HANDLE, // VkPipeline basePipelineHandle;
0, // int32_t basePipelineIndex;
};
const auto pipeline = createComputePipeline(vkd, device, VK_NULL_HANDLE, &pipelineInfo);
DE_ASSERT(!m_params.states.empty());
// Output buffer with one value per state.
std::vector<uint32_t> 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.
auto state = m_params.states[stateIdx];
if (vk::isConstructionTypeShaderObject(m_pipelineConstructionType))
{
if (state == vk::VK_DYNAMIC_STATE_VIEWPORT)
state = vk::VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT;
if (state == vk::VK_DYNAMIC_STATE_SCISSOR)
state = vk::VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT;
}
const auto stateInfo = getDynamicStateInfo(state);
statesData.push_back(getDynamicStateData(m_context, device, state, m_pipelineConstructionType));
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 uint32_t pcData = static_cast<uint32_t>(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));
}
} // namespace
tcu::TestCaseGroup *createDynamicStateComputeTests(tcu::TestContext &testCtx,
vk::PipelineConstructionType pipelineConstructionType)
{
using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
// Dynamic state mixed with compute and transfer operations
GroupPtr mainGroup(new tcu::TestCaseGroup(testCtx, "compute_transfer"));
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"));
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,
pipelineConstructionType));
}
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"));
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,
pipelineConstructionType));
}
multiStateGroup->addChild(operationGroup.release());
}
mainGroup->addChild(multiStateGroup.release());
}
return mainGroup.release();
}
void cleanupDevice()
{
g_shadingRateDeviceHelper.reset(nullptr);
g_contextDeviceHelper.reset(nullptr);
}
} // namespace DynamicState
} // namespace vkt