• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 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 Negative viewport height (part of VK_KHR_maintenance1)
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktDrawNegativeViewportHeightTests.hpp"
25 #include "vktDrawCreateInfoUtil.hpp"
26 #include "vktDrawImageObjectUtil.hpp"
27 #include "vktDrawBufferObjectUtil.hpp"
28 #include "vktTestGroupUtil.hpp"
29 #include "vktTestCaseUtil.hpp"
30 
31 #include "vkPrograms.hpp"
32 #include "vkTypeUtil.hpp"
33 #include "vkImageUtil.hpp"
34 #include "vkQueryUtil.hpp"
35 #include "vkCmdUtil.hpp"
36 
37 #include "tcuVector.hpp"
38 #include "tcuTextureUtil.hpp"
39 #include "tcuImageCompare.hpp"
40 #include "tcuTestLog.hpp"
41 
42 #include "deSharedPtr.hpp"
43 
44 namespace vkt
45 {
46 namespace Draw
47 {
48 namespace
49 {
50 using namespace vk;
51 using tcu::Vec4;
52 using de::SharedPtr;
53 using de::MovePtr;
54 
55 enum Constants
56 {
57 	WIDTH	= 256,
58 	HEIGHT	= WIDTH/2,
59 };
60 
61 struct TestParams
62 {
63 	VkFrontFace					frontFace;
64 	VkCullModeFlagBits			cullMode;
65 	bool						zeroViewportHeight;
66 	const SharedGroupParams		groupParams;
67 };
68 
69 class NegativeViewportHeightTestInstance : public TestInstance
70 {
71 public:
72 									NegativeViewportHeightTestInstance	(Context& context, const TestParams& params);
73 	tcu::TestStatus					iterate								(void);
74 	void							preRenderCommands					(VkCommandBuffer cmdBuffer, const VkClearValue& clearColor);
75 	void							draw								(VkCommandBuffer cmdBuffer, const VkViewport& viewport);
76 
77 	MovePtr<tcu::TextureLevel>		generateReferenceImage				(void) const;
78 	bool							isCulled							(const VkFrontFace triangleFace) const;
79 
80 #ifndef CTS_USES_VULKANSC
81 	void							beginSecondaryCmdBuffer				(VkCommandBuffer cmdBuffer, VkRenderingFlagsKHR renderingFlags = 0u);
82 #endif // CTS_USES_VULKANSC
83 
84 private:
85 	const TestParams				m_params;
86 	const VkFormat					m_colorAttachmentFormat;
87 	SharedPtr<Image>				m_colorTargetImage;
88 	Move<VkImageView>				m_colorTargetView;
89 	SharedPtr<Buffer>				m_vertexBuffer;
90 	Move<VkRenderPass>				m_renderPass;
91 	Move<VkFramebuffer>				m_framebuffer;
92 	Move<VkPipelineLayout>			m_pipelineLayout;
93 	Move<VkPipeline>				m_pipeline;
94 };
95 
NegativeViewportHeightTestInstance(Context & context,const TestParams & params)96 NegativeViewportHeightTestInstance::NegativeViewportHeightTestInstance (Context& context, const TestParams& params)
97 	: TestInstance				(context)
98 	, m_params					(params)
99 	, m_colorAttachmentFormat	(VK_FORMAT_R8G8B8A8_UNORM)
100 {
101 	const DeviceInterface&	vk		= m_context.getDeviceInterface();
102 	const VkDevice			device	= m_context.getDevice();
103 
104 	// Vertex data
105 	{
106 		std::vector<Vec4> vertexData;
107 
108 		// CCW triangle
109 		vertexData.push_back(Vec4(-0.8f, -0.6f, 0.0f, 1.0f));	//  0-----2
110 		vertexData.push_back(Vec4(-0.8f,  0.6f, 0.0f, 1.0f));	//   |  /
111 		vertexData.push_back(Vec4(-0.2f, -0.6f, 0.0f, 1.0f));	//  1|/
112 
113 		// CW triangle
114 		vertexData.push_back(Vec4( 0.2f, -0.6f, 0.0f, 1.0f));	//  0-----1
115 		vertexData.push_back(Vec4( 0.8f, -0.6f, 0.0f, 1.0f));	//    \  |
116 		vertexData.push_back(Vec4( 0.8f,  0.6f, 0.0f, 1.0f));	//      \|2
117 
118 		const VkDeviceSize dataSize = vertexData.size() * sizeof(Vec4);
119 		m_vertexBuffer = Buffer::createAndAlloc(vk, device, BufferCreateInfo(dataSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
120 												m_context.getDefaultAllocator(), MemoryRequirement::HostVisible);
121 
122 		deMemcpy(m_vertexBuffer->getBoundMemory().getHostPtr(), &vertexData[0], static_cast<std::size_t>(dataSize));
123 		flushMappedMemoryRange(vk, device, m_vertexBuffer->getBoundMemory().getMemory(), m_vertexBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
124 	}
125 
126 	const VkExtent3D		targetImageExtent		= { WIDTH, HEIGHT, 1 };
127 	const VkImageUsageFlags	targetImageUsageFlags	= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
128 
129 	const ImageCreateInfo	targetImageCreateInfo(
130 		VK_IMAGE_TYPE_2D,						// imageType,
131 		m_colorAttachmentFormat,				// format,
132 		targetImageExtent,						// extent,
133 		1u,										// mipLevels,
134 		1u,										// arrayLayers,
135 		VK_SAMPLE_COUNT_1_BIT,					// samples,
136 		VK_IMAGE_TILING_OPTIMAL,				// tiling,
137 		targetImageUsageFlags);					// usage,
138 
139 	m_colorTargetImage = Image::createAndAlloc(vk, device, targetImageCreateInfo, m_context.getDefaultAllocator(), m_context.getUniversalQueueFamilyIndex());
140 
141 	const ImageViewCreateInfo colorTargetViewInfo(m_colorTargetImage->object(), VK_IMAGE_VIEW_TYPE_2D, m_colorAttachmentFormat);
142 	m_colorTargetView = createImageView(vk, device, &colorTargetViewInfo);
143 
144 	// Render pass and framebuffer
145 	if (!m_params.groupParams->useDynamicRendering)
146 	{
147 		RenderPassCreateInfo	renderPassCreateInfo;
148 		renderPassCreateInfo.addAttachment(AttachmentDescription(
149 			m_colorAttachmentFormat,				// format
150 			VK_SAMPLE_COUNT_1_BIT,					// samples
151 			VK_ATTACHMENT_LOAD_OP_LOAD,				// loadOp
152 			VK_ATTACHMENT_STORE_OP_STORE,			// storeOp
153 			VK_ATTACHMENT_LOAD_OP_DONT_CARE,		// stencilLoadOp
154 			VK_ATTACHMENT_STORE_OP_DONT_CARE,		// stencilStoreOp
155 			VK_IMAGE_LAYOUT_GENERAL,				// initialLayout
156 			VK_IMAGE_LAYOUT_GENERAL));				// finalLayout
157 
158 		const VkAttachmentReference colorAttachmentReference =
159 		{
160 			0u,
161 			VK_IMAGE_LAYOUT_GENERAL
162 		};
163 
164 		renderPassCreateInfo.addSubpass(SubpassDescription(
165 			VK_PIPELINE_BIND_POINT_GRAPHICS,		// pipelineBindPoint
166 			(VkSubpassDescriptionFlags)0,			// flags
167 			0u,										// inputAttachmentCount
168 			DE_NULL,								// inputAttachments
169 			1u,										// colorAttachmentCount
170 			&colorAttachmentReference,				// colorAttachments
171 			DE_NULL,								// resolveAttachments
172 			AttachmentReference(),					// depthStencilAttachment
173 			0u,										// preserveAttachmentCount
174 			DE_NULL));								// preserveAttachments
175 
176 		m_renderPass = createRenderPass(vk, device, &renderPassCreateInfo);
177 
178 		std::vector<VkImageView>		colorAttachments		{ *m_colorTargetView };
179 		const FramebufferCreateInfo		framebufferCreateInfo	(*m_renderPass, colorAttachments, WIDTH, HEIGHT, 1);
180 		m_framebuffer = createFramebuffer(vk, device, &framebufferCreateInfo);
181 	}
182 
183 	// Vertex input
184 
185 	const VkVertexInputBindingDescription		vertexInputBindingDescription =
186 	{
187 		0u,										// uint32_t             binding;
188 		sizeof(Vec4),							// uint32_t             stride;
189 		VK_VERTEX_INPUT_RATE_VERTEX,			// VkVertexInputRate    inputRate;
190 	};
191 
192 	const VkVertexInputAttributeDescription		vertexInputAttributeDescription =
193 	{
194 		0u,										// uint32_t    location;
195 		0u,										// uint32_t    binding;
196 		VK_FORMAT_R32G32B32A32_SFLOAT,			// VkFormat    format;
197 		0u										// uint32_t    offset;
198 	};
199 
200 	const PipelineCreateInfo::VertexInputState	vertexInputState = PipelineCreateInfo::VertexInputState(1, &vertexInputBindingDescription,
201 																										1, &vertexInputAttributeDescription);
202 
203 	// Graphics pipeline
204 
205 	const VkRect2D scissor = makeRect2D(WIDTH, HEIGHT);
206 
207 	std::vector<VkDynamicState>		dynamicStates;
208 	dynamicStates.push_back(VK_DYNAMIC_STATE_VIEWPORT);
209 
210 	const Unique<VkShaderModule>	vertexModule	(createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0));
211 	const Unique<VkShaderModule>	fragmentModule	(createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0));
212 
213 	const PipelineLayoutCreateInfo	pipelineLayoutCreateInfo;
214 	m_pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
215 
216 	const PipelineCreateInfo::ColorBlendState::Attachment colorBlendAttachmentState;
217 
218 	PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, (VkPipelineCreateFlags)0);
219 	pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vertexModule,   "main", VK_SHADER_STAGE_VERTEX_BIT));
220 	pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fragmentModule, "main", VK_SHADER_STAGE_FRAGMENT_BIT));
221 	pipelineCreateInfo.addState (PipelineCreateInfo::VertexInputState	(vertexInputState));
222 	pipelineCreateInfo.addState (PipelineCreateInfo::InputAssemblerState(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
223 	pipelineCreateInfo.addState (PipelineCreateInfo::ColorBlendState	(1, &colorBlendAttachmentState));
224 	pipelineCreateInfo.addState (PipelineCreateInfo::ViewportState		(1, std::vector<VkViewport>(), std::vector<VkRect2D>(1, scissor)));
225 	pipelineCreateInfo.addState (PipelineCreateInfo::DepthStencilState	());
226 	pipelineCreateInfo.addState (PipelineCreateInfo::RasterizerState	(
227 		VK_FALSE,					// depthClampEnable
228 		VK_FALSE,					// rasterizerDiscardEnable
229 		VK_POLYGON_MODE_FILL,		// polygonMode
230 		m_params.cullMode,			// cullMode
231 		m_params.frontFace,			// frontFace
232 		VK_FALSE,					// depthBiasEnable
233 		0.0f,						// depthBiasConstantFactor
234 		0.0f,						// depthBiasClamp
235 		0.0f,						// depthBiasSlopeFactor
236 		1.0f));						// lineWidth
237 	pipelineCreateInfo.addState (PipelineCreateInfo::MultiSampleState	());
238 	pipelineCreateInfo.addState (PipelineCreateInfo::DynamicState		(dynamicStates));
239 
240 #ifndef CTS_USES_VULKANSC
241 	vk::VkPipelineRenderingCreateInfoKHR renderingCreateInfo
242 	{
243 		vk::VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
244 		DE_NULL,
245 		0u,
246 		1u,
247 		&m_colorAttachmentFormat,
248 		vk::VK_FORMAT_UNDEFINED,
249 		vk::VK_FORMAT_UNDEFINED
250 	};
251 
252 	if (m_params.groupParams->useDynamicRendering)
253 		pipelineCreateInfo.pNext = &renderingCreateInfo;
254 #endif // CTS_USES_VULKANSC
255 
256 	m_pipeline = createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
257 }
258 
preRenderCommands(VkCommandBuffer cmdBuffer,const VkClearValue & clearColor)259 void NegativeViewportHeightTestInstance::preRenderCommands(VkCommandBuffer cmdBuffer, const VkClearValue& clearColor)
260 {
261 	const DeviceInterface&		vk					= m_context.getDeviceInterface();
262 	const ImageSubresourceRange	subresourceRange	(VK_IMAGE_ASPECT_COLOR_BIT);
263 
264 	initialTransitionColor2DImage(vk, cmdBuffer, m_colorTargetImage->object(), VK_IMAGE_LAYOUT_GENERAL,
265 								  VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
266 	vk.cmdClearColorImage(cmdBuffer, m_colorTargetImage->object(), VK_IMAGE_LAYOUT_GENERAL, &clearColor.color, 1, &subresourceRange);
267 
268 	const VkMemoryBarrier memBarrier
269 	{
270 		VK_STRUCTURE_TYPE_MEMORY_BARRIER,												// VkStructureType		sType;
271 		DE_NULL,																		// const void*			pNext;
272 		VK_ACCESS_TRANSFER_WRITE_BIT,													// VkAccessFlags		srcAccessMask;
273 		VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT		// VkAccessFlags		dstAccessMask;
274 	};
275 
276 	vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 1, &memBarrier, 0, DE_NULL, 0, DE_NULL);
277 }
278 
draw(VkCommandBuffer cmdBuffer,const VkViewport & viewport)279 void NegativeViewportHeightTestInstance::draw (VkCommandBuffer cmdBuffer, const VkViewport& viewport)
280 {
281 	const DeviceInterface&	vk		= m_context.getDeviceInterface();
282 	const VkBuffer			buffer	= m_vertexBuffer->object();
283 	const VkDeviceSize		offset	= 0;
284 
285 	if (m_params.zeroViewportHeight)
286 	{
287 		// Set zero viewport height
288 		const VkViewport zeroViewportHeight
289 		{
290 			viewport.x,			// float    x;
291 			viewport.y / 2.0f,	// float    y;
292 			viewport.width,		// float    width;
293 			0.0f,				// float    height;
294 			viewport.minDepth,	// float    minDepth;
295 			viewport.maxDepth	// float    maxDepth;
296 		};
297 
298 		vk.cmdSetViewport(cmdBuffer, 0u, 1u, &zeroViewportHeight);
299 	}
300 	else
301 		vk.cmdSetViewport(cmdBuffer, 0u, 1u, &viewport);
302 
303 	vk.cmdBindVertexBuffers(cmdBuffer, 0, 1, &buffer, &offset);
304 	vk.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
305 	vk.cmdDraw(cmdBuffer, 6, 1, 0, 0);
306 }
307 
308 //! Determine if a triangle with triangleFace orientation will be culled or not
isCulled(const VkFrontFace triangleFace) const309 bool NegativeViewportHeightTestInstance::isCulled (const VkFrontFace triangleFace) const
310 {
311 	const bool isFrontFacing = (triangleFace == m_params.frontFace);
312 
313 	if (m_params.cullMode == VK_CULL_MODE_FRONT_BIT && isFrontFacing)
314 		return true;
315 	if (m_params.cullMode == VK_CULL_MODE_BACK_BIT  && !isFrontFacing)
316 		return true;
317 
318 	return m_params.cullMode == VK_CULL_MODE_FRONT_AND_BACK;
319 }
320 
generateReferenceImage(void) const321 MovePtr<tcu::TextureLevel> NegativeViewportHeightTestInstance::generateReferenceImage (void) const
322 {
323 	DE_ASSERT(HEIGHT == WIDTH/2);
324 
325 	MovePtr<tcu::TextureLevel>		image	(new tcu::TextureLevel(mapVkFormat(m_colorAttachmentFormat), WIDTH, HEIGHT));
326 	const tcu::PixelBufferAccess	access	(image->getAccess());
327 	const Vec4						blue	(0.125f, 0.25f, 0.5f, 1.0f);
328 	const Vec4						white	(1.0f);
329 	const Vec4						gray	(0.5f, 0.5f, 0.5f, 1.0f);
330 
331 	tcu::clear(access, blue);
332 
333 	// Zero viewport height
334 	if (m_params.zeroViewportHeight)
335 	{
336 		return image;
337 	}
338 	// Negative viewport height
339 	else
340 	{
341 		const int p1 =      static_cast<int>(static_cast<float>(HEIGHT) * (1.0f - 0.6f) / 2.0f);
342 		const int p2 = p1 + static_cast<int>(static_cast<float>(HEIGHT) * (2.0f * 0.6f) / 2.0f);
343 
344 		// left triangle (CCW -> CW after y-flip)
345 		if (!isCulled(VK_FRONT_FACE_CLOCKWISE))
346 		{
347 			const Vec4& color = (m_params.frontFace == VK_FRONT_FACE_CLOCKWISE ? white : gray);
348 
349 			for (int y = p1; y <= p2; ++y)
350 			for (int x = p1; x <  y;  ++x)
351 				access.setPixel(color, x, y);
352 		}
353 
354 		// right triangle (CW -> CCW after y-flip)
355 		if (!isCulled(VK_FRONT_FACE_COUNTER_CLOCKWISE))
356 		{
357 			const Vec4& color = (m_params.frontFace == VK_FRONT_FACE_COUNTER_CLOCKWISE ? white : gray);
358 
359 			for (int y = p1;        y <= p2;          ++y)
360 			for (int x = WIDTH - y; x <  p2 + HEIGHT; ++x)
361 				access.setPixel(color, x, y);
362 		}
363 
364 		return image;
365 	}
366 }
367 
368 #ifndef CTS_USES_VULKANSC
beginSecondaryCmdBuffer(VkCommandBuffer cmdBuffer,VkRenderingFlagsKHR renderingFlags)369 void NegativeViewportHeightTestInstance::beginSecondaryCmdBuffer(VkCommandBuffer cmdBuffer, VkRenderingFlagsKHR renderingFlags)
370 {
371 	VkCommandBufferInheritanceRenderingInfoKHR inheritanceRenderingInfo
372 	{
373 		VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR,		// VkStructureType					sType;
374 		DE_NULL,																// const void*						pNext;
375 		renderingFlags,															// VkRenderingFlagsKHR				flags;
376 		0u,																		// uint32_t							viewMask;
377 		1u,																		// uint32_t							colorAttachmentCount;
378 		&m_colorAttachmentFormat,												// const VkFormat*					pColorAttachmentFormats;
379 		VK_FORMAT_UNDEFINED,													// VkFormat							depthAttachmentFormat;
380 		VK_FORMAT_UNDEFINED,													// VkFormat							stencilAttachmentFormat;
381 		VK_SAMPLE_COUNT_1_BIT,													// VkSampleCountFlagBits			rasterizationSamples;
382 	};
383 	const VkCommandBufferInheritanceInfo bufferInheritanceInfo = initVulkanStructure(&inheritanceRenderingInfo);
384 
385 	VkCommandBufferUsageFlags usageFlags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
386 	if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
387 		usageFlags |= VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
388 
389 	const VkCommandBufferBeginInfo commandBufBeginParams
390 	{
391 		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,							// VkStructureType					sType;
392 		DE_NULL,																// const void*						pNext;
393 		usageFlags,																// VkCommandBufferUsageFlags		flags;
394 		&bufferInheritanceInfo
395 	};
396 
397 	const DeviceInterface& vk = m_context.getDeviceInterface();
398 	VK_CHECK(vk.beginCommandBuffer(cmdBuffer, &commandBufBeginParams));
399 }
400 #endif // CTS_USES_VULKANSC
401 
getCullModeStr(const VkCullModeFlagBits cullMode)402 std::string getCullModeStr (const VkCullModeFlagBits cullMode)
403 {
404 	// Cull mode flags are a bit special, because there's a meaning to 0 and or'ed flags.
405 	// The function getCullModeFlagsStr() doesn't work too well in this case.
406 
407 	switch (cullMode)
408 	{
409 		case VK_CULL_MODE_NONE:				return "VK_CULL_MODE_NONE";
410 		case VK_CULL_MODE_FRONT_BIT:		return "VK_CULL_MODE_FRONT_BIT";
411 		case VK_CULL_MODE_BACK_BIT:			return "VK_CULL_MODE_BACK_BIT";
412 		case VK_CULL_MODE_FRONT_AND_BACK:	return "VK_CULL_MODE_FRONT_AND_BACK";
413 
414 		default:
415 			DE_ASSERT(0);
416 			return std::string();
417 	}
418 }
419 
iterate(void)420 tcu::TestStatus NegativeViewportHeightTestInstance::iterate (void)
421 {
422 	// Set up the viewport and draw
423 
424 	const VkViewport viewport
425 	{
426 		0.0f,							// float    x;
427 		static_cast<float>(HEIGHT),		// float    y;
428 		static_cast<float>(WIDTH),		// float    width;
429 		-static_cast<float>(HEIGHT),	// float    height;
430 		0.0f,							// float    minDepth;
431 		1.0f,							// float    maxDepth;
432 	};
433 	VkRect2D rect = makeRect2D(0, 0, WIDTH, HEIGHT);
434 
435 	const DeviceInterface&			vk					= m_context.getDeviceInterface();
436 	const VkDevice					device				= m_context.getDevice();
437 	const VkQueue					queue				= m_context.getUniversalQueue();
438 	const deUint32					queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
439 	const VkClearValue				clearColor			= makeClearValueColorF32(0.125f, 0.25f, 0.5f, 1.0f);
440 	const CmdPoolCreateInfo			cmdPoolCreateInfo	(queueFamilyIndex);
441 	const Unique<VkCommandPool>		cmdPool				(createCommandPool(vk, device, &cmdPoolCreateInfo));
442 	const Unique<VkCommandBuffer>	cmdBuffer			(allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
443 	Move<VkCommandBuffer>			secCmdBuffer;
444 
445 #ifndef CTS_USES_VULKANSC
446 	if (m_params.groupParams->useSecondaryCmdBuffer)
447 	{
448 		secCmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
449 
450 		// record secondary command buffer
451 		if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
452 		{
453 			beginSecondaryCmdBuffer(*secCmdBuffer, VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
454 			beginRendering(vk, *secCmdBuffer, *m_colorTargetView, rect, clearColor, VK_IMAGE_LAYOUT_GENERAL, VK_ATTACHMENT_LOAD_OP_LOAD, 0u);
455 		}
456 		else
457 			beginSecondaryCmdBuffer(*secCmdBuffer);
458 
459 		draw(*secCmdBuffer, viewport);
460 
461 		if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
462 			endRendering(vk, *secCmdBuffer);
463 
464 		endCommandBuffer(vk, *secCmdBuffer);
465 
466 		// record primary command buffer
467 		beginCommandBuffer(vk, *cmdBuffer, 0u);
468 
469 		preRenderCommands(*cmdBuffer, clearColor);
470 
471 		if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
472 			beginRendering(vk, *cmdBuffer, *m_colorTargetView, rect, clearColor, VK_IMAGE_LAYOUT_GENERAL, VK_ATTACHMENT_LOAD_OP_LOAD, VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
473 
474 		vk.cmdExecuteCommands(*cmdBuffer, 1u, &*secCmdBuffer);
475 
476 		if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
477 			endRendering(vk, *cmdBuffer);
478 
479 		endCommandBuffer(vk, *cmdBuffer);
480 	}
481 	else if (m_params.groupParams->useDynamicRendering)
482 	{
483 		beginCommandBuffer(vk, *cmdBuffer);
484 
485 		preRenderCommands(*cmdBuffer, clearColor);
486 		beginRendering(vk, *cmdBuffer, *m_colorTargetView, rect, clearColor, VK_IMAGE_LAYOUT_GENERAL, VK_ATTACHMENT_LOAD_OP_LOAD, 0u);
487 		draw(*cmdBuffer, viewport);
488 		endRendering(vk, *cmdBuffer);
489 
490 		endCommandBuffer(vk, *cmdBuffer);
491 	}
492 #endif // CTS_USES_VULKANSC
493 
494 	if (!m_params.groupParams->useDynamicRendering)
495 	{
496 		beginCommandBuffer(vk, *cmdBuffer);
497 
498 		preRenderCommands(*cmdBuffer, clearColor);
499 		beginRenderPass(vk, *cmdBuffer, *m_renderPass, *m_framebuffer, rect);
500 		draw(*cmdBuffer, viewport);
501 		endRenderPass(vk, *cmdBuffer);
502 
503 		endCommandBuffer(vk, *cmdBuffer);
504 	}
505 
506 	// Submit
507 	submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
508 
509 	// Get result
510 	const VkOffset3D					zeroOffset	= { 0, 0, 0 };
511 	const tcu::ConstPixelBufferAccess	resultImage	= m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, VK_IMAGE_ASPECT_COLOR_BIT);
512 
513 	// Verify the results
514 
515 	tcu::TestLog&				log				= m_context.getTestContext().getLog();
516 	MovePtr<tcu::TextureLevel>	referenceImage	= generateReferenceImage();
517 
518 	// Zero viewport height
519 	if (m_params.zeroViewportHeight)
520 	{
521 		log << tcu::TestLog::Message
522 			<< "Drawing two triangles with zero viewport height."
523 			<< tcu::TestLog::EndMessage;
524 		log << tcu::TestLog::Message
525 			<< "Result image should be empty."
526 			<< tcu::TestLog::EndMessage;
527 	}
528 	// Negative viewport height
529 	else
530 	{
531 		log << tcu::TestLog::Message
532 			<< "Drawing two triangles with negative viewport height, which will cause a y-flip. This changes the sign of the triangle's area."
533 			<< tcu::TestLog::EndMessage;
534 		log << tcu::TestLog::Message
535 			<< "After the flip, the triangle on the left is CW and the triangle on the right is CCW. Right angles of the both triangles should be at the bottom of the image."
536 			<< " Front face is white, back face is gray."
537 			<< tcu::TestLog::EndMessage;
538 	}
539 
540 	log << tcu::TestLog::Message
541 		<< "Front face: " << getFrontFaceName(m_params.frontFace) << "\n"
542 		<< "Cull mode: "  << getCullModeStr  (m_params.cullMode)  << "\n"
543 		<< tcu::TestLog::EndMessage;
544 
545 	if (!tcu::fuzzyCompare(log, "Image compare", "Image compare", referenceImage->getAccess(), resultImage, 0.02f, tcu::COMPARE_LOG_RESULT))
546 		return tcu::TestStatus::fail("Rendered image is incorrect");
547 	else
548 		return tcu::TestStatus::pass("Pass");
549 }
550 
551 class NegativeViewportHeightTest : public TestCase
552 {
553 public:
NegativeViewportHeightTest(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const TestParams & params)554 	NegativeViewportHeightTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params)
555 		: TestCase	(testCtx, name, description)
556 		, m_params	(params)
557 	{
558 	}
559 
initPrograms(SourceCollections & programCollection) const560 	void initPrograms (SourceCollections& programCollection) const
561 	{
562 		// Vertex shader
563 		{
564 			std::ostringstream src;
565 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
566 				<< "\n"
567 				<< "layout(location = 0) in vec4 in_position;\n"
568 				<< "\n"
569 				<< "out gl_PerVertex {\n"
570 				<< "    vec4  gl_Position;\n"
571 				<< "};\n"
572 				<< "\n"
573 				<< "void main(void)\n"
574 				<< "{\n"
575 				<< "    gl_Position = in_position;\n"
576 				<< "}\n";
577 
578 			programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
579 		}
580 
581 		// Fragment shader
582 		{
583 			std::ostringstream src;
584 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
585 				<< "\n"
586 				<< "layout(location = 0) out vec4 out_color;\n"
587 				<< "\n"
588 				<< "void main(void)\n"
589 				<< "{\n"
590 				<< "    if (gl_FrontFacing)\n"
591 				<< "        out_color = vec4(1.0);\n"
592 				<< "    else\n"
593 				<< "        out_color = vec4(vec3(0.5), 1.0);\n"
594 				<< "}\n";
595 
596 			programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
597 		}
598 	}
599 
checkSupport(Context & context) const600 	virtual void checkSupport (Context& context) const
601 	{
602 		if (m_params.groupParams->useDynamicRendering)
603 			context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
604 
605 		context.requireDeviceFunctionality("VK_KHR_maintenance1");
606 	}
607 
createInstance(Context & context) const608 	virtual TestInstance* createInstance (Context& context) const
609 	{
610 		return new NegativeViewportHeightTestInstance(context, m_params);
611 	}
612 
613 private:
614 	const TestParams	m_params;
615 };
616 
617 struct SubGroupParams
618 {
619 	bool					zeroViewportHeight;
620 	const SharedGroupParams	groupParams;
621 };
622 
populateTestGroup(tcu::TestCaseGroup * testGroup,SubGroupParams subGroupParams)623 void populateTestGroup (tcu::TestCaseGroup* testGroup, SubGroupParams subGroupParams)
624 {
625 	const struct
626 	{
627 		const char* const	name;
628 		VkFrontFace			frontFace;
629 	} frontFace[] =
630 	{
631 		{ "front_ccw",	VK_FRONT_FACE_COUNTER_CLOCKWISE	},
632 		{ "front_cw",	VK_FRONT_FACE_CLOCKWISE			},
633 	};
634 
635 	const struct
636 	{
637 		const char* const	name;
638 		VkCullModeFlagBits	cullMode;
639 	} cullMode[] =
640 	{
641 		{ "cull_none",	VK_CULL_MODE_NONE			},
642 		{ "cull_front",	VK_CULL_MODE_FRONT_BIT		},
643 		{ "cull_back",	VK_CULL_MODE_BACK_BIT		},
644 		{ "cull_both",	VK_CULL_MODE_FRONT_AND_BACK	},
645 	};
646 
647 	for (int ndxFrontFace = 0; ndxFrontFace < DE_LENGTH_OF_ARRAY(frontFace); ++ndxFrontFace)
648 	for (int ndxCullMode  = 0; ndxCullMode  < DE_LENGTH_OF_ARRAY(cullMode);  ++ndxCullMode)
649 	{
650 		const TestParams params =
651 		{
652 			frontFace[ndxFrontFace].frontFace,
653 			cullMode[ndxCullMode].cullMode,
654 			subGroupParams.zeroViewportHeight,
655 			subGroupParams.groupParams
656 		};
657 		std::ostringstream	name;
658 		name << frontFace[ndxFrontFace].name << "_" << cullMode[ndxCullMode].name;
659 
660 		testGroup->addChild(new NegativeViewportHeightTest(testGroup->getTestContext(), name.str(), "", params));
661 	}
662 }
663 
664 }	// anonymous
665 
createNegativeViewportHeightTests(tcu::TestContext & testCtx,const SharedGroupParams groupParams)666 tcu::TestCaseGroup*	createNegativeViewportHeightTests (tcu::TestContext& testCtx, const SharedGroupParams groupParams)
667 {
668 	SubGroupParams subGroupParams { false, groupParams };
669 	return createTestGroup(testCtx, "negative_viewport_height", "Negative viewport height (VK_KHR_maintenance1)", populateTestGroup, subGroupParams);
670 }
671 
createZeroViewportHeightTests(tcu::TestContext & testCtx,const SharedGroupParams groupParams)672 tcu::TestCaseGroup*	createZeroViewportHeightTests (tcu::TestContext& testCtx, const SharedGroupParams groupParams)
673 {
674 	SubGroupParams subGroupParams{ false, groupParams };
675 	return createTestGroup(testCtx, "zero_viewport_height", "Zero viewport height (VK_KHR_maintenance1)", populateTestGroup, subGroupParams);
676 }
677 
678 }	// Draw
679 }	// vkt
680