• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2021 The Khronos Group Inc.
6  * Copyright (c) 2021 Valve Corporation.
7  * Copyright (c) 2023 LunarG, Inc.
8  * Copyright (c) 2023 Nintendo
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  *//*!
23  * \file
24  * \brief Dynamic State tests mixing it with compute and transfer.
25  *//*--------------------------------------------------------------------*/
26 #include "vktDynamicStateComputeTests.hpp"
27 #include "vktCustomInstancesDevices.hpp"
28 
29 #include "vkBufferWithMemory.hpp"
30 #include "vkObjUtil.hpp"
31 #include "vkCmdUtil.hpp"
32 #include "vkBarrierUtil.hpp"
33 #include "vkBuilderUtil.hpp"
34 #include "vkTypeUtil.hpp"
35 
36 #include "tcuCommandLine.hpp"
37 #include "tcuVector.hpp"
38 
39 #include <vector>
40 #include <string>
41 #include <functional>
42 #include <map>
43 #include <sstream>
44 #include <cstring>
45 #include <iterator>
46 #include <numeric>
47 #include <memory>
48 
49 namespace vkt
50 {
51 namespace DynamicState
52 {
53 
54 namespace
55 {
56 
57 using namespace vk;
58 
59 // Additional objects needed to set a given dynamic state that need to exist beyond the state-setting call. Empty by default.
60 struct DynamicStateData
61 {
~DynamicStateDatavkt::DynamicState::__anona4c866bd0111::DynamicStateData62 	virtual ~DynamicStateData() {}
63 };
64 
65 // A vertex buffer and graphics pipeline are needed for vkCmdBindVertexBuffers2EXT().
66 struct BindVertexBuffersData : public DynamicStateData
67 {
68 private:
69 	using BufferPtr			= de::MovePtr<BufferWithMemory>;
70 	using RenderPassPtr		= RenderPassWrapper;
71 	using LayoutPtr			= Move<VkPipelineLayout>;
72 	using ModulePtr			= Move<VkShaderModule>;
73 	using PipelinePtr		= Move<VkPipeline>;
74 
75 	static constexpr deUint32 kWidth	= 16u;
76 	static constexpr deUint32 kHeight	= 16u;
77 
getExtentvkt::DynamicState::__anona4c866bd0111::BindVertexBuffersData78 	VkExtent3D getExtent (void)
79 	{
80 		return makeExtent3D(kWidth, kHeight, 1u);
81 	}
82 
83 public:
BindVertexBuffersDatavkt::DynamicState::__anona4c866bd0111::BindVertexBuffersData84 	BindVertexBuffersData(Context& ctx, VkDevice device, PipelineConstructionType pipelineConstructionType)
85 		: m_vertexBuffer		()
86 		, m_dataSize			(0u)
87 		, m_vertexBufferSize	(0ull)
88 		, m_renderPass			()
89 		, m_pipelineLayout		()
90 		, m_vertexShader		()
91 		, m_graphicsPipeline	()
92 	{
93 		const auto&	vki			= ctx.getInstanceInterface();
94 		const auto	phyDev		= ctx.getPhysicalDevice();
95 		const auto&	vkd			= ctx.getDeviceInterface();
96 		auto&		alloc		= ctx.getDefaultAllocator();
97 
98 		// Vertex buffer.
99 		tcu::Vec4	vertex		(0.f, 0.f, 0.f, 1.f);
100 		m_dataSize				= sizeof(vertex);
101 		m_vertexBufferSize		= de::roundUp(static_cast<VkDeviceSize>(m_dataSize), getPhysicalDeviceProperties(vki, phyDev).limits.nonCoherentAtomSize);
102 		const auto	bufferInfo	= makeBufferCreateInfo(m_vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
103 
104 		m_vertexBuffer			= BufferPtr(new BufferWithMemory(vkd, device, alloc, bufferInfo, MemoryRequirement::HostVisible));
105 		auto&	bufferAlloc		= m_vertexBuffer->getAllocation();
106 
107 		deMemcpy(bufferAlloc.getHostPtr(), &vertex, m_dataSize);
108 		flushAlloc(vkd, device, bufferAlloc);
109 
110 		// Empty render pass.
111 		m_renderPass = RenderPassWrapper(pipelineConstructionType, vkd, device);
112 
113 		// Empty pipeline layout.
114 		m_pipelineLayout = makePipelineLayout(vkd, device);
115 
116 		// Passthrough vertex shader.
117 		m_vertexShader = createShaderModule(vkd, device, ctx.getBinaryCollection().get("vert"), 0u);
118 
119 		const auto						extent		= getExtent();
120 		const std::vector<VkViewport>	viewports	(1, makeViewport(extent));
121 		const std::vector<VkRect2D>		scissors	(1, makeRect2D(extent));
122 		const VkDynamicState			state		= VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT;
123 
124 		const VkPipelineDynamicStateCreateInfo dynamicStateInfo =
125 		{
126 			VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,	//	VkStructureType						sType;
127 			nullptr,												//	const void*							pNext;
128 			0u,														//	VkPipelineDynamicStateCreateFlags	flags;
129 			1u,														//	deUint32							dynamicStateCount;
130 			&state,													//	const VkDynamicState*				pDynamicStates;
131 		};
132 
133 		// Graphics pipeline.
134 		m_graphicsPipeline = makeGraphicsPipeline(vkd, device, m_pipelineLayout.get(),
135 			m_vertexShader.get(), DE_NULL, DE_NULL, DE_NULL, DE_NULL,
136 			m_renderPass.get(), viewports, scissors, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0u, 0u,
137 			nullptr, nullptr, nullptr, nullptr, nullptr, &dynamicStateInfo);
138 	}
139 
getVertexBuffervkt::DynamicState::__anona4c866bd0111::BindVertexBuffersData140 	const BufferWithMemory*	getVertexBuffer () const
141 	{
142 		return m_vertexBuffer.get();
143 	}
144 
getDataSizevkt::DynamicState::__anona4c866bd0111::BindVertexBuffersData145 	size_t getDataSize () const
146 	{
147 		return m_dataSize;
148 	}
149 
getPipelinevkt::DynamicState::__anona4c866bd0111::BindVertexBuffersData150 	VkPipeline getPipeline () const
151 	{
152 		return m_graphicsPipeline.get();
153 	}
154 
~BindVertexBuffersDatavkt::DynamicState::__anona4c866bd0111::BindVertexBuffersData155 	virtual ~BindVertexBuffersData() {}
156 
157 private:
158 	BufferPtr		m_vertexBuffer;
159 	size_t			m_dataSize;
160 	VkDeviceSize	m_vertexBufferSize;
161 	RenderPassPtr	m_renderPass;
162 	LayoutPtr		m_pipelineLayout;
163 	ModulePtr		m_vertexShader;
164 	PipelinePtr		m_graphicsPipeline;
165 };
166 
167 // Function that records a state-setting command in the given command buffer.
168 using RecordStateFunction = std::function<void(const DeviceInterface*, VkCommandBuffer, const DynamicStateData*)>;
169 
170 // State-setting functions
setViewport(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData *)171 void setViewport (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
172 {
173 	const VkViewport viewport =
174 	{
175 		0.0f,	//	float	x;
176 		0.0f,	//	float	y;
177 		1.0f,	//	float	width;
178 		1.0f,	//	float	height;
179 		0.0f,	//	float	minDepth;
180 		1.0f,	//	float	maxDepth;
181 	};
182 	vkd->cmdSetViewport(cmdBuffer, 0u, 1u, &viewport);
183 }
184 
setScissor(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData *)185 void setScissor (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
186 {
187 	const VkRect2D scissor =
188 	{
189 		{ 0, 0 },	//	VkOffset2D	offset;
190 		{ 1u, 1u },	//	VkExtent2D	extent;
191 	};
192 	vkd->cmdSetScissor(cmdBuffer, 0u, 1u, &scissor);
193 }
194 
setLineWidth(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData *)195 void setLineWidth (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
196 {
197 	vkd->cmdSetLineWidth(cmdBuffer, 1.0f);
198 }
199 
setDepthBias(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData *)200 void setDepthBias (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
201 {
202 	vkd->cmdSetDepthBias(cmdBuffer, 0.0f, 0.0f, 0.0f);
203 }
204 
setBlendConstants(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData *)205 void setBlendConstants (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
206 {
207 	const float blendConstants[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
208 	vkd->cmdSetBlendConstants(cmdBuffer, blendConstants);
209 }
210 
setDepthBounds(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData *)211 void setDepthBounds (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
212 {
213 	vkd->cmdSetDepthBounds(cmdBuffer, 0.0f, 1.0f);
214 }
215 
setStencilCompareMask(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData *)216 void setStencilCompareMask (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
217 {
218 	vkd->cmdSetStencilCompareMask(cmdBuffer, VK_STENCIL_FACE_FRONT_AND_BACK, 0xFFu);
219 }
220 
setStencilWriteMask(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData *)221 void setStencilWriteMask (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
222 {
223 	vkd->cmdSetStencilWriteMask(cmdBuffer, VK_STENCIL_FACE_FRONT_AND_BACK, 0xFFu);
224 }
225 
setStencilReference(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData *)226 void setStencilReference (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
227 {
228 	vkd->cmdSetStencilReference(cmdBuffer, VK_STENCIL_FACE_FRONT_AND_BACK, 0xFFu);
229 }
230 
setDiscardRectangle(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData *)231 void setDiscardRectangle (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
232 {
233 	const VkRect2D rectangle =
234 	{
235 		{ 0, 0 },	//	VkOffset2D	offset;
236 		{ 1u, 1u },	//	VkExtent2D	extent;
237 	};
238 	vkd->cmdSetDiscardRectangleEXT(cmdBuffer, 0u, 1u, &rectangle);
239 }
240 
setSampleLocations(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData *)241 void setSampleLocations (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
242 {
243 	const VkSampleLocationEXT locations[] =
244 	{
245 		{ 0.5f, 0.5f },
246 		{ 0.5f, 1.5f },
247 		{ 1.5f, 0.5f },
248 		{ 1.5f, 1.5f },
249 	};
250 	const VkSampleLocationsInfoEXT info =
251 	{
252 		VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT,	//	VkStructureType				sType;
253 		nullptr,										//	const void*					pNext;
254 		VK_SAMPLE_COUNT_4_BIT,							//	VkSampleCountFlagBits		sampleLocationsPerPixel;
255 		{ 1u, 1u },										//	VkExtent2D					sampleLocationGridSize;
256 		4u,												//	deUint32					sampleLocationsCount;
257 		locations,										//	const VkSampleLocationEXT*	pSampleLocations;
258 	};
259 	vkd->cmdSetSampleLocationsEXT(cmdBuffer, &info);
260 }
261 
262 #ifndef CTS_USES_VULKANSC
setRTPipelineStatckSize(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData *)263 void setRTPipelineStatckSize (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
264 {
265 	vkd->cmdSetRayTracingPipelineStackSizeKHR(cmdBuffer, 4096u);
266 }
267 #endif // CTS_USES_VULKANSC
268 
setFragmentShadingRage(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData *)269 void setFragmentShadingRage (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
270 {
271 	const VkExtent2D							fragmentSize	= { 1u, 1u };
272 	const VkFragmentShadingRateCombinerOpKHR	combinerOps[2]	=
273 	{
274 		VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR,
275 		VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR,
276 	};
277 	vkd->cmdSetFragmentShadingRateKHR(cmdBuffer, &fragmentSize, combinerOps);
278 }
279 
setLineStipple(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData *)280 void setLineStipple (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
281 {
282 	vkd->cmdSetLineStippleEXT(cmdBuffer, 1u, 1u);
283 }
284 
setCullMode(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData *)285 void setCullMode (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
286 {
287 #ifndef CTS_USES_VULKANSC
288 	vkd->cmdSetCullMode(cmdBuffer, VK_CULL_MODE_FRONT_AND_BACK);
289 #else
290 	vkd->cmdSetCullModeEXT(cmdBuffer, VK_CULL_MODE_FRONT_AND_BACK);
291 #endif // CTS_USES_VULKANSC
292 }
293 
setFrontFace(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData *)294 void setFrontFace (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
295 {
296 #ifndef CTS_USES_VULKANSC
297 	vkd->cmdSetFrontFace(cmdBuffer, VK_FRONT_FACE_COUNTER_CLOCKWISE);
298 #else
299 	vkd->cmdSetFrontFaceEXT(cmdBuffer, VK_FRONT_FACE_COUNTER_CLOCKWISE);
300 #endif // CTS_USES_VULKANSC
301 }
302 
setPrimitiveTopology(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData *)303 void setPrimitiveTopology (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
304 {
305 #ifndef CTS_USES_VULKANSC
306 	vkd->cmdSetPrimitiveTopology(cmdBuffer, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
307 #else
308 	vkd->cmdSetPrimitiveTopologyEXT(cmdBuffer, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
309 #endif // CTS_USES_VULKANSC
310 }
311 
setViewportWithCount(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData *)312 void setViewportWithCount (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
313 {
314 	const VkViewport viewport =
315 	{
316 		0.0f,	//	float	x;
317 		0.0f,	//	float	y;
318 		1.0f,	//	float	width;
319 		1.0f,	//	float	height;
320 		0.0f,	//	float	minDepth;
321 		1.0f,	//	float	maxDepth;
322 	};
323 #ifndef CTS_USES_VULKANSC
324 	vkd->cmdSetViewportWithCount(cmdBuffer, 1u, &viewport);
325 #else
326 	vkd->cmdSetViewportWithCountEXT(cmdBuffer, 1u, &viewport);
327 #endif // CTS_USES_VULKANSC
328 }
329 
setScissorWithCount(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData *)330 void setScissorWithCount (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
331 {
332 	const VkRect2D scissor =
333 	{
334 		{ 0, 0 },	//	VkOffset2D	offset;
335 		{ 1u, 1u },	//	VkExtent2D	extent;
336 	};
337 #ifndef CTS_USES_VULKANSC
338 	vkd->cmdSetScissorWithCount(cmdBuffer, 1u, &scissor);
339 #else
340 	vkd->cmdSetScissorWithCountEXT(cmdBuffer, 1u, &scissor);
341 #endif // CTS_USES_VULKANSC
342 }
343 
bindVertexBuffers(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData * data)344 void bindVertexBuffers (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData* data)
345 {
346 	const auto bindData			= dynamic_cast<const BindVertexBuffersData*>(data);
347 	DE_ASSERT(bindData != nullptr);
348 	const auto vertexBuffer		= bindData->getVertexBuffer();
349 	const auto dataSize			= static_cast<VkDeviceSize>(bindData->getDataSize());
350 	const auto bufferOffset		= vertexBuffer->getAllocation().getOffset();
351 	const auto stride			= static_cast<VkDeviceSize>(0);
352 	const auto pipeline			= bindData->getPipeline();
353 
354 	vkd->cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
355 #ifndef CTS_USES_VULKANSC
356 	vkd->cmdBindVertexBuffers2(cmdBuffer, 0u, 1u, &vertexBuffer->get(), &bufferOffset, &dataSize, &stride);
357 #else
358 	vkd->cmdBindVertexBuffers2EXT(cmdBuffer, 0u, 1u, &vertexBuffer->get(), &bufferOffset, &dataSize, &stride);
359 #endif // CTS_USES_VULKANSC
360 }
361 
setDepthTestEnable(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData *)362 void setDepthTestEnable (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
363 {
364 #ifndef CTS_USES_VULKANSC
365 	vkd->cmdSetDepthTestEnable(cmdBuffer, VK_TRUE);
366 #else
367 	vkd->cmdSetDepthTestEnableEXT(cmdBuffer, VK_TRUE);
368 #endif // CTS_USES_VULKANSC
369 }
370 
setDepthWriteEnable(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData *)371 void setDepthWriteEnable (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
372 {
373 #ifndef CTS_USES_VULKANSC
374 	vkd->cmdSetDepthWriteEnable(cmdBuffer, VK_TRUE);
375 #else
376 	vkd->cmdSetDepthWriteEnableEXT(cmdBuffer, VK_TRUE);
377 #endif // CTS_USES_VULKANSC
378 }
379 
setDepthCompareOp(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData *)380 void setDepthCompareOp (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
381 {
382 #ifndef CTS_USES_VULKANSC
383 	vkd->cmdSetDepthCompareOp(cmdBuffer, VK_COMPARE_OP_LESS);
384 #else
385 	vkd->cmdSetDepthCompareOpEXT(cmdBuffer, VK_COMPARE_OP_LESS);
386 #endif // CTS_USES_VULKANSC
387 }
388 
setDepthBoundsTestEnable(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData *)389 void setDepthBoundsTestEnable (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
390 {
391 #ifndef CTS_USES_VULKANSC
392 	vkd->cmdSetDepthBoundsTestEnable(cmdBuffer, VK_TRUE);
393 #else
394 	vkd->cmdSetDepthBoundsTestEnableEXT(cmdBuffer, VK_TRUE);
395 #endif // CTS_USES_VULKANSC
396 }
397 
setStencilTestEnable(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData *)398 void setStencilTestEnable (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
399 {
400 #ifndef CTS_USES_VULKANSC
401 	vkd->cmdSetStencilTestEnable(cmdBuffer, VK_TRUE);
402 #else
403 	vkd->cmdSetStencilTestEnableEXT(cmdBuffer, VK_TRUE);
404 #endif // CTS_USES_VULKANSC
405 }
406 
setStencilOp(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData *)407 void setStencilOp (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
408 {
409 #ifndef CTS_USES_VULKANSC
410 	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);
411 #else
412 	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);
413 #endif // CTS_USES_VULKANSC
414 }
415 
416 #ifndef CTS_USES_VULKANSC
417 
setViewportWScaling(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData *)418 void setViewportWScaling (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
419 {
420 	const VkViewportWScalingNV viewport =
421 	{
422 		1.0f,	//	float	xcoeff;
423 		1.0f,	//	float	ycoeff;
424 	};
425 	vkd->cmdSetViewportWScalingNV(cmdBuffer, 0u, 1u, &viewport);
426 }
427 
setViewportShadingRatePalette(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData *)428 void setViewportShadingRatePalette (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
429 {
430 	const VkShadingRatePaletteEntryNV	entry	= VK_SHADING_RATE_PALETTE_ENTRY_NO_INVOCATIONS_NV;
431 	const VkShadingRatePaletteNV		palette	=
432 	{
433 		1u,		//	deUint32							shadingRatePaletteEntryCount;
434 		&entry,	//	const VkShadingRatePaletteEntryNV*	pShadingRatePaletteEntries;
435 	};
436 	vkd->cmdSetViewportShadingRatePaletteNV(cmdBuffer, 0u, 1u, &palette);
437 }
438 
setCoarseSamplingOrder(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData *)439 void setCoarseSamplingOrder (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
440 {
441 	const VkCoarseSampleLocationNV locations[2] =
442 	{
443 		{
444 			0u,	//	deUint32	pixelX;
445 			0u,	//	deUint32	pixelY;
446 			0u,	//	deUint32	sample;
447 		},
448 		{
449 			0u,	//	deUint32	pixelX;
450 			1u,	//	deUint32	pixelY;
451 			0u,	//	deUint32	sample;
452 		},
453 	};
454 	const VkCoarseSampleOrderCustomNV order =
455 	{
456 		VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV,	//	VkShadingRatePaletteEntryNV		shadingRate;
457 		1u,																//	deUint32						sampleCount;
458 		2u,																//	deUint32						sampleLocationCount;
459 		locations														//	const VkCoarseSampleLocationNV*	pSampleLocations;
460 	};
461 	vkd->cmdSetCoarseSampleOrderNV(cmdBuffer, VK_COARSE_SAMPLE_ORDER_TYPE_CUSTOM_NV, 1u, &order);
462 }
463 
setExclusiveScissor(const DeviceInterface * vkd,VkCommandBuffer cmdBuffer,const DynamicStateData *)464 void setExclusiveScissor (const DeviceInterface* vkd, VkCommandBuffer cmdBuffer, const DynamicStateData*)
465 {
466 	const VkRect2D scissor =
467 	{
468 		{ 0, 0 },	//	VkOffset2D	offset;
469 		{ 1u, 1u },	//	VkExtent2D	extent;
470 	};
471 	vkd->cmdSetExclusiveScissorNV(cmdBuffer, 0u, 1u, &scissor);
472 }
473 
474 #endif // CTS_USES_VULKANSC
475 
476 const VkDynamicState dynamicStateList[] =
477 {
478 	VK_DYNAMIC_STATE_VIEWPORT,
479 	VK_DYNAMIC_STATE_SCISSOR,
480 	VK_DYNAMIC_STATE_LINE_WIDTH,
481 	VK_DYNAMIC_STATE_DEPTH_BIAS,
482 	VK_DYNAMIC_STATE_BLEND_CONSTANTS,
483 	VK_DYNAMIC_STATE_DEPTH_BOUNDS,
484 	VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK,
485 	VK_DYNAMIC_STATE_STENCIL_WRITE_MASK,
486 	VK_DYNAMIC_STATE_STENCIL_REFERENCE,
487 	VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT,
488 	VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT,
489 #ifndef CTS_USES_VULKANSC
490 	VK_DYNAMIC_STATE_RAY_TRACING_PIPELINE_STACK_SIZE_KHR,
491 #endif // CTS_USES_VULKANSC
492 	VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR,
493 	VK_DYNAMIC_STATE_LINE_STIPPLE_EXT,
494 	VK_DYNAMIC_STATE_CULL_MODE_EXT,
495 	VK_DYNAMIC_STATE_FRONT_FACE_EXT,
496 	VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT,
497 	VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT,
498 	VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT,
499 	VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT,
500 	VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT,
501 	VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT,
502 	VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT,
503 	VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT,
504 	VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT,
505 	VK_DYNAMIC_STATE_STENCIL_OP_EXT,
506 #ifndef CTS_USES_VULKANSC
507 	VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV,
508 	VK_DYNAMIC_STATE_VIEWPORT_SHADING_RATE_PALETTE_NV,
509 	VK_DYNAMIC_STATE_VIEWPORT_COARSE_SAMPLE_ORDER_NV,
510 	VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_NV,
511 #endif // CTS_USES_VULKANSC
512 };
513 
514 // Information about a dynamic state.
515 struct StateInfo
516 {
517 	std::vector<std::string>	requirements;	// List of required functionalities.
518 	RecordStateFunction			recorder;		// Function that records the state to the command buffer being used.
519 };
520 
521 // Returns the state info for a given dynamic state.
getDynamicStateInfo(VkDynamicState state)522 const StateInfo& getDynamicStateInfo (VkDynamicState state)
523 {
524 	// Maps a given state to its state info structure.
525 	using StateInfoMap = std::map<VkDynamicState, StateInfo>;
526 
527 	static const StateInfoMap result =
528 	{
529 		{	VK_DYNAMIC_STATE_VIEWPORT,								{	{},										setViewport						}	},
530 		{	VK_DYNAMIC_STATE_SCISSOR,								{	{},										setScissor						}	},
531 		{	VK_DYNAMIC_STATE_LINE_WIDTH,							{	{},										setLineWidth					}	},
532 		{	VK_DYNAMIC_STATE_DEPTH_BIAS,							{	{},										setDepthBias					}	},
533 		{	VK_DYNAMIC_STATE_BLEND_CONSTANTS,						{	{},										setBlendConstants				}	},
534 		{	VK_DYNAMIC_STATE_DEPTH_BOUNDS,							{	{},										setDepthBounds					}	},
535 		{	VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK,					{	{},										setStencilCompareMask			}	},
536 		{	VK_DYNAMIC_STATE_STENCIL_WRITE_MASK,					{	{},										setStencilWriteMask				}	},
537 		{	VK_DYNAMIC_STATE_STENCIL_REFERENCE,						{	{},										setStencilReference				}	},
538 		{	VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT,					{	{ "VK_EXT_discard_rectangles" },		setDiscardRectangle				}	},
539 		{	VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT,					{	{ "VK_EXT_sample_locations" },			setSampleLocations				}	},
540 #ifndef CTS_USES_VULKANSC
541 		{	VK_DYNAMIC_STATE_RAY_TRACING_PIPELINE_STACK_SIZE_KHR,	{	{ "VK_KHR_ray_tracing_pipeline" },		setRTPipelineStatckSize			}	},
542 #endif // CTS_USES_VULKANSC
543 		{	VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR,				{	{ "VK_KHR_fragment_shading_rate" },		setFragmentShadingRage			}	},
544 		{	VK_DYNAMIC_STATE_LINE_STIPPLE_EXT,						{	{ "VK_EXT_line_rasterization" },		setLineStipple					}	},
545 		{	VK_DYNAMIC_STATE_CULL_MODE_EXT,							{	{ "VK_EXT_extended_dynamic_state" },	setCullMode						}	},
546 		{	VK_DYNAMIC_STATE_FRONT_FACE_EXT,						{	{ "VK_EXT_extended_dynamic_state" },	setFrontFace					}	},
547 		{	VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT,				{	{ "VK_EXT_extended_dynamic_state" },	setPrimitiveTopology			}	},
548 		{	VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT,				{	{ "VK_EXT_extended_dynamic_state" },	setViewportWithCount			}	},
549 		{	VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT,				{	{ "VK_EXT_extended_dynamic_state" },	setScissorWithCount				}	},
550 		{	VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT,		{	{ "VK_EXT_extended_dynamic_state" },	bindVertexBuffers				}	},
551 		{	VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT,					{	{ "VK_EXT_extended_dynamic_state" },	setDepthTestEnable				}	},
552 		{	VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT,				{	{ "VK_EXT_extended_dynamic_state" },	setDepthWriteEnable				}	},
553 		{	VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT,					{	{ "VK_EXT_extended_dynamic_state" },	setDepthCompareOp				}	},
554 		{	VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT,			{	{ "VK_EXT_extended_dynamic_state" },	setDepthBoundsTestEnable		}	},
555 		{	VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT,				{	{ "VK_EXT_extended_dynamic_state" },	setStencilTestEnable			}	},
556 		{	VK_DYNAMIC_STATE_STENCIL_OP_EXT,						{	{ "VK_EXT_extended_dynamic_state" },	setStencilOp					}	},
557 #ifndef CTS_USES_VULKANSC
558 		{	VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV,					{	{ "VK_NV_clip_space_w_scaling" },		setViewportWScaling				}	},
559 		{	VK_DYNAMIC_STATE_VIEWPORT_SHADING_RATE_PALETTE_NV,		{	{ "VK_NV_shading_rate_image"},			setViewportShadingRatePalette	}	},
560 		{	VK_DYNAMIC_STATE_VIEWPORT_COARSE_SAMPLE_ORDER_NV,		{	{ "VK_NV_shading_rate_image"},			setCoarseSamplingOrder			}	},
561 		{	VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_NV,					{	{ "VK_NV_scissor_exclusive"},			setExclusiveScissor				}	},
562 #endif // CTS_USES_VULKANSC
563 	};
564 
565 	const auto itr = result.find(state);
566 	DE_ASSERT(itr != result.end());
567 
568 	return itr->second;
569 }
570 
571 // Device helper: this is needed in some tests when we create custom devices.
572 class DeviceHelper
573 {
574 public:
~DeviceHelper()575 	virtual ~DeviceHelper () {}
576 	virtual const DeviceInterface&			getDeviceInterface	(void) const = 0;
577 	virtual VkDevice						getDevice			(void) const = 0;
578 	virtual uint32_t						getQueueFamilyIndex	(void) const = 0;
579 	virtual VkQueue							getQueue			(void) const = 0;
580 	virtual Allocator&						getAllocator		(void) const = 0;
581 	virtual const std::vector<std::string>&	getDeviceExtensions	(void) const = 0;
582 };
583 
584 // This one just reuses the default device from the context.
585 class ContextDeviceHelper : public DeviceHelper
586 {
587 public:
ContextDeviceHelper(Context & context)588 	ContextDeviceHelper (Context& context)
589 		: m_deviceInterface		(context.getDeviceInterface())
590 		, m_device				(context.getDevice())
591 		, m_queueFamilyIndex	(context.getUniversalQueueFamilyIndex())
592 		, m_queue				(context.getUniversalQueue())
593 		, m_allocator			(context.getDefaultAllocator())
594 		, m_extensions			(context.getDeviceExtensions())
595 		{}
596 
~ContextDeviceHelper()597 	virtual ~ContextDeviceHelper () {}
598 
getDeviceInterface(void) const599 	const DeviceInterface&			getDeviceInterface	(void) const override	{ return m_deviceInterface;		}
getDevice(void) const600 	VkDevice						getDevice			(void) const override	{ return m_device;				}
getQueueFamilyIndex(void) const601 	uint32_t						getQueueFamilyIndex	(void) const override	{ return m_queueFamilyIndex;	}
getQueue(void) const602 	VkQueue							getQueue			(void) const override	{ return m_queue;				}
getAllocator(void) const603 	Allocator&						getAllocator		(void) const override	{ return m_allocator;			}
getDeviceExtensions(void) const604 	const std::vector<std::string>&	getDeviceExtensions	(void) const override	{ return m_extensions;			}
605 
606 protected:
607 	const DeviceInterface&		m_deviceInterface;
608 	const VkDevice				m_device;
609 	const uint32_t				m_queueFamilyIndex;
610 	const VkQueue				m_queue;
611 	Allocator&					m_allocator;
612 	std::vector<std::string>	m_extensions;
613 };
614 
615 // This one creates a new device with VK_NV_shading_rate_image.
616 class ShadingRateImageDeviceHelper : public DeviceHelper
617 {
618 public:
ShadingRateImageDeviceHelper(Context & context)619 	ShadingRateImageDeviceHelper (Context& context)
620 	{
621 		const auto&	vkp				= context.getPlatformInterface();
622 		const auto&	vki				= context.getInstanceInterface();
623 		const auto	instance		= context.getInstance();
624 		const auto	physicalDevice	= context.getPhysicalDevice();
625 		const auto	queuePriority	= 1.0f;
626 
627 		// Queue index first.
628 		m_queueFamilyIndex = context.getUniversalQueueFamilyIndex();
629 
630 		// Create a universal queue that supports graphics and compute.
631 		const VkDeviceQueueCreateInfo queueParams =
632 		{
633 			VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,	// VkStructureType				sType;
634 			DE_NULL,									// const void*					pNext;
635 			0u,											// VkDeviceQueueCreateFlags		flags;
636 			m_queueFamilyIndex,							// deUint32						queueFamilyIndex;
637 			1u,											// deUint32						queueCount;
638 			&queuePriority								// const float*					pQueuePriorities;
639 		};
640 
641 		const char* extensions[] =
642 		{
643 			"VK_NV_shading_rate_image",
644 		};
645 		m_extensions.push_back("VK_NV_shading_rate_image");
646 
647 #ifndef CTS_USES_VULKANSC
648 		VkPhysicalDeviceShadingRateImageFeaturesNV	shadingRateImageFeatures	= initVulkanStructure();
649 		VkPhysicalDeviceFeatures2					features2					= initVulkanStructure(&shadingRateImageFeatures);
650 
651 		vki.getPhysicalDeviceFeatures2(physicalDevice, &features2);
652 #endif // CTS_USES_VULKANSC
653 
654 		const VkDeviceCreateInfo deviceCreateInfo =
655 		{
656 			VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,					//sType;
657 #ifndef CTS_USES_VULKANSC
658 			&features2,												//pNext;
659 #else
660 			DE_NULL,
661 #endif // CTS_USES_VULKANSC
662 			0u,														//flags
663 			1u,														//queueRecordCount;
664 			&queueParams,											//pRequestedQueues;
665 			0u,														//layerCount;
666 			nullptr,												//ppEnabledLayerNames;
667 			static_cast<uint32_t>(de::arrayLength(extensions)),		// deUint32							enabledExtensionCount;
668 			extensions,												// const char* const*				ppEnabledExtensionNames;
669 			nullptr,												//pEnabledFeatures;
670 		};
671 
672 		m_device	= createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(), vkp, instance, vki, physicalDevice, &deviceCreateInfo);
673 		m_vkd		.reset(new DeviceDriver(vkp, instance, m_device.get(), context.getUsedApiVersion()));
674 		m_queue		= getDeviceQueue(*m_vkd, *m_device, m_queueFamilyIndex, 0u);
675 		m_allocator	.reset(new SimpleAllocator(*m_vkd, m_device.get(), getPhysicalDeviceMemoryProperties(vki, physicalDevice)));
676 	}
677 
~ShadingRateImageDeviceHelper()678 	virtual ~ShadingRateImageDeviceHelper () {}
679 
getDeviceInterface(void) const680 	const DeviceInterface&			getDeviceInterface	(void) const override	{ return *m_vkd;				}
getDevice(void) const681 	VkDevice						getDevice			(void) const override	{ return m_device.get();		}
getQueueFamilyIndex(void) const682 	uint32_t						getQueueFamilyIndex	(void) const override	{ return m_queueFamilyIndex;	}
getQueue(void) const683 	VkQueue							getQueue			(void) const override	{ return m_queue;				}
getAllocator(void) const684 	Allocator&						getAllocator		(void) const override	{ return *m_allocator;			}
getDeviceExtensions(void) const685 	const std::vector<std::string>&	getDeviceExtensions	(void) const override	{ return m_extensions;			}
686 
687 protected:
688 	Move<VkDevice>						m_device;
689 	std::unique_ptr<DeviceDriver>		m_vkd;
690 	deUint32							m_queueFamilyIndex;
691 	VkQueue								m_queue;
692 	std::unique_ptr<SimpleAllocator>	m_allocator;
693 	std::vector<std::string>			m_extensions;
694 };
695 
696 std::unique_ptr<DeviceHelper> g_shadingRateDeviceHelper;
697 std::unique_ptr<DeviceHelper> g_contextDeviceHelper;
698 
getDeviceHelper(Context & context,VkDynamicState dynamicState)699 DeviceHelper& getDeviceHelper(Context& context, VkDynamicState dynamicState)
700 {
701 	const auto& stateInfo = getDynamicStateInfo(dynamicState);
702 
703 	if (de::contains(stateInfo.requirements.begin(), stateInfo.requirements.end(), "VK_NV_shading_rate_image"))
704 	{
705 		if (!g_shadingRateDeviceHelper)
706 			g_shadingRateDeviceHelper.reset(new ShadingRateImageDeviceHelper(context));
707 		return *g_shadingRateDeviceHelper;
708 	}
709 
710 	if (!g_contextDeviceHelper)
711 		g_contextDeviceHelper.reset(new ContextDeviceHelper(context));
712 	return *g_contextDeviceHelper;
713 }
714 
715 // Returns the set of auxiliary data needed to set a given state.
getDynamicStateData(Context & ctx,VkDevice device,VkDynamicState state,PipelineConstructionType pipelineConstructionType)716 de::MovePtr<DynamicStateData> getDynamicStateData (Context& ctx, VkDevice device, VkDynamicState state, PipelineConstructionType pipelineConstructionType)
717 {
718 	// Create vertex buffer for VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT.
719 	if (state == VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT)
720 		return de::MovePtr<DynamicStateData>(new BindVertexBuffersData(ctx, device, pipelineConstructionType));
721 
722 	// null pointer normally.
723 	return de::MovePtr<DynamicStateData>();
724 }
725 
726 enum class OperType		{ COMPUTE = 0,	TRANSFER	};
727 enum class WhenToSet	{ BEFORE = 0,	AFTER		};
728 
729 // Set dynamic state before or after attempting to run a compute or transfer operation.
730 struct TestParams
731 {
732 	OperType					operationType;
733 	WhenToSet					whenToSet;
734 	std::vector<VkDynamicState>	states;
735 };
736 
737 class DynamicStateComputeCase : public vkt::TestCase
738 {
739 public:
740 
741 							DynamicStateComputeCase		(tcu::TestContext& testCtx, const std::string& name, const TestParams& params, PipelineConstructionType pipelineConstructionType);
~DynamicStateComputeCase(void)742 	virtual					~DynamicStateComputeCase	(void) {}
743 
744 	virtual void			checkSupport				(Context& context) const;
745 	virtual void			initPrograms				(vk::SourceCollections& programCollection) const;
746 	virtual TestInstance*	createInstance				(Context& context) const;
747 
748 protected:
749 	TestParams					m_params;
750 	PipelineConstructionType	m_pipelineConstructionType;
751 };
752 
753 class DynamicStateComputeInstance : public vkt::TestInstance
754 {
755 public:
756 								DynamicStateComputeInstance		(Context& context, const TestParams& params, PipelineConstructionType pipelineConstructionType);
~DynamicStateComputeInstance(void)757 	virtual						~DynamicStateComputeInstance	(void) {}
758 
759 	virtual tcu::TestStatus		iterate							(void);
760 
761 protected:
762 	tcu::TestStatus				iterateTransfer					(void);
763 	tcu::TestStatus				iterateCompute					(void);
764 
765 	TestParams					m_params;
766 	PipelineConstructionType	m_pipelineConstructionType;
767 };
768 
DynamicStateComputeCase(tcu::TestContext & testCtx,const std::string & name,const TestParams & params,PipelineConstructionType pipelineConstructionType)769 DynamicStateComputeCase::DynamicStateComputeCase(tcu::TestContext& testCtx, const std::string& name, const TestParams& params, PipelineConstructionType pipelineConstructionType)
770 	: vkt::TestCase					(testCtx, name)
771 	, m_params						(params)
772 	, m_pipelineConstructionType	(pipelineConstructionType)
773 {}
774 
DynamicStateComputeInstance(Context & context,const TestParams & params,PipelineConstructionType pipelineConstructionType)775 DynamicStateComputeInstance::DynamicStateComputeInstance (Context& context, const TestParams& params, PipelineConstructionType pipelineConstructionType)
776 	: vkt::TestInstance				(context)
777 	, m_params						(params)
778 	, m_pipelineConstructionType	(pipelineConstructionType)
779 {}
780 
checkSupport(Context & context) const781 void DynamicStateComputeCase::checkSupport (Context& context) const
782 {
783 	checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), m_pipelineConstructionType);
784 
785 	// Check required functionalities.
786 	for (const auto& state : m_params.states)
787 	{
788 		const auto stateInfo = getDynamicStateInfo(state);
789 		for (const auto& functionality : stateInfo.requirements)
790 			context.requireDeviceFunctionality(functionality);
791 	}
792 }
793 
initPrograms(vk::SourceCollections & programCollection) const794 void DynamicStateComputeCase::initPrograms (vk::SourceCollections& programCollection) const
795 {
796 	if (m_params.operationType == OperType::COMPUTE)
797 	{
798 		std::ostringstream comp;
799 		comp
800 			<< "#version 450\n"
801 			<< "\n"
802 			<< "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
803 			<< "\n"
804 			<< "layout (push_constant, std430) uniform PushConstants {\n"
805 			<< "	uint valueIndex;\n"
806 			<< "} pc;\n"
807 			<< "\n"
808 			<< "layout (set=0, binding=0, std430) buffer OutputBlock {\n"
809 			<< "	uint value[];\n"
810 			<< "} ob;\n"
811 			<< "\n"
812 			<< "void main ()\n"
813 			<< "{\n"
814 			<< "	ob.value[pc.valueIndex] = 1u;\n"
815 			<< "}\n"
816 			;
817 
818 		programCollection.glslSources.add("comp") << glu::ComputeSource(comp.str());
819 	}
820 
821 	if (de::contains(begin(m_params.states), end(m_params.states), VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT))
822 	{
823 		// Passthrough vertex shader for stand-in graphics pipeline.
824 		std::ostringstream vert;
825 		vert
826 			<< "#version 450\n"
827 			<< "layout (location=0) in vec4 inVertex;\n"
828 			<< "void main() {\n"
829 			<< "    gl_Position = inVertex;\n"
830 			<< "}\n"
831 			;
832 
833 		programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
834 	}
835 }
836 
createInstance(Context & context) const837 vkt::TestInstance* DynamicStateComputeCase::createInstance (Context& context) const
838 {
839 	return new DynamicStateComputeInstance(context, m_params, m_pipelineConstructionType);
840 }
841 
iterate(void)842 tcu::TestStatus DynamicStateComputeInstance::iterate (void)
843 {
844 	if (m_params.operationType == OperType::COMPUTE)
845 		return iterateCompute();
846 	else
847 		return iterateTransfer();
848 }
849 
fillBuffer(const DeviceInterface & vkd,VkDevice device,BufferWithMemory & buffer,const std::vector<deUint32> & values)850 void fillBuffer(const DeviceInterface& vkd, VkDevice device, BufferWithMemory& buffer, const std::vector<deUint32> &values)
851 {
852 	auto& alloc = buffer.getAllocation();
853 
854 	deMemcpy(alloc.getHostPtr(), values.data(), de::dataSize(values));
855 	flushAlloc(vkd, device, alloc);
856 }
857 
iterateTransfer(void)858 tcu::TestStatus DynamicStateComputeInstance::iterateTransfer (void)
859 {
860 	const auto&	vki			= m_context.getInstanceInterface();
861 	const auto	phyDev		= m_context.getPhysicalDevice();
862 	auto&		devHelper	= getDeviceHelper(m_context, m_params.states.at(0));
863 	const auto&	vkd			= devHelper.getDeviceInterface();
864 	const auto	device		= devHelper.getDevice();
865 	const auto	qIndex		= devHelper.getQueueFamilyIndex();
866 	const auto	queue		= devHelper.getQueue();
867 	auto&		alloc		= devHelper.getAllocator();
868 
869 	const auto	cmdPool			= makeCommandPool(vkd, device, qIndex);
870 	const auto	cmdBufferPtr	= allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
871 	const auto	cmdBuffer		= cmdBufferPtr.get();
872 
873 	// Prepare two host-visible buffers for a transfer operation, with one element per dynamic state.
874 	const deUint32		seqStart	= 1611747605u;
875 
876 	DE_ASSERT(!m_params.states.empty());
877 	std::vector<deUint32>		srcValues(m_params.states.size());
878 	const decltype(srcValues)	dstValues(srcValues.size(), 0u);
879 	std::iota(begin(srcValues), end(srcValues), seqStart);
880 
881 	const auto			elemSize	= static_cast<VkDeviceSize>(sizeof(decltype(srcValues)::value_type));
882 	const auto			dataSize	= static_cast<VkDeviceSize>(de::dataSize(srcValues));
883 	const auto			bufferSize	= de::roundUp(dataSize, getPhysicalDeviceProperties(vki, phyDev).limits.nonCoherentAtomSize);
884 	const auto			srcInfo		= makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
885 	const auto			dstInfo		= makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
886 	BufferWithMemory	srcBuffer	(vkd, device, alloc, srcInfo, MemoryRequirement::HostVisible);
887 	BufferWithMemory	dstBuffer	(vkd, device, alloc, dstInfo, MemoryRequirement::HostVisible);
888 
889 	// Fill source and destination buffer.
890 	fillBuffer(vkd, device, srcBuffer, srcValues);
891 	fillBuffer(vkd, device, dstBuffer, dstValues);
892 
893 	beginCommandBuffer(vkd, cmdBuffer);
894 
895 	// We need to preserve dynamic state data until the command buffer has run.
896 	std::vector<de::MovePtr<DynamicStateData>> statesData;
897 
898 	for (size_t stateIdx = 0; stateIdx < m_params.states.size(); ++stateIdx)
899 	{
900 		// Get extra data needed for using the dynamic state.
901 		const auto	offset		= elemSize * stateIdx;
902 		const auto&	state		= m_params.states[stateIdx];
903 		const auto	stateInfo	= getDynamicStateInfo(state);
904 		statesData.push_back(getDynamicStateData(m_context, device, state, m_pipelineConstructionType));
905 
906 		// Record command if before.
907 		if (m_params.whenToSet == WhenToSet::BEFORE)
908 			stateInfo.recorder(&vkd, cmdBuffer, statesData.back().get());
909 
910 		// Transfer op (copy one buffer element per dynamic state).
911 		const VkBufferCopy region = { offset, offset, elemSize };
912 		vkd.cmdCopyBuffer(cmdBuffer, srcBuffer.get(), dstBuffer.get(), 1u, &region);
913 
914 		// Record command if after.
915 		if (m_params.whenToSet == WhenToSet::AFTER)
916 			stateInfo.recorder(&vkd, cmdBuffer, statesData.back().get());
917 	}
918 
919 	const auto barrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
920 	vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &barrier, 0u, nullptr, 0u, nullptr);
921 
922 	endCommandBuffer(vkd, cmdBuffer);
923 	submitCommandsAndWait(vkd, device, queue, cmdBuffer);
924 
925 	// Invalidate alloc and check destination buffer.
926 	auto& dstBufferAlloc = dstBuffer.getAllocation();
927 	invalidateAlloc(vkd, device, dstBufferAlloc);
928 
929 	decltype(srcValues) results (srcValues.size());
930 	deMemcpy(results.data(), dstBufferAlloc.getHostPtr(), de::dataSize(srcValues));
931 
932 	for (size_t valueIdx = 0; valueIdx < srcValues.size(); ++valueIdx)
933 	{
934 		const auto& orig	= srcValues[valueIdx];
935 		const auto& res		= results[valueIdx];
936 
937 		if (orig != res)
938 		{
939 			std::ostringstream msg;
940 			msg << "Unexpected value found in destination buffer at position " << valueIdx << " (found=" << res << " expected=" << orig << ")";
941 			TCU_FAIL(msg.str());
942 		}
943 	}
944 
945 	return tcu::TestStatus::pass("Pass");
946 }
947 
iterateCompute(void)948 tcu::TestStatus DynamicStateComputeInstance::iterateCompute (void)
949 {
950 	const auto&	vki			= m_context.getInstanceInterface();
951 	const auto	phyDev		= m_context.getPhysicalDevice();
952 	auto&		devHelper	= getDeviceHelper(m_context, m_params.states.at(0));
953 	const auto&	vkd			= devHelper.getDeviceInterface();
954 	const auto	device		= devHelper.getDevice();
955 	const auto	qIndex		= devHelper.getQueueFamilyIndex();
956 	const auto	queue		= devHelper.getQueue();
957 	auto&		alloc		= devHelper.getAllocator();
958 
959 	const auto	cmdPool			= makeCommandPool(vkd, device, qIndex);
960 	const auto	cmdBufferPtr	= allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
961 	const auto	cmdBuffer		= cmdBufferPtr.get();
962 
963 	DescriptorSetLayoutBuilder setLayoutBuilder;
964 	setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT);
965 	const auto	setLayout		= setLayoutBuilder.build(vkd, device);
966 
967 	// Push constants.
968 	const deUint32	pcSize		= static_cast<deUint32>(sizeof(deUint32));
969 	const auto		pcRange		= makePushConstantRange(VK_SHADER_STAGE_COMPUTE_BIT, 0u, pcSize);
970 
971 	// Pipeline.
972 	const VkPipelineLayoutCreateInfo layoutInfo =
973 	{
974 		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,	//	VkStructureType					sType;
975 		nullptr,										//	const void*						pNext;
976 		0u,												//	VkPipelineLayoutCreateFlags		flags;
977 		1u,												//	deUint32						setLayoutCount;
978 		&setLayout.get(),								//	const VkDescriptorSetLayout*	pSetLayouts;
979 		1u,												//	deUint32						pushConstantRangeCount;
980 		&pcRange,										//	const VkPushConstantRange*		pPushConstantRanges;
981 	};
982 	const auto pipelineLayout = createPipelineLayout(vkd, device, &layoutInfo);
983 
984 	const auto shaderModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("comp"), 0u);
985 
986 	const VkPipelineShaderStageCreateInfo shaderStageInfo =
987 	{
988 		VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	//	VkStructureType						sType;
989 		nullptr,												//	const void*							pNext;
990 		0u,														//	VkPipelineShaderStageCreateFlags	flags;
991 		VK_SHADER_STAGE_COMPUTE_BIT,							//	VkShaderStageFlagBits				stage;
992 		shaderModule.get(),										//	VkShaderModule						module;
993 		"main",													//	const char*							pName;
994 		nullptr,												//	const VkSpecializationInfo*			pSpecializationInfo;
995 	};
996 
997 	const VkComputePipelineCreateInfo pipelineInfo =
998 	{
999 		VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,	//	VkStructureType					sType;
1000 		nullptr,										//	const void*						pNext;
1001 		0u,												//	VkPipelineCreateFlags			flags;
1002 		shaderStageInfo,								//	VkPipelineShaderStageCreateInfo	stage;
1003 		pipelineLayout.get(),							//	VkPipelineLayout				layout;
1004 		DE_NULL,										//	VkPipeline						basePipelineHandle;
1005 		0,												//	deInt32							basePipelineIndex;
1006 	};
1007 	const auto pipeline = createComputePipeline(vkd, device, DE_NULL, &pipelineInfo);
1008 
1009 	DE_ASSERT(!m_params.states.empty());
1010 
1011 	// Output buffer with one value per state.
1012 	std::vector<deUint32>	bufferData			(m_params.states.size(), 0u);
1013 	const auto				dataSize			(de::dataSize(bufferData));
1014 	const auto				outputBufferSize	= de::roundUp(static_cast<VkDeviceSize>(dataSize), getPhysicalDeviceProperties(vki, phyDev).limits.nonCoherentAtomSize);
1015 	const auto				bufferCreateInfo	= makeBufferCreateInfo(outputBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
1016 
1017 	BufferWithMemory		outputBuffer		(vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible);
1018 	auto&					outputBufferAlloc	= outputBuffer.getAllocation();
1019 	auto					outputBufferPtr		= outputBufferAlloc.getHostPtr();
1020 
1021 	deMemcpy(outputBufferPtr, bufferData.data(), dataSize);
1022 	flushAlloc(vkd, device, outputBufferAlloc);
1023 
1024 	// Descriptor set.
1025 	DescriptorPoolBuilder poolBuilder;
1026 	poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
1027 	const auto descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1028 
1029 	const auto descriptorSet = makeDescriptorSet(vkd, device, descriptorPool.get(), setLayout.get());
1030 
1031 	const auto bufferInfo = makeDescriptorBufferInfo(outputBuffer.get(), 0ull, outputBufferSize);
1032 	DescriptorSetUpdateBuilder updateBuilder;
1033 	updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &bufferInfo);
1034 	updateBuilder.update(vkd, device);
1035 
1036 	// Record and submit.
1037 	beginCommandBuffer(vkd, cmdBuffer);
1038 
1039 	// We need to preserve dynamic state data until the command buffer has run.
1040 	std::vector<de::MovePtr<DynamicStateData>> statesData;
1041 
1042 	for (size_t stateIdx = 0; stateIdx < m_params.states.size(); ++stateIdx)
1043 	{
1044 		// Objects needed to set the dynamic state.
1045 		auto		state		= m_params.states[stateIdx];
1046 		if (vk::isConstructionTypeShaderObject(m_pipelineConstructionType))
1047 		{
1048 			if (state == vk::VK_DYNAMIC_STATE_VIEWPORT)
1049 				state = vk::VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT;
1050 			if (state == vk::VK_DYNAMIC_STATE_SCISSOR)
1051 				state = vk::VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT;
1052 		}
1053 
1054 		const auto	stateInfo	= getDynamicStateInfo(state);
1055 		statesData.push_back(getDynamicStateData(m_context, device, state, m_pipelineConstructionType));
1056 
1057 		if (m_params.whenToSet == WhenToSet::BEFORE)
1058 			stateInfo.recorder(&vkd, cmdBuffer, statesData.back().get());
1059 
1060 		vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.get());
1061 		vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr);
1062 		{
1063 			// Each state will write to a different buffer position.
1064 			const deUint32 pcData = static_cast<deUint32>(stateIdx);
1065 			vkd.cmdPushConstants(cmdBuffer, pipelineLayout.get(), VK_SHADER_STAGE_COMPUTE_BIT, 0u, pcSize, &pcData);
1066 		}
1067 		vkd.cmdDispatch(cmdBuffer, 1u, 1u, 1u);
1068 
1069 		if (m_params.whenToSet == WhenToSet::AFTER)
1070 			stateInfo.recorder(&vkd, cmdBuffer, statesData.back().get());
1071 	}
1072 
1073 	// Barrier to read buffer contents.
1074 	const auto barrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
1075 	vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &barrier, 0u, nullptr, 0u, nullptr);
1076 
1077 	endCommandBuffer(vkd, cmdBuffer);
1078 	submitCommandsAndWait(vkd, device, queue, cmdBuffer);
1079 
1080 	// Read and verify buffer contents.
1081 	invalidateAlloc(vkd, device, outputBufferAlloc);
1082 	deMemcpy(bufferData.data(), outputBufferPtr, dataSize);
1083 
1084 	for (size_t idx = 0u; idx < bufferData.size(); ++idx)
1085 	{
1086 		if (bufferData[idx] != 1u)
1087 		{
1088 			std::ostringstream msg;
1089 			msg << "Unexpected value found at buffer position " << idx << ": " << bufferData[idx];
1090 			TCU_FAIL(msg.str());
1091 		}
1092 	}
1093 
1094 	return tcu::TestStatus::pass("Pass");
1095 }
1096 
getDynamicStateBriefName(VkDynamicState state)1097 std::string getDynamicStateBriefName (VkDynamicState state)
1098 {
1099 	const auto fullName		= de::toString(state);
1100 	const auto prefixLen	= strlen("VK_DYNAMIC_STATE_");
1101 
1102 	return de::toLower(fullName.substr(prefixLen));
1103 }
1104 
1105 } // anonymous
1106 
createDynamicStateComputeTests(tcu::TestContext & testCtx,vk::PipelineConstructionType pipelineConstructionType)1107 tcu::TestCaseGroup* createDynamicStateComputeTests (tcu::TestContext& testCtx, vk::PipelineConstructionType pipelineConstructionType)
1108 {
1109 	using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
1110 
1111 	// Dynamic state mixed with compute and transfer operations
1112 	GroupPtr mainGroup(new tcu::TestCaseGroup(testCtx, "compute_transfer"));
1113 
1114 	const struct
1115 	{
1116 		OperType	operationType;
1117 		const char*	name;
1118 	} operations[] =
1119 	{
1120 		{	OperType::COMPUTE,	"compute"	},
1121 		{	OperType::TRANSFER,	"transfer"	},
1122 	};
1123 
1124 	const struct
1125 	{
1126 		WhenToSet	when;
1127 		const char*	name;
1128 	} moments[] =
1129 	{
1130 		{	WhenToSet::BEFORE,	"before"	},
1131 		{	WhenToSet::AFTER,	"after"		},
1132 	};
1133 
1134 	// Tests with a single dynamic state.
1135 	{
1136 		GroupPtr singleStateGroup(new tcu::TestCaseGroup(testCtx, "single"));
1137 
1138 		for (int operIdx = 0; operIdx < DE_LENGTH_OF_ARRAY(operations); ++operIdx)
1139 		{
1140 			GroupPtr operationGroup(new tcu::TestCaseGroup(testCtx, operations[operIdx].name));
1141 
1142 			for (int stateIdx = 0; stateIdx < DE_LENGTH_OF_ARRAY(dynamicStateList); ++stateIdx)
1143 			{
1144 				const auto	state		= dynamicStateList[stateIdx];
1145 				const auto	stateName	= getDynamicStateBriefName(state);
1146 
1147 				GroupPtr stateGroup(new tcu::TestCaseGroup(testCtx, stateName.c_str()));
1148 
1149 				for (int momentIdx = 0; momentIdx < DE_LENGTH_OF_ARRAY(moments); ++momentIdx)
1150 				{
1151 					const TestParams testParams =
1152 					{
1153 						operations[operIdx].operationType,		//	OperType					operationType;
1154 						moments[momentIdx].when,				//	WhenToSet					whenToSet;
1155 						std::vector<VkDynamicState>(1, state),	//	std::vector<VkDynamicState>	state;
1156 					};
1157 
1158 					stateGroup->addChild(new DynamicStateComputeCase(testCtx, moments[momentIdx].name, testParams, pipelineConstructionType));
1159 				}
1160 
1161 				operationGroup->addChild(stateGroup.release());
1162 			}
1163 
1164 			singleStateGroup->addChild(operationGroup.release());
1165 		}
1166 
1167 		mainGroup->addChild(singleStateGroup.release());
1168 	}
1169 
1170 	// A few tests with several dynamic states.
1171 	{
1172 		GroupPtr multiStateGroup(new tcu::TestCaseGroup(testCtx, "multi"));
1173 
1174 		for (int operIdx = 0; operIdx < DE_LENGTH_OF_ARRAY(operations); ++operIdx)
1175 		{
1176 			GroupPtr operationGroup(new tcu::TestCaseGroup(testCtx, operations[operIdx].name));
1177 
1178 			for (int momentIdx = 0; momentIdx < DE_LENGTH_OF_ARRAY(moments); ++momentIdx)
1179 			{
1180 				TestParams testParams =
1181 				{
1182 					operations[operIdx].operationType,	//	OperType					operationType;
1183 					moments[momentIdx].when,			//	WhenToSet					whenToSet;
1184 					std::vector<VkDynamicState>(),		//	std::vector<VkDynamicState>	states;
1185 				};
1186 
1187 				// Use the basic states so as not to introduce extra requirements.
1188 				for (int stateIdx = 0; stateIdx < DE_LENGTH_OF_ARRAY(dynamicStateList); ++stateIdx)
1189 				{
1190 					testParams.states.push_back(dynamicStateList[stateIdx]);
1191 					if (dynamicStateList[stateIdx] == VK_DYNAMIC_STATE_STENCIL_REFERENCE)
1192 						break;
1193 				}
1194 
1195 				operationGroup->addChild(new DynamicStateComputeCase(testCtx, moments[momentIdx].name, testParams, pipelineConstructionType));
1196 			}
1197 
1198 			multiStateGroup->addChild(operationGroup.release());
1199 		}
1200 
1201 		mainGroup->addChild(multiStateGroup.release());
1202 	}
1203 
1204 	return mainGroup.release();
1205 }
1206 
cleanupDevice()1207 void cleanupDevice()
1208 {
1209 	g_shadingRateDeviceHelper.reset(nullptr);
1210 	g_contextDeviceHelper.reset(nullptr);
1211 }
1212 
1213 } // DynamicState
1214 } // vkt
1215