• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2023 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief DYnamic State Line Width Tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktDynamicStateLineWidthTests.hpp"
25 #include "vktDynamicStateBaseClass.hpp"
26 #include "vkTypeUtil.hpp"
27 #include "vkObjUtil.hpp"
28 #include "vkBufferWithMemory.hpp"
29 #include "vkImageWithMemory.hpp"
30 #include "vkImageUtil.hpp"
31 #include "vkCmdUtil.hpp"
32 #include "vkBarrierUtil.hpp"
33 
34 #include <array>
35 #include <functional>
36 #include <sstream>
37 
38 using namespace vk;
39 
40 namespace vkt
41 {
42 namespace DynamicState
43 {
44 namespace
45 {
46 struct TestLineWidthParams
47 {
48 	VkPrimitiveTopology	staticTopo;
49 	VkPrimitiveTopology	dynamicTopo;
50 	deUint32			staticWidth;
51 	deUint32			dynamicWidth;
52 	bool				dynamicFirst;
53 	VkFormat			format;
54 	deUint32			width;
55 	deUint32			height;
56 	std::string	rep () const;
57 };
58 
59 struct LineWidthInstance : public DynamicStateBaseClass
60 {
LineWidthInstancevkt::DynamicState::__anon229200890111::LineWidthInstance61 									LineWidthInstance		(Context&					context,
62 															 PipelineConstructionType	pipelineConstructionType,
63 															 const TestLineWidthParams&	params)
64 										: DynamicStateBaseClass(context, pipelineConstructionType, "vert", "frag")
65 										, m_params	(params) { /* Intentionally empty */ }
66 	de::MovePtr<BufferWithMemory>	buildVertices			(VkPrimitiveTopology		lineTopology,
67 															 bool						horizontal,
68 															 deUint32*					vertexCount);
69 	Move<VkRenderPass>				buildRenderPass			(VkFormat					format);
70 	void							beginColorRenderPass	(VkCommandBuffer			commandBuffer,
71 															 VkRenderPass				renderPass,
72 															 VkFramebuffer				framebuffer,
73 															 const deUint32				width,
74 															 const deUint32				height);
75 	de::MovePtr<ImageWithMemory>	buildImage				(VkFormat					format,
76 															 deUint32					width,
77 															 deUint32					height);
78 	Move<VkImageView>				buildView				(const VkImage				image,
79 															 VkFormat					format);
80 	Move<VkPipeline>				buildPipeline			(VkPrimitiveTopology		lineTopology,
81 															 float						lineWidth,
82 															 bool						dynamic,
83 															 deUint32					subpass,
84 															 VkPipelineLayout			layout,
85 															 VkShaderModule				vertexModule,
86 															 VkShaderModule				fragmentModule,
87 															 VkRenderPass				renderPass,
88 															 deUint32					width,
89 															 deUint32					height);
90 	tcu::TestStatus iterate									() override;
91 	bool							verifyResults			(const BufferWithMemory&	resultBuffer,
92 															 const tcu::Vec4&			dynamicColor,
93 															 const tcu::Vec4&			staticColor,
94 															 const VkFormat				format,
95 															 const deUint32				width,
96 															 const deUint32				height,
97 															 const deUint32				dynamicWidth,
98 															 const deUint32				staticWidth);
99 private:
100 	const TestLineWidthParams	m_params;
101 };
102 
103 template<class T, class P = T(*)[1], class R = decltype(std::begin(*std::declval<P>()))>
makeStdBeginEnd(void * p,deUint32 n)104 auto makeStdBeginEnd(void* p, deUint32 n) -> std::pair<R, R>
105 {
106 	auto tmp = std::begin(*P(p));
107 	auto begin = tmp;
108 	std::advance(tmp, n);
109 	return { begin, tmp };
110 }
111 
buildVertices(VkPrimitiveTopology lineTopology,bool horizontal,deUint32 * vertexCount)112 de::MovePtr<BufferWithMemory> LineWidthInstance::buildVertices (VkPrimitiveTopology	lineTopology,
113 																bool				horizontal,
114 																deUint32*			vertexCount)
115 {
116 	typedef tcu::Vec4	ElementType;
117 	std::vector<ElementType>	vertices;
118 	if (lineTopology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST)
119 	{
120 		if (horizontal) {
121 			vertices.emplace_back(-1,0,0,0);
122 			vertices.emplace_back(0,0,0,0);
123 			vertices.emplace_back(0,0,0,0);
124 			vertices.emplace_back(+1,0,0,0);
125 		} else {
126 			vertices.emplace_back(0,-1,0,0);
127 			vertices.emplace_back(0,0,0,0);
128 			vertices.emplace_back(0,0,0,0);
129 			vertices.emplace_back(0,+1,0,0);
130 		}
131 	}
132 	else if (lineTopology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP)
133 	{
134 		if (horizontal) {
135 			vertices.emplace_back(-1,0,0,0);
136 			vertices.emplace_back(0,0,0,0);
137 			vertices.emplace_back(+1,0,0,0);
138 		} else {
139 			vertices.emplace_back(0,-1,0,0);
140 			vertices.emplace_back(0,0,0,0);
141 			vertices.emplace_back(0,+1,0,0);
142 		}
143 	}
144 	else { DE_ASSERT(VK_FALSE); }
145 	const VkBufferCreateInfo	createInfo	= makeBufferCreateInfo(vertices.size() * sizeof(ElementType), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
146 	BufferWithMemory*			pBuffer		= new BufferWithMemory(m_context.getDeviceInterface(), m_context.getDevice(),
147 																   m_context.getDefaultAllocator(), createInfo,
148 																   (MemoryRequirement::HostVisible | MemoryRequirement::Coherent));
149 	DE_ASSERT(vertexCount);
150 	*vertexCount = static_cast<deUint32>(vertices.size());
151 	auto range = makeStdBeginEnd<ElementType>(pBuffer->getAllocation().getHostPtr(), *vertexCount);
152 	std::copy(vertices.begin(), vertices.end(), range.first);
153 
154 	return de::MovePtr<BufferWithMemory>(pBuffer);
155 }
156 
buildRenderPass(VkFormat format)157 Move<VkRenderPass> LineWidthInstance::buildRenderPass (VkFormat format)
158 {
159 	VkAttachmentDescription desc{};
160 	desc.flags			= VkAttachmentDescriptionFlags(0);
161 	desc.format			= format;
162 	desc.samples		= VK_SAMPLE_COUNT_1_BIT;
163 	desc.loadOp			= VK_ATTACHMENT_LOAD_OP_CLEAR;
164 	desc.storeOp		= VK_ATTACHMENT_STORE_OP_STORE;
165 	desc.stencilLoadOp	= VK_ATTACHMENT_LOAD_OP_DONT_CARE;
166 	desc.stencilStoreOp	= VK_ATTACHMENT_STORE_OP_DONT_CARE;
167 	desc.initialLayout	= VK_IMAGE_LAYOUT_UNDEFINED;
168 	desc.finalLayout	= VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
169 
170 	VkAttachmentReference ref{};
171 	ref.attachment	= 0u;
172 	ref.layout		= desc.finalLayout;
173 
174 	VkSubpassDescription subpassTemplate{};
175 	subpassTemplate.flags					= VkSubpassDescriptionFlags(0);
176 	subpassTemplate.pipelineBindPoint		= VK_PIPELINE_BIND_POINT_GRAPHICS;
177 	subpassTemplate.colorAttachmentCount	= 1u;
178 	subpassTemplate.pColorAttachments		= &ref;
179 	subpassTemplate.pDepthStencilAttachment	= nullptr;
180 	subpassTemplate.inputAttachmentCount	= 0;
181 	subpassTemplate.pInputAttachments		= nullptr;
182 	subpassTemplate.preserveAttachmentCount	= 0;
183 	subpassTemplate.pPreserveAttachments	= nullptr;
184 	subpassTemplate.pResolveAttachments		= nullptr;
185 
186 	std::array<VkSubpassDescription, 2> subpasses { subpassTemplate, subpassTemplate };
187 
188 	VkSubpassDependency	dependency{};
189 	dependency.srcSubpass		= 0u;
190 	dependency.dstSubpass		= 1u;
191 	dependency.srcAccessMask	= VK_ACCESS_MEMORY_WRITE_BIT;
192 	dependency.dstAccessMask	= VK_ACCESS_MEMORY_READ_BIT;
193 	dependency.srcStageMask		= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
194 	dependency.dstStageMask		= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
195 
196 	VkRenderPassCreateInfo renderPassInfo = initVulkanStructure();
197 	renderPassInfo.attachmentCount	= 1u;
198 	renderPassInfo.pAttachments		= &desc;
199 	renderPassInfo.subpassCount		= 2u;
200 	renderPassInfo.pSubpasses		= subpasses.data();
201 	renderPassInfo.dependencyCount	= 1u;
202 	renderPassInfo.pDependencies	= &dependency;
203 
204 	return createRenderPass(m_context.getDeviceInterface(), m_context.getDevice(), &renderPassInfo, nullptr);
205 }
206 
beginColorRenderPass(VkCommandBuffer commandBuffer,VkRenderPass renderPass,VkFramebuffer framebuffer,const deUint32 width,const deUint32 height)207 void LineWidthInstance::beginColorRenderPass (VkCommandBuffer		commandBuffer,
208 											  VkRenderPass			renderPass,
209 											  VkFramebuffer			framebuffer,
210 											  const deUint32		width,
211 											  const deUint32		height)
212 {
213 	const VkClearValue clearColor { { { 0.f, 0.f, 0.f, 0.f } } };
214 	const VkRenderPassBeginInfo	renderPassBeginInfo	=
215 	{
216 		VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,	// VkStructureType         sType;
217 		nullptr,									// const void*             pNext;
218 		renderPass,									// VkRenderPass            renderPass;
219 		framebuffer,								// VkFramebuffer           framebuffer;
220 		makeRect2D(width, height),					// VkRect2D                renderArea;
221 		1u,											// deUint32                clearValueCount;
222 		&clearColor									// const VkClearValue*     pClearValues;
223 	};
224 	m_context.getDeviceInterface()
225 			.cmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
226 }
227 
buildImage(VkFormat format,deUint32 width,deUint32 height)228 de::MovePtr<ImageWithMemory> LineWidthInstance::buildImage (VkFormat format, deUint32 width, deUint32 height)
229 {
230 	VkImageCreateInfo createInfo = initVulkanStructure();
231 	createInfo.flags					= VkImageCreateFlags(0);
232 	createInfo.imageType				= VK_IMAGE_TYPE_2D;
233 	createInfo.format					= format;
234 	createInfo.extent					= makeExtent3D(width, height, 1u);
235 	createInfo.mipLevels				= 1u;
236 	createInfo.arrayLayers				= 1u;
237 	createInfo.samples					= VK_SAMPLE_COUNT_1_BIT;
238 	createInfo.tiling					= VK_IMAGE_TILING_OPTIMAL;
239 	createInfo.usage					= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
240 											| VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
241 	createInfo.sharingMode				= VK_SHARING_MODE_EXCLUSIVE;
242 	createInfo.queueFamilyIndexCount	= 0u;
243 	createInfo.pQueueFamilyIndices		= nullptr;
244 	createInfo.initialLayout			= VK_IMAGE_LAYOUT_UNDEFINED;
245 
246 	return de::MovePtr<ImageWithMemory>(new ImageWithMemory(m_context.getDeviceInterface(),
247 															m_context.getDevice(),
248 															m_context.getDefaultAllocator(),
249 															createInfo,
250 															MemoryRequirement::Any));
251 }
252 
buildView(const VkImage image,VkFormat format)253 Move<VkImageView> LineWidthInstance::buildView (const VkImage image, VkFormat format)
254 {
255 	return makeImageView(m_context.getDeviceInterface(),
256 						 m_context.getDevice(),
257 						 image,
258 						 VK_IMAGE_VIEW_TYPE_2D,
259 						 format,
260 						 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u),
261 						 nullptr);
262 }
263 
buildPipeline(VkPrimitiveTopology lineTopology,float lineWidth,bool dynamic,deUint32 subpass,VkPipelineLayout layout,VkShaderModule vertexModule,VkShaderModule fragmentModule,VkRenderPass renderPass,deUint32 width,deUint32 height)264 Move<VkPipeline> LineWidthInstance::buildPipeline (VkPrimitiveTopology	lineTopology,
265 												   float				lineWidth,
266 												   bool					dynamic,
267 												   deUint32				subpass,
268 												   VkPipelineLayout		layout,
269 												   VkShaderModule		vertexModule,
270 												   VkShaderModule		fragmentModule,
271 												   VkRenderPass			renderPass,
272 												   deUint32				width,
273 												   deUint32				height)
274 {
275 	const std::vector<VkRect2D>			scissors			{ makeRect2D(width, height) };
276 	const std::vector<VkViewport>		viewports			{ makeViewport(0.f, 0.f, float(width), float(height), 0.f, 1.f) };
277 
278 	VkPipelineRasterizationStateCreateInfo rasterizationCreateInfo	= initVulkanStructure();
279 	rasterizationCreateInfo.lineWidth	= dynamic ? 0.0f : lineWidth;
280 
281 	const VkDynamicState dynamicStates[1] { VK_DYNAMIC_STATE_LINE_WIDTH };
282 	VkPipelineDynamicStateCreateInfo dynamicCreateInfo	= initVulkanStructure();
283 	dynamicCreateInfo.pDynamicStates	= dynamicStates;
284 	dynamicCreateInfo.dynamicStateCount	= 1u;
285 
286 	const auto attribute	= makeVertexInputAttributeDescription(0u, subpass, VK_FORMAT_R32G32B32A32_SFLOAT, 0u);
287 	const auto binding		= makeVertexInputBindingDescription(subpass, static_cast<deUint32>(sizeof(tcu::Vec4)), VK_VERTEX_INPUT_RATE_VERTEX);
288 	VkPipelineVertexInputStateCreateInfo inputCreateInfo = initVulkanStructure();
289 	inputCreateInfo.flags	= VkPipelineVertexInputStateCreateFlags(0);
290 	inputCreateInfo.vertexAttributeDescriptionCount	= 1u;
291 	inputCreateInfo.pVertexAttributeDescriptions	= &attribute;
292 	inputCreateInfo.vertexBindingDescriptionCount	= 1u;
293 	inputCreateInfo.pVertexBindingDescriptions		= &binding;
294 
295 	return makeGraphicsPipeline(m_context.getDeviceInterface(), m_context.getDevice(), layout,
296 								vertexModule, VkShaderModule(0), VkShaderModule(0), VkShaderModule(0), fragmentModule,
297 								renderPass, viewports, scissors, lineTopology, subpass,
298 								0u,			// patchControlPoints
299 								&inputCreateInfo,
300 								&rasterizationCreateInfo,
301 								nullptr,	// multisampleStateCreateInfo
302 								nullptr,	// depthStencilStateCreateInfo
303 								nullptr,	// colorBlendStateCreateInfo
304 								dynamic ? &dynamicCreateInfo : nullptr);
305 }
306 
verifyResults(const BufferWithMemory & resultBuffer,const tcu::Vec4 & dynamicColor,const tcu::Vec4 & staticColor,const VkFormat format,const deUint32 width,const deUint32 height,const deUint32 dynamicWidth,const deUint32 staticWidth)307 bool LineWidthInstance::verifyResults (const BufferWithMemory&	resultBuffer,
308 									   const tcu::Vec4&			dynamicColor,
309 									   const tcu::Vec4&			staticColor,
310 									   const VkFormat			format,
311 									   const deUint32			width,
312 									   const deUint32			height,
313 									   const deUint32			dynamicWidth,
314 									   const deUint32			staticWidth)
315 {
316 	tcu::ConstPixelBufferAccess	pixels(mapVkFormat(format), deInt32(width), deInt32(height), 1, resultBuffer.getAllocation().getHostPtr());
317 
318 	// count pixels in vertical line
319 	deUint32 staticLineWidth = 0u;
320 	for (deInt32 x = 0; x < deInt32(width); ++x)
321 	{
322 		if (pixels.getPixel(x, 0) == staticColor)
323 			++staticLineWidth;
324 	}
325 
326 	// count pixels in horizontal line
327 	deUint32 dynamicLineWidth = 0u;
328 	for (deInt32 y = 0; y < deInt32(height); ++y)
329 	{
330 		if (pixels.getPixel(0, y) == dynamicColor)
331 			++dynamicLineWidth;
332 	}
333 
334 	return ((dynamicWidth == dynamicLineWidth) && (staticWidth == staticLineWidth));
335 }
336 
iterate()337 tcu::TestStatus LineWidthInstance::iterate ()
338 {
339 	const DeviceInterface&			vkd				= m_context.getDeviceInterface();
340 	const VkDevice					device			= m_context.getDevice();
341 	Allocator&						allocator		= m_context.getDefaultAllocator();
342 	const deUint32					familyIndex		= m_context.getUniversalQueueFamilyIndex();
343 	const VkQueue					queue			= m_context.getUniversalQueue();
344 
345 	deUint32						dynamicVertCount(0);
346 	deUint32						staticVertCount	(0);
347 	Move<VkShaderModule>			vertex			= createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"));
348 	Move<VkShaderModule>			fragment		= createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"));
349 													// note that dynamic lines are always drawn horizontally
350 	de::MovePtr<BufferWithMemory>	dynamicVertices	= buildVertices(m_params.dynamicTopo, (m_params.dynamicFirst == true), &dynamicVertCount); DE_ASSERT(dynamicVertCount);
351 	de::MovePtr<BufferWithMemory>	staticVertices	= buildVertices(m_params.staticTopo, (m_params.dynamicFirst == false), &staticVertCount); DE_ASSERT(staticVertCount);
352 	const VkBuffer					dynamicBuffs[2]	{ **dynamicVertices, **staticVertices };
353 	const VkBuffer*					vertexBuffers	= dynamicBuffs;
354 	const VkDeviceSize				vertexOffsets[]	{ 0u, 0u };
355 	const tcu::Vec4					dynamicColor	(1, 0, 1, 1);
356 	const tcu::Vec4					staticColor		(0, 1, 0, 1);
357 	de::MovePtr<ImageWithMemory>	image			= buildImage(m_params.format, m_params.width, m_params.height);
358 	const VkImageMemoryBarrier		prepareCopy		= makeImageMemoryBarrier(
359 														VK_ACCESS_MEMORY_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
360 														VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
361 														**image, makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
362 	const VkBufferImageCopy			copyRegion		= makeBufferImageCopy(makeExtent3D(m_params.width, m_params.height, 1u),
363 														makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u));
364 	Move<VkImageView>				attachment		= buildView(**image, m_params.format);
365 	Move<VkRenderPass>				renderPass		= buildRenderPass(m_params.format);
366 	Move<VkFramebuffer>				framebuffer		= makeFramebuffer(vkd, device, *renderPass, *attachment, m_params.width, m_params.height);
367 	const VkDeviceSize				resultByteSize	= m_params.width * m_params.height * tcu::getPixelSize(mapVkFormat(m_params.format));
368 	const VkBufferCreateInfo		resultInfo		= makeBufferCreateInfo(resultByteSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
369 	de::MovePtr<BufferWithMemory>	resultBuffer	= de::MovePtr<BufferWithMemory>(new BufferWithMemory(vkd, device, allocator,
370 														resultInfo, MemoryRequirement::HostVisible | MemoryRequirement::Coherent));
371 	const VkPushConstantRange		pcRange			{ VK_SHADER_STAGE_FRAGMENT_BIT, 0u, static_cast<deUint32>(sizeof(tcu::Vec4)) };
372 	Move<VkPipelineLayout>			pipelineLayout	= makePipelineLayout(vkd, device, VK_NULL_HANDLE, &pcRange);
373 	Move<VkPipeline>				dynamicPipeline	= buildPipeline(m_params.dynamicTopo, float(m_params.dynamicWidth), true,
374 																	m_params.dynamicFirst ? 0u : 1u,
375 																	*pipelineLayout, *vertex, *fragment, *renderPass,
376 																	m_params.width, m_params.height);
377 	Move<VkPipeline>				staticPipeline	= buildPipeline(m_params.staticTopo, float(m_params.staticWidth), false,
378 																	m_params.dynamicFirst ? 1u : 0u,
379 																	*pipelineLayout, *vertex, *fragment, *renderPass,
380 																	m_params.width, m_params.height);
381 	Move<VkCommandPool>				cmdPool			= makeCommandPool(vkd, device, familyIndex);
382 	Move<VkCommandBuffer>			cmdBuffer		= allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
383 
384 	auto putDynamics	= [&]() -> void
385 	{
386 		vkd.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *dynamicPipeline);
387 		vkd.cmdPushConstants(*cmdBuffer, *pipelineLayout, pcRange.stageFlags, pcRange.offset, pcRange.size, &dynamicColor);
388 		vkd.cmdSetLineWidth(*cmdBuffer, float(m_params.dynamicWidth));
389 		vkd.cmdDraw(*cmdBuffer, dynamicVertCount, 1u, 0u, 0u);
390 	};
391 	std::function<void()> putDynamicsRecords(putDynamics);
392 	auto putStatics		= [&]() -> void
393 	{
394 		vkd.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *staticPipeline);
395 		vkd.cmdPushConstants(*cmdBuffer, *pipelineLayout, pcRange.stageFlags, pcRange.offset, pcRange.size, &staticColor);
396 		vkd.cmdDraw(*cmdBuffer, staticVertCount, 1u, 0u, 0u);
397 	};
398 	std::function<void()> putStaticsRecords(putStatics);
399 
400 	beginCommandBuffer(vkd, *cmdBuffer);
401 		vkd.cmdBindVertexBuffers(*cmdBuffer, 0u, 2u, vertexBuffers, vertexOffsets);
402 		beginColorRenderPass(*cmdBuffer, *renderPass, *framebuffer, m_params.width, m_params.height);
403 			(m_params.dynamicFirst ? putDynamicsRecords : putStaticsRecords)();
404 		vkd.cmdNextSubpass(*cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
405 			(m_params.dynamicFirst ? putStaticsRecords : putDynamicsRecords)();
406 		endRenderPass(vkd, *cmdBuffer);
407 		vkd.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
408 						   VK_DEPENDENCY_BY_REGION_BIT, 0u, nullptr, 0u, nullptr, 1u, &prepareCopy);
409 		vkd.cmdCopyImageToBuffer(*cmdBuffer, **image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **resultBuffer, 1u, &copyRegion);
410 	endCommandBuffer(vkd, *cmdBuffer);
411 	submitCommandsAndWait(vkd, device, queue, *cmdBuffer);
412 
413 	const bool status = verifyResults(*resultBuffer, dynamicColor, staticColor,
414 									  m_params.format, m_params.width, m_params.height,
415 									  m_params.dynamicWidth, m_params.staticWidth);
416 	return status ? tcu::TestStatus::pass(std::string()) : tcu::TestStatus::fail(std::string());
417 }
418 
419 struct LineWidthCase : public TestCase
420 {
LineWidthCasevkt::DynamicState::__anon229200890111::LineWidthCase421 					LineWidthCase	(tcu::TestContext&			testCtx,
422 									 const std::string&			name,
423 									 PipelineConstructionType	pipelineConstructionType,
424 									 const TestLineWidthParams&	params)
425 						: TestCase(testCtx, name)
426 						, m_pipelineConstructionType	(pipelineConstructionType)
427 						, m_params						(params) { /* Intentionally empty */ }
428 
429 	void			checkSupport	(Context&					context) const override;
430 	void			initPrograms	(SourceCollections&			programs) const override;
createInstancevkt::DynamicState::__anon229200890111::LineWidthCase431 	TestInstance*	createInstance	(Context&					context) const override {
432 										return new LineWidthInstance(context, m_pipelineConstructionType, m_params); }
433 private:
434 	const PipelineConstructionType	m_pipelineConstructionType;
435 	const TestLineWidthParams		m_params;
436 };
437 
initPrograms(SourceCollections & programs) const438 void LineWidthCase::initPrograms (SourceCollections& programs) const
439 {
440 	const std::string vert(
441 	R"glsl(#version 450
442 	layout(location = 0) in vec4 pos;
443 	void main() {
444 		gl_Position = vec4(pos.xy, 0.0, 1.0);
445 	})glsl");
446 
447 	const std::string frag(
448 	R"glsl(#version 450
449 	layout(push_constant) uniform PC { vec4 color; };
450 	layout(location = 0) out vec4 attachment;
451 	void main() {
452 		attachment = vec4(color.rgb, 1.0);
453 	})glsl");
454 
455 	programs.glslSources.add("frag") << glu::FragmentSource(frag);
456 	programs.glslSources.add("vert") << glu::VertexSource(vert);
457 }
458 
checkSupport(Context & context) const459 void LineWidthCase::checkSupport (Context& context) const
460 {
461 	VkPhysicalDeviceFeatures	fts	{};
462 	const InstanceInterface&	vki	= context.getInstanceInterface();
463 	const VkPhysicalDevice		dev	= context.getPhysicalDevice();
464 
465 	checkPipelineConstructionRequirements(vki, dev, m_pipelineConstructionType);
466 
467 	if (float(m_params.staticWidth) < context.getDeviceProperties().limits.lineWidthRange[0]
468 		|| float(m_params.staticWidth) > context.getDeviceProperties().limits.lineWidthRange[1]
469 		|| float(m_params.dynamicWidth) < context.getDeviceProperties().limits.lineWidthRange[0]
470 		|| float(m_params.dynamicWidth) > context.getDeviceProperties().limits.lineWidthRange[1])
471 	{
472 		TCU_THROW(NotSupportedError, "Line widths don't meet VkPhysicalDeviceLimits::lineWidthRange");
473 	}
474 
475 	vki.getPhysicalDeviceFeatures(dev, &fts);
476 	if (!context.getDeviceFeatures().wideLines)
477 	{
478 		TCU_THROW(NotSupportedError, "VkPhysicalDeviceFeatures::wideLines not supported");
479 	}
480 
481 	DE_ASSERT(context.getDeviceFeatures().wideLines);
482 }
483 
484 } // anonymous namespace
485 
486 // Test for VK_DYNAMIC_STATE_LINE_WIDTH
DynamicStateLWTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType)487 DynamicStateLWTests::DynamicStateLWTests (tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType)
488 	: tcu::TestCaseGroup	(testCtx, "line_width")
489 	, m_pipelineConstructionType	(pipelineConstructionType)
490 {
491 	/* Consciously empty */
492 }
493 
rep() const494 std::string TestLineWidthParams::rep () const
495 {
496 	auto topo = [](VkPrimitiveTopology topology) -> const char*	{
497 		switch (topology) {
498 			case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
499 				return "list";
500 			case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
501 				return "strip";
502 			default: DE_ASSERT(VK_FALSE);
503 		}
504 		return "";
505 	};
506 	std::ostringstream os;
507 	if (dynamicFirst)
508 		os << topo(dynamicTopo) << dynamicWidth << '_' << topo(staticTopo) << staticWidth;
509 	else
510 		os << topo(staticTopo) << staticWidth << '_' << topo(dynamicTopo) << dynamicWidth;
511 	os.flush();
512 	return os.str();
513 }
514 
init(void)515 void DynamicStateLWTests::init (void)
516 {
517 	TestLineWidthParams const params[] {
518 		{ VK_PRIMITIVE_TOPOLOGY_LINE_LIST,  VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, 0u, 0u, true,  VK_FORMAT_R32G32B32A32_SFLOAT, 128, 128 },
519 		{ VK_PRIMITIVE_TOPOLOGY_LINE_LIST,  VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, 0u, 0u, false, VK_FORMAT_R32G32B32A32_SFLOAT, 128, 128 },
520 		{ VK_PRIMITIVE_TOPOLOGY_LINE_LIST,  VK_PRIMITIVE_TOPOLOGY_LINE_LIST,  0u, 0u, true,  VK_FORMAT_R32G32B32A32_SFLOAT, 128, 128 },
521 		{ VK_PRIMITIVE_TOPOLOGY_LINE_LIST,  VK_PRIMITIVE_TOPOLOGY_LINE_LIST,  0u, 0u, false, VK_FORMAT_R32G32B32A32_SFLOAT, 128, 128 },
522 
523 		{ VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, VK_PRIMITIVE_TOPOLOGY_LINE_LIST,  0u, 0u, true,  VK_FORMAT_R32G32B32A32_SFLOAT, 128, 128 },
524 		{ VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, VK_PRIMITIVE_TOPOLOGY_LINE_LIST,  0u, 0u, false, VK_FORMAT_R32G32B32A32_SFLOAT, 128, 128 },
525 		{ VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, 0u, 0u, true,  VK_FORMAT_R32G32B32A32_SFLOAT, 128, 128 },
526 		{ VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, 0u, 0u, false, VK_FORMAT_R32G32B32A32_SFLOAT, 128, 128 },
527 	};
528 	de::MovePtr<tcu::TestCaseGroup>	dynaStatic(new tcu::TestCaseGroup(m_testCtx, "dyna_static"));
529 	de::MovePtr<tcu::TestCaseGroup>	staticDyna(new tcu::TestCaseGroup(m_testCtx, "static_dyna"));
530 	deUint32 lineWidth = 0u;
531 	for (const TestLineWidthParams& param : params)
532 	{
533 		TestLineWidthParams p(param);
534 		p.staticWidth	= ++lineWidth;
535 		p.dynamicWidth	= ++lineWidth;
536 		if (param.dynamicFirst)
537 			dynaStatic->addChild(new LineWidthCase(m_testCtx, p.rep(), m_pipelineConstructionType, p));
538 		else
539 			staticDyna->addChild(new LineWidthCase(m_testCtx, p.rep(), m_pipelineConstructionType, p));
540 	}
541 	addChild(dynaStatic.release());
542 	addChild(staticDyna.release());
543 }
544 
545 } // DynamicState
546 } // vkt
547