• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2019 Google Inc.
6  * Copyright (c) 2019 The Khronos Group Inc.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Scissoring tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktDrawScissorTests.hpp"
26 
27 #include "vktDrawBaseClass.hpp"
28 #include "vkQueryUtil.hpp"
29 #include "vkCmdUtil.hpp"
30 #include "vkTypeUtil.hpp"
31 #include "vktTestGroupUtil.hpp"
32 
33 #include "tcuTestCase.hpp"
34 #include "tcuTextureUtil.hpp"
35 #include "tcuImageCompare.hpp"
36 
37 #include <string>
38 
39 namespace vkt
40 {
41 namespace Draw
42 {
43 namespace
44 {
45 using namespace vk;
46 using namespace std;
47 using namespace tcu;
48 
49 enum
50 {
51 	WIDTH = 256,
52 	HEIGHT = 256
53 };
54 
55 struct ColorQuad
56 {
ColorQuadvkt::Draw::__anon0b2debf80111::ColorQuad57 	ColorQuad	(deUint32 x, deUint32 y, deUint32 width, deUint32 height, Vec4 color)
58 	: m_x(x), m_y(y), m_width(width), m_height(height), m_color(color)
59 	{
60 	}
61 
62 	deUint32	m_x;
63 	deUint32	m_y;
64 	deUint32	m_width;
65 	deUint32	m_height;
66 	Vec4		m_color;
67 };
68 
scissorQuad(ColorQuad quad,VkRect2D scissor,VkExtent2D framebufferSize)69 ColorQuad scissorQuad (ColorQuad quad, VkRect2D scissor, VkExtent2D framebufferSize)
70 {
71 	int	left	= quad.m_x;
72 	int	right	= quad.m_x + quad.m_width;
73 	int	top		= quad.m_y;
74 	int	bottom	= quad.m_y + quad.m_height;
75 
76 	left	= de::max(left, scissor.offset.x);
77 	left	= de::max(left, 0);
78 	right	= de::min(right, scissor.offset.x + (int)scissor.extent.width);
79 	right	= de::min(right, (int)framebufferSize.width);
80 	top		= de::max(top, scissor.offset.y);
81 	top		= de::max(top, 0);
82 	bottom	= de::min(bottom, scissor.offset.y + (int)scissor.extent.height);
83 	bottom	= de::min(bottom, (int)framebufferSize.height);
84 
85 	return ColorQuad(left, top, de::max(right - left, 0), de::max(bottom - top, 0), quad.m_color);
86 }
87 
88 class TestCommand
89 {
90 	public:
TestCommand(void)91 											TestCommand		(void) {}
~TestCommand(void)92 		virtual								~TestCommand	(void) {}
93 
getVertices(deUint32 offset)94 		virtual vector<PositionColorVertex>	getVertices		(deUint32 offset) { DE_UNREF(offset); return vector<PositionColorVertex>(); }
95 		virtual void						addCommands		(const DeviceInterface& vk, VkCommandBuffer cmdBuffer) = 0;
getMaxScissor(void)96 		virtual deUint32					getMaxScissor	(void) { return 0; }
getQuad(void)97 		virtual vector<ColorQuad>			getQuad			(void) { return vector<ColorQuad>(); }
updateScissors(vector<VkRect2D> scissors)98 		virtual vector<VkRect2D>			updateScissors	(vector<VkRect2D> scissors) { return scissors; }
isScissored(void)99 		virtual bool						isScissored		(void) { return false; }
100 
101 
102 	private:
103 };
104 
105 typedef de::SharedPtr<TestCommand> TestCommandSp;
106 
107 class QuadDrawTestCommand : public TestCommand
108 {
109 	public:
110 											QuadDrawTestCommand		(deUint32 x, deUint32 y, deUint32 width, deUint32 height, Vec4 color);
~QuadDrawTestCommand(void)111 		virtual								~QuadDrawTestCommand	(void) {}
112 
113 		virtual vector<PositionColorVertex>	getVertices				(deUint32 offset);
114 		virtual void						addCommands				(const DeviceInterface& vk, VkCommandBuffer cmdBuffer);
getQuad(void)115 		virtual vector<ColorQuad>			getQuad					(void) { return vector<ColorQuad>(1, m_quad); }
isScissored(void)116 		virtual bool						isScissored				(void) { return true; }
117 	private:
118 		deUint32	m_offset;
119 		ColorQuad	m_quad;
120 };
121 
QuadDrawTestCommand(deUint32 x,deUint32 y,deUint32 width,deUint32 height,Vec4 color)122 QuadDrawTestCommand::QuadDrawTestCommand (deUint32 x, deUint32 y, deUint32 width, deUint32 height, Vec4 color)
123 : m_offset(0)
124 , m_quad(x, y, width, height, color)
125 {
126 }
127 
getVertices(deUint32 offset)128 vector<PositionColorVertex> QuadDrawTestCommand::getVertices (deUint32 offset)
129 {
130 	vector<PositionColorVertex>	vertices;
131 	float						scaleWidth	= 2.0f / (float)WIDTH;
132 	float						scaleHeight	= 2.0f / (float)HEIGHT;
133 	Vec4						topLeft		(-1.0f + scaleWidth * (float)m_quad.m_x, -1.0f + scaleHeight * (float)m_quad.m_y, 0.0f, 1.0f);
134 	Vec4						topRight	(-1.0f + scaleWidth * (float)(m_quad.m_x + m_quad.m_width), -1.0f + scaleHeight * (float)m_quad.m_y, 0.0f, 1.0f);
135 	Vec4						bottomLeft	(-1.0f + scaleWidth * (float)m_quad.m_x, -1.0f + scaleHeight * (float)(m_quad.m_y + m_quad.m_height), 0.0f, 1.0f);
136 	Vec4						bottomRight	(-1.0f + scaleWidth * (float)(m_quad.m_x + m_quad.m_width), -1.0f + scaleHeight * (float)(m_quad.m_y + m_quad.m_height), 0.0f, 1.0f);
137 
138 	m_offset = offset;
139 
140 	vertices.push_back(PositionColorVertex(topLeft,		m_quad.m_color));
141 	vertices.push_back(PositionColorVertex(bottomRight,	m_quad.m_color));
142 	vertices.push_back(PositionColorVertex(bottomLeft,	m_quad.m_color));
143 	vertices.push_back(PositionColorVertex(topLeft,		m_quad.m_color));
144 	vertices.push_back(PositionColorVertex(topRight,	m_quad.m_color));
145 	vertices.push_back(PositionColorVertex(bottomRight,	m_quad.m_color));
146 
147 	return vertices;
148 }
149 
addCommands(const DeviceInterface & vk,VkCommandBuffer cmdBuffer)150 void QuadDrawTestCommand::addCommands (const DeviceInterface& vk, VkCommandBuffer cmdBuffer)
151 {
152 	vk.cmdDraw(cmdBuffer, 6u, 1u, m_offset, 0u);
153 }
154 
155 class RectClearTestCommand : public TestCommand
156 {
157 	public:
158 									RectClearTestCommand	(deUint32 x, deUint32 y, deUint32 width, deUint32 height, Vec4 color);
~RectClearTestCommand(void)159 		virtual						~RectClearTestCommand	(void) {}
160 
161 		virtual void				addCommands				(const DeviceInterface& vk, VkCommandBuffer cmdBuffer);
getQuad(void)162 		virtual vector<ColorQuad>	getQuad					(void) { return vector<ColorQuad>(1, m_quad); }
163 	private:
164 		ColorQuad	m_quad;
165 };
166 
RectClearTestCommand(deUint32 x,deUint32 y,deUint32 width,deUint32 height,Vec4 color)167 RectClearTestCommand::RectClearTestCommand (deUint32 x, deUint32 y, deUint32 width, deUint32 height, Vec4 color)
168 : m_quad(x, y, width, height, color)
169 {
170 }
171 
addCommands(const DeviceInterface & vk,VkCommandBuffer cmdBuffer)172 void RectClearTestCommand::addCommands (const DeviceInterface& vk, VkCommandBuffer cmdBuffer)
173 {
174 	const VkClearAttachment	attachment	=
175 	{
176 		VK_IMAGE_ASPECT_COLOR_BIT,			// VkImageAspectFlags	aspectMask
177 		0u,									// deUint32				colorAttachment
178 		makeClearValueColor(m_quad.m_color)	// VkClearValue			clearValue
179 	};
180 
181 	const VkClearRect		rect		=
182 	{
183 		makeRect2D(m_quad.m_x, m_quad.m_y, m_quad.m_width, m_quad.m_height),	// VkRect2D    rect
184 		0u,																		// deUint32    baseArrayLayer
185 		1u																		// deUint32    layerCount
186 	};
187 
188 	vk.cmdClearAttachments(cmdBuffer, 1u, &attachment, 1u, &rect);
189 }
190 
191 class DynamicScissorTestCommand : public TestCommand
192 {
193 	public:
194 									DynamicScissorTestCommand	(deUint32 firstScissor, vector<VkRect2D> scissors);
~DynamicScissorTestCommand(void)195 		virtual						~DynamicScissorTestCommand	(void) {}
196 
197 		virtual void				addCommands					(const DeviceInterface& vk, VkCommandBuffer cmdBuffer);
getMaxScissor(void)198 		virtual deUint32			getMaxScissor				(void) { return m_firstScissor + (deUint32)m_scissors.size(); }
199 		virtual vector<VkRect2D>	updateScissors				(vector<VkRect2D> scissors);
200 	private:
201 		deUint32					m_firstScissor;
202 		vector<VkRect2D>			m_scissors;
203 };
204 
DynamicScissorTestCommand(deUint32 firstScissor,vector<VkRect2D> scissors)205 DynamicScissorTestCommand::DynamicScissorTestCommand (deUint32 firstScissor, vector<VkRect2D> scissors)
206 : m_firstScissor(firstScissor)
207 , m_scissors(scissors)
208 {
209 }
210 
addCommands(const DeviceInterface & vk,VkCommandBuffer cmdBuffer)211 void DynamicScissorTestCommand::addCommands (const DeviceInterface& vk, VkCommandBuffer cmdBuffer)
212 {
213 	vk.cmdSetScissor(cmdBuffer, m_firstScissor, (deUint32)m_scissors.size(), m_scissors.data());
214 }
215 
updateScissors(vector<VkRect2D> scissors)216 vector<VkRect2D> DynamicScissorTestCommand::updateScissors (vector<VkRect2D> scissors)
217 {
218 	for (size_t scissorIdx = 0; scissorIdx < m_scissors.size(); scissorIdx++)
219 	{
220 		while (scissors.size() <= m_firstScissor + scissorIdx)
221 			scissors.push_back(makeRect2D(0, 0)); // Add empty scissor
222 
223 		scissors[m_firstScissor + scissorIdx] = m_scissors[scissorIdx];
224 	}
225 
226 	return scissors;
227 }
228 
229 struct TestParams
230 {
TestParamsvkt::Draw::__anon0b2debf80111::TestParams231 	TestParams(const SharedGroupParams gp)
232 		: groupParams		(gp)
233 		, framebufferSize	({WIDTH,HEIGHT})
234 	{}
235 
236 	bool					dynamicScissor;
237 	vector<VkRect2D>		staticScissors;
238 	vector<TestCommandSp>	commands;
239 	bool					usesMultipleScissors;
240 	const SharedGroupParams	groupParams;
241 	VkExtent2D				framebufferSize;
242 };
243 
countScissors(TestParams params)244 deUint32 countScissors (TestParams params)
245 {
246 	if (params.dynamicScissor)
247 	{
248 		deUint32 numScissors = 0u;
249 
250 		for (size_t commandIdx = 0; commandIdx < params.commands.size(); commandIdx++)
251 			numScissors = de::max(numScissors, params.commands[commandIdx]->getMaxScissor());
252 
253 		return numScissors;
254 	}
255 	else
256 		return (deUint32)params.staticScissors.size();
257 }
258 
259 class ScissorTestInstance : public TestInstance
260 {
261 public:
262 				ScissorTestInstance		(Context& context, const TestParams& params);
263 				~ScissorTestInstance	(void);
264 	TestStatus	iterate					(void);
265 
266 protected:
267 	void		drawCommands			(VkCommandBuffer cmdBuffer, VkPipeline pipeline, VkBuffer vertexBuffer) const;
268 	void		postRenderCommands		(VkCommandBuffer cmdBuffer, VkImage colorTargetImage) const;
269 
270 #ifndef CTS_USES_VULKANSC
271 	void		beginSecondaryCmdBuffer	(VkCommandBuffer cmdBuffer, VkFormat colorAttachmentFormat, VkRenderingFlagsKHR renderingFlags = 0u) const;
272 #endif // CTS_USES_VULKANSC
273 
274 private:
275 	TestParams	m_params;
276 
277 };
278 
ScissorTestInstance(Context & context,const TestParams & params)279 ScissorTestInstance::ScissorTestInstance (Context& context, const TestParams& params)
280 : vkt::TestInstance	(context)
281 , m_params			(params)
282 {
283 }
284 
~ScissorTestInstance(void)285 ScissorTestInstance::~ScissorTestInstance (void)
286 {
287 }
288 
289 class ScissorTestCase : public TestCase
290 {
291 	public:
292 							ScissorTestCase		(TestContext& context, const char* name, const TestParams params);
293 							~ScissorTestCase	(void);
294 	virtual	void			initPrograms		(SourceCollections& programCollection) const;
295 	virtual TestInstance*	createInstance		(Context& context) const;
296 	virtual void			checkSupport		(Context& context) const;
297 
298 private:
299 	TestParams				m_params;
300 };
301 
ScissorTestCase(TestContext & context,const char * name,const TestParams params)302 ScissorTestCase::ScissorTestCase (TestContext& context, const char* name, const TestParams params)
303 : vkt::TestCase	(context, name)
304 , m_params		(params)
305 {
306 	m_params.usesMultipleScissors = params.staticScissors.size() > 1;
307 
308 	for (size_t commandIdx = 0; commandIdx < m_params.commands.size(); commandIdx++)
309 		if (m_params.commands[commandIdx]->getMaxScissor() > 1)
310 			m_params.usesMultipleScissors = true;
311 }
312 
~ScissorTestCase(void)313 ScissorTestCase::~ScissorTestCase (void)
314 {
315 }
316 
checkSupport(Context & context) const317 void ScissorTestCase::checkSupport (Context& context) const
318 {
319 	if (m_params.groupParams->useDynamicRendering)
320 		context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
321 
322 	if (m_params.usesMultipleScissors)
323 	{
324 		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
325 		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_MULTI_VIEWPORT);
326 	}
327 }
328 
initPrograms(SourceCollections & programCollection) const329 void ScissorTestCase::initPrograms (SourceCollections& programCollection) const
330 {
331 	programCollection.glslSources.add("vert") << glu::VertexSource(
332 		"#version 430\n"
333 		"layout(location = 0) in vec4 in_position;\n"
334 		"layout(location = 1) in vec4 in_color;\n"
335 		"layout(location = 0) out vec4 out_color;\n"
336 		"void main()\n"
337 		"{\n"
338 		"    gl_Position  = in_position;\n"
339 		"    out_color    = in_color;\n"
340 		"}\n");
341 
342 	// Geometry shader draws the same triangles to all viewports
343 	string geomSource = string(
344 		"#version 430\n"
345 		"layout(invocations = ") + de::toString(countScissors(m_params)) + ") in;\n"
346 		"layout(triangles) in;\n"
347 		"layout(triangle_strip, max_vertices = 3) out;\n"
348 		"layout(location = 0) in vec4 in_color[];\n"
349 		"layout(location = 0) out vec4 out_color;\n"
350 		"void main()\n"
351 		"{\n"
352 		"    for (int i = 0; i < gl_in.length(); i++)\n"
353 		"    {\n"
354 		"        gl_ViewportIndex = gl_InvocationID;\n"
355 		"        gl_Position      = gl_in[i].gl_Position;\n"
356 		"        out_color        = in_color[i];\n"
357 		"        EmitVertex();\n"
358 		"    }\n"
359 		"    EndPrimitive();\n"
360 		"}\n";
361 
362 	programCollection.glslSources.add("geom") << glu::GeometrySource(geomSource);
363 
364 	programCollection.glslSources.add("frag") << glu::FragmentSource(
365 		"#version 430\n"
366 		"layout(location = 0) in vec4 in_color;\n"
367 		"layout(location = 0) out vec4 out_color;\n"
368 		"void main()\n"
369 		"{\n"
370 		"    out_color = in_color;\n"
371 		"}\n");
372 }
373 
createInstance(Context & context) const374 TestInstance* ScissorTestCase::createInstance (Context& context) const
375 {
376 	return new ScissorTestInstance(context, m_params);
377 }
378 
iterate(void)379 TestStatus ScissorTestInstance::iterate (void)
380 {
381 	ConstPixelBufferAccess			frame;
382 	VkFormat						colorImageFormat		= VK_FORMAT_R8G8B8A8_UNORM;
383 	de::SharedPtr<Image>			colorTargetImage;
384 	TestLog&						log						= m_context.getTestContext().getLog();
385 	const DeviceInterface&			vk						= m_context.getDeviceInterface();
386 	const VkDevice					device					= m_context.getDevice();
387 	const CmdPoolCreateInfo			cmdPoolCreateInfo		(m_context.getUniversalQueueFamilyIndex());
388 	Move<VkCommandPool>				cmdPool					= createCommandPool(vk, device, &cmdPoolCreateInfo);
389 	Move<VkCommandBuffer>			cmdBuffer				= allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
390 	Move<VkCommandBuffer>			secCmdBuffer;
391 	const Unique<VkShaderModule>	vs						(createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0));
392 	Move<VkShaderModule>			gs;
393 	const Unique<VkShaderModule>	fs						(createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0));
394 	const deUint32					numScissors				= countScissors(m_params);
395 	VkDeviceSize					vertexBufferSize		= 0;
396 	de::SharedPtr<Buffer>			vertexBuffer;
397 	Move<VkRenderPass>				renderPass;
398 	Move<VkImageView>				colorTargetView;
399 	Move<VkFramebuffer>				framebuffer;
400 	Move<VkPipeline>				pipeline;
401 	TextureLevel					refImage;
402 	VkExtent2D						framebufferSize			= m_params.framebufferSize;
403 
404 	if (m_params.usesMultipleScissors)
405 		gs = createShaderModule(vk, device, m_context.getBinaryCollection().get("geom"), 0);
406 
407 	// Create color buffer image
408 	{
409 		const VkExtent3D		targetImageExtent		= { WIDTH, HEIGHT, 1 };
410 		const ImageCreateInfo	targetImageCreateInfo	(VK_IMAGE_TYPE_2D, colorImageFormat, targetImageExtent, 1, 1, VK_SAMPLE_COUNT_1_BIT,
411 														 VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
412 		colorTargetImage = Image::createAndAlloc(vk, device, targetImageCreateInfo, m_context.getDefaultAllocator(), m_context.getUniversalQueueFamilyIndex());
413 	}
414 
415 	const ImageViewCreateInfo	colorTargetViewInfo(colorTargetImage->object(), VK_IMAGE_VIEW_TYPE_2D, colorImageFormat);
416 	colorTargetView = createImageView(vk, device, &colorTargetViewInfo);
417 
418 	// Create render pass
419 	if (!m_params.groupParams->useDynamicRendering)
420 	{
421 		RenderPassCreateInfo		renderPassCreateInfo;
422 		renderPassCreateInfo.addAttachment(AttachmentDescription(colorImageFormat,
423 																 VK_SAMPLE_COUNT_1_BIT,
424 																 VK_ATTACHMENT_LOAD_OP_CLEAR,
425 																 VK_ATTACHMENT_STORE_OP_STORE,
426 																 VK_ATTACHMENT_LOAD_OP_DONT_CARE,
427 																 VK_ATTACHMENT_STORE_OP_STORE,
428 																 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
429 																 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
430 
431 		const VkAttachmentReference	colorAttachmentRef		= { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
432 		renderPassCreateInfo.addSubpass(SubpassDescription(VK_PIPELINE_BIND_POINT_GRAPHICS, 0, 0, DE_NULL, 1, &colorAttachmentRef,
433 														   DE_NULL, AttachmentReference(), 0, DE_NULL));
434 
435 		renderPass = createRenderPass(vk, device, &renderPassCreateInfo);
436 
437 		// Create framebuffer
438 		vector<VkImageView>			colorAttachment { *colorTargetView };
439 		const FramebufferCreateInfo	framebufferCreateInfo(*renderPass, colorAttachment, framebufferSize.width, framebufferSize.height, 1);
440 		framebuffer = createFramebuffer(vk, device, &framebufferCreateInfo);
441 	}
442 
443 	// Create vertex buffer
444 	{
445 		vector<PositionColorVertex> vertices;
446 
447 		for (size_t commandIdx = 0; commandIdx < m_params.commands.size(); commandIdx++)
448 		{
449 			vector<PositionColorVertex> commandVertices = m_params.commands[commandIdx]->getVertices((deUint32)vertices.size());
450 			vertices.insert(vertices.end(), commandVertices.begin(), commandVertices.end());
451 		}
452 
453 		vertexBufferSize = vertices.size() * sizeof(PositionColorVertex);
454 
455 		if (vertexBufferSize > 0)
456 		{
457 			vertexBuffer = Buffer::createAndAlloc(vk, device, BufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), m_context.getDefaultAllocator(), MemoryRequirement::HostVisible);
458 			deUint8* ptr = reinterpret_cast<deUint8*>(vertexBuffer->getBoundMemory().getHostPtr());
459 
460 			deMemcpy(ptr, vertices.data(), static_cast<size_t>(vertexBufferSize));
461 			flushMappedMemoryRange(vk, device, vertexBuffer->getBoundMemory().getMemory(), vertexBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
462 		}
463 	}
464 
465 	const PipelineLayoutCreateInfo	pipelineLayoutCreateInfo;
466 	Move<VkPipelineLayout>			pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
467 
468 	// Create pipeline
469 	{
470 		const PipelineCreateInfo::ColorBlendState::Attachment	colorBlendState;
471 
472 		const VkVertexInputBindingDescription					vertexInputBindingDescription	=
473 		{
474 			0,							// deUintre				binding
475 			(deUint32)sizeof(Vec4) * 2,	// deUint32				stride
476 			VK_VERTEX_INPUT_RATE_VERTEX	// VkVertexInputRate	inputRate
477 		};
478 		const VkViewport viewport = makeViewport(WIDTH, HEIGHT);
479 
480 		const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] =
481 		{
482 			{ 0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, 0u },
483 			{ 1u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, (deUint32)(sizeof(float) * 4) }
484 		};
485 
486 		PipelineCreateInfo::VertexInputState vertexInputState	= PipelineCreateInfo::VertexInputState(1, &vertexInputBindingDescription, 2, vertexInputAttributeDescriptions);
487 
488 		PipelineCreateInfo pipelineCreateInfo(*pipelineLayout, *renderPass, 0, 0);
489 		pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", VK_SHADER_STAGE_VERTEX_BIT));
490 		if (m_params.usesMultipleScissors)
491 			pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*gs, "main", VK_SHADER_STAGE_GEOMETRY_BIT));
492 		pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fs, "main", VK_SHADER_STAGE_FRAGMENT_BIT));
493 		pipelineCreateInfo.addState(PipelineCreateInfo::VertexInputState(vertexInputState));
494 		pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
495 		pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState(1, &colorBlendState));
496 		pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState());
497 		pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
498 		pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState());
499 
500 		if (m_params.dynamicScissor)
501 		{
502 			pipelineCreateInfo.addState(PipelineCreateInfo::DynamicState(vector<VkDynamicState>(1, VK_DYNAMIC_STATE_SCISSOR)));
503 			pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(numScissors, vector<VkViewport>(numScissors, viewport), vector<VkRect2D>(numScissors, makeRect2D(0, 0))));
504 		}
505 		else
506 		{
507 			pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(numScissors, vector<VkViewport>(numScissors, viewport), m_params.staticScissors));
508 		}
509 
510 #ifndef CTS_USES_VULKANSC
511 		VkPipelineRenderingCreateInfoKHR renderingCreateInfo
512 		{
513 			VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
514 			DE_NULL,
515 			0u,
516 			1u,
517 			&colorImageFormat,
518 			VK_FORMAT_UNDEFINED,
519 			VK_FORMAT_UNDEFINED
520 		};
521 
522 		if (m_params.groupParams->useDynamicRendering)
523 			pipelineCreateInfo.pNext = &renderingCreateInfo;
524 #endif // CTS_USES_VULKANSC
525 
526 		pipeline = createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
527 	}
528 
529 	// Queue commands and read results.
530 	{
531 		const ImageSubresourceRange subresourceRange	(VK_IMAGE_ASPECT_COLOR_BIT);
532 		const VkOffset3D			zeroOffset			= { 0, 0, 0 };
533 		const tcu::Vec4				clearColor			= { 0.0f, 0.0f, 0.0f, 1.0f };
534 		const VkClearValue			clearValue			= makeClearValueColor(clearColor);
535 		const VkBuffer				vBuffer				= (vertexBufferSize > 0) ? vertexBuffer->object() : DE_NULL;
536 		const VkRect2D				renderArea			= makeRect2D(m_params.framebufferSize);
537 
538 		// Unreference value for Vulkan SC
539 		DE_UNREF(clearValue);
540 
541 		clearColorImage(vk, device, m_context.getUniversalQueue(), m_context.getUniversalQueueFamilyIndex(), colorTargetImage->object(), clearColor,
542 						VK_IMAGE_LAYOUT_UNDEFINED,
543 						VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
544 						VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u, 1u);
545 
546 #ifndef CTS_USES_VULKANSC
547 		if (m_params.groupParams->useSecondaryCmdBuffer)
548 		{
549 			secCmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
550 
551 			// record secondary command buffer
552 			if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
553 			{
554 				beginSecondaryCmdBuffer(*secCmdBuffer, colorImageFormat, VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
555 				beginRendering(vk, *secCmdBuffer, *colorTargetView, renderArea, clearValue, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ATTACHMENT_LOAD_OP_CLEAR);
556 			}
557 			else
558 				beginSecondaryCmdBuffer(*secCmdBuffer, colorImageFormat);
559 
560 			drawCommands(*secCmdBuffer, *pipeline, vBuffer);
561 
562 			if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
563 				endRendering(vk, *secCmdBuffer);
564 
565 			endCommandBuffer(vk, *secCmdBuffer);
566 
567 			// record primary command buffer
568 			beginCommandBuffer(vk, *cmdBuffer, 0u);
569 
570 			if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
571 				beginRendering(vk, *cmdBuffer, *colorTargetView, renderArea, clearValue, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
572 
573 			vk.cmdExecuteCommands(*cmdBuffer, 1u, &*secCmdBuffer);
574 
575 			if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
576 				endRendering(vk, *cmdBuffer);
577 
578 			postRenderCommands(*cmdBuffer, colorTargetImage->object());
579 			endCommandBuffer(vk, *cmdBuffer);
580 		}
581 		else if (m_params.groupParams->useDynamicRendering)
582 		{
583 			beginCommandBuffer(vk, *cmdBuffer);
584 
585 			beginRendering(vk, *cmdBuffer, *colorTargetView, renderArea, clearValue, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ATTACHMENT_LOAD_OP_CLEAR);
586 			drawCommands(*cmdBuffer, *pipeline, vBuffer);
587 			endRendering(vk, *cmdBuffer);
588 			postRenderCommands(*cmdBuffer, colorTargetImage->object());
589 
590 			endCommandBuffer(vk, *cmdBuffer);
591 		}
592 #endif // CTS_USES_VULKANSC
593 
594 		if (!m_params.groupParams->useDynamicRendering)
595 		{
596 			beginCommandBuffer(vk, *cmdBuffer);
597 
598 			beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
599 			drawCommands(*cmdBuffer, *pipeline, vBuffer);
600 			endRenderPass(vk, *cmdBuffer);
601 			postRenderCommands(*cmdBuffer, colorTargetImage->object());
602 
603 			endCommandBuffer(vk, *cmdBuffer);
604 		}
605 
606 		submitCommandsAndWait(vk, device, m_context.getUniversalQueue(), cmdBuffer.get());
607 
608 		frame = colorTargetImage->readSurface(m_context.getUniversalQueue(), m_context.getDefaultAllocator(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, zeroOffset, WIDTH, HEIGHT, VK_IMAGE_ASPECT_COLOR_BIT);
609 	}
610 
611 	// Generate reference
612 	{
613 		refImage.setStorage(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM), WIDTH, HEIGHT);
614 		clear(refImage.getAccess(), Vec4(0.0f, 0.0f, 0.0f, 1.0f));
615 
616 		vector<VkRect2D> scissors = m_params.staticScissors;
617 
618 		for (size_t commandIdx = 0; commandIdx < m_params.commands.size(); commandIdx++)
619 		{
620 			scissors = m_params.commands[commandIdx]->updateScissors(scissors);
621 
622 			vector<ColorQuad> quad = m_params.commands[commandIdx]->getQuad();
623 
624 			if (quad.empty())
625 				continue;
626 
627 			for (size_t scissorIdx = 0; scissorIdx < scissors.size(); scissorIdx++)
628 			{
629 				ColorQuad scissoredQuad = m_params.commands[commandIdx]->isScissored() ? scissorQuad(quad[0], scissors[scissorIdx], framebufferSize) : quad[0];
630 
631 				if (scissoredQuad.m_width == 0 || scissoredQuad.m_height == 0)
632 					continue;
633 
634 				clear(getSubregion(refImage.getAccess(), scissoredQuad.m_x, scissoredQuad.m_y, 0, scissoredQuad.m_width, scissoredQuad.m_height, 1), scissoredQuad.m_color);
635 			}
636 		}
637 	}
638 
639 	// Compare results
640 	qpTestResult res = QP_TEST_RESULT_PASS;
641 
642 	if (!intThresholdCompare(log, "Result", "Image comparison result", refImage.getAccess(), frame, UVec4(0), COMPARE_LOG_RESULT))
643 		res = QP_TEST_RESULT_FAIL;
644 
645 	return TestStatus(res, qpGetTestResultName(res));
646 }
647 
drawCommands(VkCommandBuffer cmdBuffer,VkPipeline pipeline,VkBuffer vertexBuffer) const648 void ScissorTestInstance::drawCommands(VkCommandBuffer cmdBuffer, VkPipeline pipeline, VkBuffer vertexBuffer) const
649 {
650 	const DeviceInterface&	vk					= m_context.getDeviceInterface();
651 	const VkDeviceSize		vertexBufferOffset	= 0;
652 
653 	if (vertexBuffer != DE_NULL)
654 		vk.cmdBindVertexBuffers(cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
655 	vk.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
656 
657 	for (size_t commandIdx = 0; commandIdx < m_params.commands.size(); commandIdx++)
658 		m_params.commands[commandIdx]->addCommands(vk, cmdBuffer);
659 }
660 
postRenderCommands(VkCommandBuffer cmdBuffer,VkImage colorTargetImage) const661 void ScissorTestInstance::postRenderCommands(VkCommandBuffer cmdBuffer, VkImage colorTargetImage) const
662 {
663 	const DeviceInterface&	vk = m_context.getDeviceInterface();
664 	transition2DImage(vk, cmdBuffer, colorTargetImage,
665 						VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
666 						VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
667 						VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
668 						VK_PIPELINE_STAGE_TRANSFER_BIT);
669 }
670 
671 #ifndef CTS_USES_VULKANSC
beginSecondaryCmdBuffer(VkCommandBuffer cmdBuffer,VkFormat colorAttachmentFormat,VkRenderingFlagsKHR renderingFlags) const672 void ScissorTestInstance::beginSecondaryCmdBuffer(VkCommandBuffer cmdBuffer, VkFormat colorAttachmentFormat, VkRenderingFlagsKHR renderingFlags) const
673 {
674 	VkCommandBufferInheritanceRenderingInfoKHR inheritanceRenderingInfo
675 	{
676 		VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR,		// VkStructureType					sType;
677 		DE_NULL,																// const void*						pNext;
678 		renderingFlags,															// VkRenderingFlagsKHR				flags;
679 		0u,																		// uint32_t							viewMask;
680 		1u,																		// uint32_t							colorAttachmentCount;
681 		&colorAttachmentFormat,													// const VkFormat*					pColorAttachmentFormats;
682 		VK_FORMAT_UNDEFINED,													// VkFormat							depthAttachmentFormat;
683 		VK_FORMAT_UNDEFINED,													// VkFormat							stencilAttachmentFormat;
684 		VK_SAMPLE_COUNT_1_BIT,													// VkSampleCountFlagBits			rasterizationSamples;
685 	};
686 	const VkCommandBufferInheritanceInfo bufferInheritanceInfo = initVulkanStructure(&inheritanceRenderingInfo);
687 
688 	VkCommandBufferUsageFlags usageFlags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
689 	if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
690 		usageFlags |= VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
691 
692 	const VkCommandBufferBeginInfo commandBufBeginParams
693 	{
694 		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,							// VkStructureType					sType;
695 		DE_NULL,																// const void*						pNext;
696 		usageFlags,																// VkCommandBufferUsageFlags		flags;
697 		&bufferInheritanceInfo
698 	};
699 
700 	const DeviceInterface& vk = m_context.getDeviceInterface();
701 	VK_CHECK(vk.beginCommandBuffer(cmdBuffer, &commandBufBeginParams));
702 }
703 #endif // CTS_USES_VULKANSC
704 
createTests(TestCaseGroup * testGroup,const SharedGroupParams groupParams)705 void createTests (TestCaseGroup* testGroup, const SharedGroupParams groupParams)
706 {
707 	TestContext&		testCtx		= testGroup->getTestContext();
708 	const Vec4			red			(1.0f, 0.0f, 0.0f, 1.0f);
709 	const Vec4			green		(0.0f, 1.0f, 0.0f, 1.0f);
710 	const Vec4			blue		(0.0f, 0.0f, 1.0f, 1.0f);
711 	const Vec4			yellow		(1.0f, 1.0f, 0.0f, 1.0f);
712 
713 	// Two quads with a single static scissor
714 	{
715 		TestParams params(groupParams);
716 		params.dynamicScissor = false;
717 		params.staticScissors.push_back(makeRect2D(30, 40, WIDTH - 60, HEIGHT - 80));
718 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(10, 10, 50, 50, red)));
719 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(WIDTH - 80, HEIGHT - 100, 30, 40, green)));
720 
721 		testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_two_quads", params));
722 	}
723 
724 	// Two clears with a single static scissor
725 	{
726 		TestParams params(groupParams);
727 		params.dynamicScissor = false;
728 		params.staticScissors.push_back(makeRect2D(30, 40, WIDTH - 60, HEIGHT - 80));
729 		params.commands.push_back(TestCommandSp(new RectClearTestCommand(10, 10, 50, 50, red)));
730 		params.commands.push_back(TestCommandSp(new RectClearTestCommand(WIDTH - 80, HEIGHT - 100, 30, 40, green)));
731 
732 		testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_two_clears", params));
733 	}
734 
735 	// One quad with two static scissors
736 	{
737 		TestParams params(groupParams);
738 		params.dynamicScissor = false;
739 		params.staticScissors.push_back(makeRect2D(30, 40, WIDTH - 60, HEIGHT - 70));
740 		params.staticScissors.push_back(makeRect2D(40, 50, WIDTH - 60, HEIGHT - 70));
741 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(10, 10, WIDTH - 10, HEIGHT - 10, red)));
742 
743 		testGroup->addChild(new ScissorTestCase(testCtx, "two_static_scissors_one_quad", params));
744 	}
745 
746 	// Static scissor extending outside viewport
747 	{
748 		TestParams params(groupParams);
749 		params.dynamicScissor = false;
750 		params.staticScissors.push_back(makeRect2D(30, 40, WIDTH, HEIGHT));
751 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH, HEIGHT + 30, green)));
752 
753 		testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_partially_outside_viewport", params));
754 	}
755 
756 	// Static scissor completely outside viewport
757 	{
758 		TestParams params(groupParams);
759 		params.dynamicScissor = false;
760 		params.staticScissors.push_back(makeRect2D(WIDTH + 30, HEIGHT + 40, WIDTH, HEIGHT));
761 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(100, 100, 20, 30, green)));
762 
763 		testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_outside_viewport", params));
764 	}
765 
766 	// Static scissor outside viewport and touching right border of viewport
767 	{
768 		TestParams params(groupParams);
769 		params.dynamicScissor = false;
770 		params.staticScissors.push_back(makeRect2D(WIDTH, 0, WIDTH, HEIGHT));
771 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(100, 100, 20, 30, green)));
772 
773 		testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_viewport_border", params));
774 	}
775 
776 	// Static scissor with offset + extent equal to largest positive int32
777 	{
778 		TestParams params(groupParams);
779 		params.dynamicScissor = false;
780 		params.staticScissors.push_back(makeRect2D(100, 100, 0x7fffffff - 100, 0x7fffffff - 100));
781 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH, HEIGHT, green)));
782 
783 		testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_max_int32", params));
784 	}
785 
786 	// 16 static scissors (minimum number required when multiViewport supported)
787 	{
788 		TestParams params(groupParams);
789 		params.dynamicScissor = false;
790 
791 		for (deUint32 i = 0; i < 16; i++)
792 			params.staticScissors.push_back(makeRect2D(10 + i * 3, 20 + i * 2, WIDTH / 2, HEIGHT / 2));
793 
794 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(5, 6, WIDTH - 10, HEIGHT - 2, red)));
795 
796 		testGroup->addChild(new ScissorTestCase(testCtx, "16_static_scissors", params));
797 	}
798 
799 	// Two quads with an empty scissor
800 	{
801 		TestParams params(groupParams);
802 		params.dynamicScissor = false;
803 		params.staticScissors.push_back(makeRect2D(0, 0, 0, 0));
804 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(10, 10, 50, 50, red)));
805 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(WIDTH - 80, HEIGHT - 100, 30, 40, green)));
806 
807 		testGroup->addChild(new ScissorTestCase(testCtx, "empty_static_scissor", params));
808 	}
809 
810 	// Two quads with a single dynamic scissor
811 	{
812 		TestParams params(groupParams);
813 		params.dynamicScissor = true;
814 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(30, 40, WIDTH - 60, HEIGHT - 80)))));
815 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(10, 10, 50, 50, red)));
816 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(WIDTH - 80, HEIGHT - 100, 30, 40, green)));
817 
818 		testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_two_quads", params));
819 	}
820 
821 	// Empty scissor for the first draw
822 	{
823 		TestParams params(groupParams);
824 		params.dynamicScissor = true;
825 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(0, 0, 0, 0)))));
826 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(10, 10, 50, 50, red)));
827 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(30, 40, WIDTH - 60, HEIGHT - 80)))));
828 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(WIDTH - 80, HEIGHT - 100, 30, 40, green)));
829 
830 		testGroup->addChild(new ScissorTestCase(testCtx, "empty_dynamic_scissor_first_draw", params));
831 	}
832 
833 	// Two quads with three scissors updated in between
834 	{
835 		TestParams			params(groupParams);
836 		VkRect2D			rect		= makeRect2D(10, 20, WIDTH - 60, HEIGHT - 70);
837 		vector<VkRect2D>	scissors;
838 
839 		params.dynamicScissor = true;
840 
841 		scissors.push_back(rect);
842 		rect.offset.x += 10;
843 		rect.offset.y += 10;
844 		scissors.push_back(rect);
845 		rect.offset.x += 10;
846 		rect.offset.y += 10;
847 		scissors.push_back(rect);
848 
849 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors)));
850 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(5, 7, WIDTH - 20, HEIGHT - 9, red)));
851 
852 		for (size_t scissorIdx = 0; scissorIdx < scissors.size(); scissorIdx++)
853 			scissors[scissorIdx].offset.x += 20;
854 
855 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors)));
856 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(8, 12, WIDTH - 2, HEIGHT - 19, green)));
857 
858 		testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_updates_between_draws", params));
859 	}
860 
861 	// Scissor updates out of order
862 	{
863 		TestParams			params(groupParams);
864 		VkRect2D			rect		= makeRect2D(10, 20, WIDTH - 60, HEIGHT - 70);
865 		vector<VkRect2D>	scissors;
866 
867 		params.dynamicScissor = true;
868 
869 		scissors.push_back(rect);
870 		rect.offset.x += 10;
871 		rect.offset.y += 10;
872 		scissors.push_back(rect);
873 		rect.offset.x += 10;
874 		rect.offset.y += 10;
875 		scissors.push_back(rect);
876 
877 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(2, vector<VkRect2D>(1, scissors[2]))));
878 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(1, vector<VkRect2D>(1, scissors[1]))));
879 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, scissors[0]))));
880 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(5, 7, WIDTH - 20, HEIGHT - 9, red)));
881 
882 		for (size_t scissorIdx = 0; scissorIdx < scissors.size(); scissorIdx++)
883 			scissors[scissorIdx].offset.x += 20;
884 
885 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(1, vector<VkRect2D>(1, scissors[1]))));
886 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, scissors[0]))));
887 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(2, vector<VkRect2D>(1, scissors[2]))));
888 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(8, 12, WIDTH - 2, HEIGHT - 19, green)));
889 
890 		testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_out_of_order_updates", params));
891 	}
892 
893 	// Dynamic scissor extending outside viewport
894 	{
895 		TestParams params(groupParams);
896 		params.dynamicScissor = true;
897 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(30, 40, WIDTH, HEIGHT)))));
898 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH + 50, HEIGHT + 20, green)));
899 
900 		testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_partially_outside_viewport", params));
901 	}
902 
903 	// Dynamic scissor completely outside viewport
904 	{
905 		TestParams params(groupParams);
906 		params.dynamicScissor = true;
907 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(WIDTH + 30, HEIGHT + 40, WIDTH, HEIGHT)))));
908 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(100, 100, 20, 30, green)));
909 
910 		testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_outside_viewport", params));
911 	}
912 
913 	// Dynamic scissor outside viewport and touching right border of viewport
914 	{
915 		TestParams params(groupParams);
916 		params.dynamicScissor = true;
917 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(WIDTH, 0, WIDTH, HEIGHT)))));
918 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(100, 100, 20, 30, green)));
919 
920 		testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_viewport_border", params));
921 	}
922 
923 	// Dynamic scissor with offset + extent equal to largest positive int32
924 	{
925 		TestParams params(groupParams);
926 		params.dynamicScissor = true;
927 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(100, 100, 0x7fffffff - 100, 0x7fffffff - 100)))));
928 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH, HEIGHT, green)));
929 
930 		testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_max_int32", params));
931 	}
932 
933 	// 16 dynamic scissors (minimum number required when multiViewport supported)
934 	{
935 		TestParams			params(groupParams);
936 		vector<VkRect2D>	scissors;
937 		params.dynamicScissor = true;
938 
939 		for (deUint32 i = 0; i < 16; i++)
940 			scissors.push_back(makeRect2D(10 + i * 3, 20 + i * 2, WIDTH / 2, HEIGHT / 2));
941 
942 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors)));
943 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(5, 6, WIDTH - 10, HEIGHT - 2, red)));
944 
945 		testGroup->addChild(new ScissorTestCase(testCtx, "16_dynamic_scissors", params));
946 	}
947 
948 	// Two clears with a single dynamic scissor
949 	{
950 		TestParams params(groupParams);
951 		params.dynamicScissor = true;
952 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(30, 40, WIDTH - 60, HEIGHT - 80)))));
953 		params.commands.push_back(TestCommandSp(new RectClearTestCommand(10, 10, 50, 50, red)));
954 		params.commands.push_back(TestCommandSp(new RectClearTestCommand(WIDTH - 80, HEIGHT - 100, 30, 40, green)));
955 
956 		testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_two_clears", params));
957 	}
958 
959 	// Mixture of quad draws and clears with dynamic scissor updates
960 	{
961 		TestParams			params(groupParams);
962 		vector<VkRect2D>	scissors;
963 
964 		params.dynamicScissor = true;
965 
966 		scissors.push_back(makeRect2D(30, 40, 50, 60));
967 		scissors.push_back(makeRect2D(40, 20, 50, 50));
968 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors)));
969 		params.commands.push_back(TestCommandSp(new RectClearTestCommand(10, 10, 50, 50, red)));
970 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(40, 30, 50, 50, green)));
971 		scissors[1].extent.width -= 20;
972 		scissors[1].extent.height += 30;
973 		scissors[1].offset.x -= 20;
974 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(1, vector<VkRect2D>(1, scissors[1]))));
975 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(70, 70, 50, 50, blue)));
976 		params.commands.push_back(TestCommandSp(new RectClearTestCommand(75, 77, 50, 50, yellow)));
977 
978 		testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_mix", params));
979 	}
980 
981 	// Static scissor off by one, inside frame buffer border
982 	{
983 		VkExtent2D size =
984 		{
985 			WIDTH / 2 - 1,
986 			HEIGHT / 2 - 1
987 		};
988 
989 		TestParams params(groupParams);
990 
991 		params.framebufferSize = size;
992 		params.dynamicScissor = false;
993 		params.staticScissors.push_back(makeRect2D(1, 1, size.width - 2, size.height - 2));
994 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH * 4, HEIGHT * 4, red)));
995 
996 		testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_framebuffer_border_in", params));
997 	}
998 
999 	// Dynamic scissor off by one, inside frame buffer border
1000 	{
1001 		VkExtent2D size =
1002 		{
1003 			WIDTH / 2 - 1,
1004 			HEIGHT / 2 - 1
1005 		};
1006 
1007 		TestParams			params(groupParams);
1008 		vector<VkRect2D>	scissors;
1009 
1010 		params.framebufferSize = size;
1011 		params.dynamicScissor = true;
1012 
1013 		scissors.push_back(makeRect2D(1, 1, size.width - 2, size.height - 2));
1014 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors)));
1015 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH * 4, HEIGHT * 4, red)));
1016 
1017 		testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_framebuffer_border_in", params));
1018 	}
1019 }
1020 
1021 }	// anonymous
1022 
createScissorTests(TestContext & testCtx,const SharedGroupParams groupParams)1023 TestCaseGroup*	createScissorTests (TestContext& testCtx, const SharedGroupParams groupParams)
1024 {
1025 	return createTestGroup(testCtx, "scissor", createTests, groupParams);
1026 }
1027 
1028 }	// Draw
1029 }	// vkt
1030