• 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::__anon12e10fd70111::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 dummy scissor
222 
223 		scissors[m_firstScissor + scissorIdx] = m_scissors[scissorIdx];
224 	}
225 
226 	return scissors;
227 }
228 
229 struct TestParams
230 {
TestParamsvkt::Draw::__anon12e10fd70111::TestParams231 	TestParams() : framebufferSize({WIDTH,HEIGHT}) {}
232 
233 	bool					dynamicScissor;
234 	vector<VkRect2D>		staticScissors;
235 	vector<TestCommandSp>	commands;
236 	bool					usesMultipleScissors;
237 	bool					usesDynamicRendering;
238 	VkExtent2D				framebufferSize;
239 };
240 
countScissors(TestParams params)241 deUint32 countScissors (TestParams params)
242 {
243 	if (params.dynamicScissor)
244 	{
245 		deUint32 numScissors = 0u;
246 
247 		for (size_t commandIdx = 0; commandIdx < params.commands.size(); commandIdx++)
248 			numScissors = de::max(numScissors, params.commands[commandIdx]->getMaxScissor());
249 
250 		return numScissors;
251 	}
252 	else
253 		return (deUint32)params.staticScissors.size();
254 }
255 
256 class ScissorTestInstance : public TestInstance
257 {
258 public:
259 				ScissorTestInstance		(Context& context, const TestParams& params);
260 				~ScissorTestInstance	(void);
261 	TestStatus	iterate					(void);
262 private:
263 	TestParams	m_params;
264 
265 };
266 
ScissorTestInstance(Context & context,const TestParams & params)267 ScissorTestInstance::ScissorTestInstance (Context& context, const TestParams& params)
268 : vkt::TestInstance	(context)
269 , m_params			(params)
270 {
271 }
272 
~ScissorTestInstance(void)273 ScissorTestInstance::~ScissorTestInstance (void)
274 {
275 }
276 
277 class ScissorTestCase : public TestCase
278 {
279 	public:
280 							ScissorTestCase		(TestContext& context, const char* name, const char* desc, const TestParams params);
281 							~ScissorTestCase	(void);
282 	virtual	void			initPrograms		(SourceCollections& programCollection) const;
283 	virtual TestInstance*	createInstance		(Context& context) const;
284 	virtual void			checkSupport		(Context& context) const;
285 
286 private:
287 	TestParams				m_params;
288 };
289 
ScissorTestCase(TestContext & context,const char * name,const char * desc,const TestParams params)290 ScissorTestCase::ScissorTestCase (TestContext& context, const char* name, const char* desc, const TestParams params)
291 : vkt::TestCase	(context, name, desc)
292 , m_params		(params)
293 {
294 	m_params.usesMultipleScissors = params.staticScissors.size() > 1;
295 
296 	for (size_t commandIdx = 0; commandIdx < m_params.commands.size(); commandIdx++)
297 		if (m_params.commands[commandIdx]->getMaxScissor() > 1)
298 			m_params.usesMultipleScissors = true;
299 }
300 
~ScissorTestCase(void)301 ScissorTestCase::~ScissorTestCase (void)
302 {
303 }
304 
checkSupport(Context & context) const305 void ScissorTestCase::checkSupport (Context& context) const
306 {
307 	if (m_params.usesDynamicRendering)
308 		context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
309 
310 	if (m_params.usesMultipleScissors)
311 	{
312 		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
313 		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_MULTI_VIEWPORT);
314 	}
315 }
316 
initPrograms(SourceCollections & programCollection) const317 void ScissorTestCase::initPrograms (SourceCollections& programCollection) const
318 {
319 	programCollection.glslSources.add("vert") << glu::VertexSource(
320 		"#version 430\n"
321 		"layout(location = 0) in vec4 in_position;\n"
322 		"layout(location = 1) in vec4 in_color;\n"
323 		"layout(location = 0) out vec4 out_color;\n"
324 		"void main()\n"
325 		"{\n"
326 		"    gl_Position  = in_position;\n"
327 		"    out_color    = in_color;\n"
328 		"}\n");
329 
330 	// Geometry shader draws the same triangles to all viewports
331 	string geomSource = string(
332 		"#version 430\n"
333 		"layout(invocations = ") + de::toString(countScissors(m_params)) + ") in;\n"
334 		"layout(triangles) in;\n"
335 		"layout(triangle_strip, max_vertices = 3) out;\n"
336 		"layout(location = 0) in vec4 in_color[];\n"
337 		"layout(location = 0) out vec4 out_color;\n"
338 		"void main()\n"
339 		"{\n"
340 		"    for (int i = 0; i < gl_in.length(); i++)\n"
341 		"    {\n"
342 		"        gl_ViewportIndex = gl_InvocationID;\n"
343 		"        gl_Position      = gl_in[i].gl_Position;\n"
344 		"        out_color        = in_color[i];\n"
345 		"        EmitVertex();\n"
346 		"    }\n"
347 		"    EndPrimitive();\n"
348 		"}\n";
349 
350 	programCollection.glslSources.add("geom") << glu::GeometrySource(geomSource);
351 
352 	programCollection.glslSources.add("frag") << glu::FragmentSource(
353 		"#version 430\n"
354 		"layout(location = 0) in vec4 in_color;\n"
355 		"layout(location = 0) out vec4 out_color;\n"
356 		"void main()\n"
357 		"{\n"
358 		"    out_color = in_color;\n"
359 		"}\n");
360 }
361 
createInstance(Context & context) const362 TestInstance* ScissorTestCase::createInstance (Context& context) const
363 {
364 	return new ScissorTestInstance(context, m_params);
365 }
366 
iterate(void)367 TestStatus ScissorTestInstance::iterate (void)
368 {
369 	ConstPixelBufferAccess			frame;
370 	VkFormat						colorImageFormat		= VK_FORMAT_R8G8B8A8_UNORM;
371 	de::SharedPtr<Image>			colorTargetImage;
372 	TestLog&						log						= m_context.getTestContext().getLog();
373 	const DeviceInterface&			vk						= m_context.getDeviceInterface();
374 	const VkDevice					device					= m_context.getDevice();
375 	const CmdPoolCreateInfo			cmdPoolCreateInfo		(m_context.getUniversalQueueFamilyIndex());
376 	Move<VkCommandPool>				cmdPool					= createCommandPool(vk, device, &cmdPoolCreateInfo);
377 	Move<VkCommandBuffer>			cmdBuffer				= allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
378 	const Unique<VkShaderModule>	vs						(createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0));
379 	Move<VkShaderModule>			gs;
380 	const Unique<VkShaderModule>	fs						(createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0));
381 	const deUint32					numScissors				= countScissors(m_params);
382 	VkDeviceSize					vertexBufferSize		= 0;
383 	de::SharedPtr<Buffer>			vertexBuffer;
384 	Move<VkRenderPass>				renderPass;
385 	Move<VkImageView>				colorTargetView;
386 	Move<VkFramebuffer>				framebuffer;
387 	Move<VkPipeline>				pipeline;
388 	TextureLevel					refImage;
389 	VkExtent2D						framebufferSize			= m_params.framebufferSize;
390 
391 	if (m_params.usesMultipleScissors)
392 		gs = createShaderModule(vk, device, m_context.getBinaryCollection().get("geom"), 0);
393 
394 	// Create color buffer image
395 	{
396 		const VkExtent3D		targetImageExtent		= { WIDTH, HEIGHT, 1 };
397 		const ImageCreateInfo	targetImageCreateInfo	(VK_IMAGE_TYPE_2D, colorImageFormat, targetImageExtent, 1, 1, VK_SAMPLE_COUNT_1_BIT,
398 														 VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
399 		colorTargetImage = Image::createAndAlloc(vk, device, targetImageCreateInfo, m_context.getDefaultAllocator(), m_context.getUniversalQueueFamilyIndex());
400 	}
401 
402 	const ImageViewCreateInfo	colorTargetViewInfo(colorTargetImage->object(), VK_IMAGE_VIEW_TYPE_2D, colorImageFormat);
403 	colorTargetView = createImageView(vk, device, &colorTargetViewInfo);
404 
405 	// Create render pass
406 	if (!m_params.usesDynamicRendering)
407 	{
408 		RenderPassCreateInfo		renderPassCreateInfo;
409 		renderPassCreateInfo.addAttachment(AttachmentDescription(colorImageFormat,
410 																 VK_SAMPLE_COUNT_1_BIT,
411 																 VK_ATTACHMENT_LOAD_OP_CLEAR,
412 																 VK_ATTACHMENT_STORE_OP_STORE,
413 																 VK_ATTACHMENT_LOAD_OP_DONT_CARE,
414 																 VK_ATTACHMENT_STORE_OP_STORE,
415 																 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
416 																 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
417 
418 		const VkAttachmentReference	colorAttachmentRef		= { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
419 		renderPassCreateInfo.addSubpass(SubpassDescription(VK_PIPELINE_BIND_POINT_GRAPHICS, 0, 0, DE_NULL, 1, &colorAttachmentRef,
420 														   DE_NULL, AttachmentReference(), 0, DE_NULL));
421 
422 		renderPass = createRenderPass(vk, device, &renderPassCreateInfo);
423 
424 		// Create framebuffer
425 		vector<VkImageView>			colorAttachment { *colorTargetView };
426 		const FramebufferCreateInfo	framebufferCreateInfo(*renderPass, colorAttachment, framebufferSize.width, framebufferSize.height, 1);
427 		framebuffer = createFramebuffer(vk, device, &framebufferCreateInfo);
428 	}
429 
430 	// Create vertex buffer
431 	{
432 		vector<PositionColorVertex> vertices;
433 
434 		for (size_t commandIdx = 0; commandIdx < m_params.commands.size(); commandIdx++)
435 		{
436 			vector<PositionColorVertex> commandVertices = m_params.commands[commandIdx]->getVertices((deUint32)vertices.size());
437 			vertices.insert(vertices.end(), commandVertices.begin(), commandVertices.end());
438 		}
439 
440 		vertexBufferSize = vertices.size() * sizeof(PositionColorVertex);
441 
442 		if (vertexBufferSize > 0)
443 		{
444 			vertexBuffer = Buffer::createAndAlloc(vk, device, BufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), m_context.getDefaultAllocator(), MemoryRequirement::HostVisible);
445 			deUint8* ptr = reinterpret_cast<deUint8*>(vertexBuffer->getBoundMemory().getHostPtr());
446 
447 			deMemcpy(ptr, vertices.data(), static_cast<size_t>(vertexBufferSize));
448 			flushMappedMemoryRange(vk, device, vertexBuffer->getBoundMemory().getMemory(), vertexBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
449 		}
450 	}
451 
452 	const PipelineLayoutCreateInfo	pipelineLayoutCreateInfo;
453 	Move<VkPipelineLayout>			pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
454 
455 	// Create pipeline
456 	{
457 		const PipelineCreateInfo::ColorBlendState::Attachment	colorBlendState;
458 
459 		const VkVertexInputBindingDescription					vertexInputBindingDescription	=
460 		{
461 			0,							// deUintre				binding
462 			(deUint32)sizeof(Vec4) * 2,	// deUint32				stride
463 			VK_VERTEX_INPUT_RATE_VERTEX	// VkVertexInputRate	inputRate
464 		};
465 		const VkViewport viewport = makeViewport(WIDTH, HEIGHT);
466 
467 		const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] =
468 		{
469 			{ 0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, 0u },
470 			{ 1u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, (deUint32)(sizeof(float) * 4) }
471 		};
472 
473 		PipelineCreateInfo::VertexInputState vertexInputState	= PipelineCreateInfo::VertexInputState(1, &vertexInputBindingDescription, 2, vertexInputAttributeDescriptions);
474 
475 		PipelineCreateInfo pipelineCreateInfo(*pipelineLayout, *renderPass, 0, 0);
476 		pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", VK_SHADER_STAGE_VERTEX_BIT));
477 		if (m_params.usesMultipleScissors)
478 			pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*gs, "main", VK_SHADER_STAGE_GEOMETRY_BIT));
479 		pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fs, "main", VK_SHADER_STAGE_FRAGMENT_BIT));
480 		pipelineCreateInfo.addState(PipelineCreateInfo::VertexInputState(vertexInputState));
481 		pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
482 		pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState(1, &colorBlendState));
483 		pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState());
484 		pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
485 		pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState());
486 
487 		if (m_params.dynamicScissor)
488 		{
489 			pipelineCreateInfo.addState(PipelineCreateInfo::DynamicState(vector<VkDynamicState>(1, VK_DYNAMIC_STATE_SCISSOR)));
490 			pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(numScissors, vector<VkViewport>(numScissors, viewport), vector<VkRect2D>(numScissors, makeRect2D(0, 0))));
491 		}
492 		else
493 		{
494 			pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(numScissors, vector<VkViewport>(numScissors, viewport), m_params.staticScissors));
495 		}
496 
497 		VkPipelineRenderingCreateInfoKHR renderingCreateInfo
498 		{
499 			VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
500 			DE_NULL,
501 			0u,
502 			1u,
503 			&colorImageFormat,
504 			VK_FORMAT_UNDEFINED,
505 			VK_FORMAT_UNDEFINED
506 		};
507 
508 		if (m_params.usesDynamicRendering)
509 			pipelineCreateInfo.pNext = &renderingCreateInfo;
510 
511 		pipeline = createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
512 	}
513 
514 	// Queue commands and read results.
515 	{
516 		const ImageSubresourceRange subresourceRange	(VK_IMAGE_ASPECT_COLOR_BIT);
517 		const VkRect2D				renderArea			= makeRect2D(framebufferSize);
518 		const VkDeviceSize			vertexBufferOffset	= 0;
519 		const VkOffset3D			zeroOffset			= { 0, 0, 0 };
520 		const tcu::Vec4				clearColor			= { 0.0f, 0.0f, 0.0f, 1.0f };
521 		const VkClearValue			clearValue			= makeClearValueColor(clearColor);
522 
523 		clearColorImage(vk, device, m_context.getUniversalQueue(), m_context.getUniversalQueueFamilyIndex(), colorTargetImage->object(), clearColor,
524 						VK_IMAGE_LAYOUT_UNDEFINED,
525 						VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
526 						VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
527 
528 		beginCommandBuffer(vk, *cmdBuffer, 0u);
529 
530 		if (m_params.usesDynamicRendering)
531 			beginRendering(vk, *cmdBuffer, *colorTargetView, renderArea, clearValue, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ATTACHMENT_LOAD_OP_CLEAR);
532 		else
533 			beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
534 
535 		if (vertexBufferSize > 0)
536 		{
537 			const VkBuffer buffer = vertexBuffer->object();
538 			vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &buffer, &vertexBufferOffset);
539 		}
540 		vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
541 
542 		for (size_t commandIdx = 0; commandIdx < m_params.commands.size(); commandIdx++)
543 			m_params.commands[commandIdx]->addCommands(vk, *cmdBuffer);
544 
545 		if (m_params.usesDynamicRendering)
546 			endRendering(vk, *cmdBuffer);
547 		else
548 			endRenderPass(vk, *cmdBuffer);
549 
550 		transition2DImage(vk, *cmdBuffer, colorTargetImage->object(),
551 						  VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
552 						  VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
553 						  VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
554 						  VK_PIPELINE_STAGE_TRANSFER_BIT);
555 		endCommandBuffer(vk, *cmdBuffer);
556 		submitCommandsAndWait(vk, device, m_context.getUniversalQueue(), cmdBuffer.get());
557 
558 		frame = colorTargetImage->readSurface(m_context.getUniversalQueue(), m_context.getDefaultAllocator(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, zeroOffset, WIDTH, HEIGHT, VK_IMAGE_ASPECT_COLOR_BIT);
559 	}
560 
561 	// Generate reference
562 	{
563 		refImage.setStorage(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM), WIDTH, HEIGHT);
564 		clear(refImage.getAccess(), Vec4(0.0f, 0.0f, 0.0f, 1.0f));
565 
566 		vector<VkRect2D> scissors = m_params.staticScissors;
567 
568 		for (size_t commandIdx = 0; commandIdx < m_params.commands.size(); commandIdx++)
569 		{
570 			scissors = m_params.commands[commandIdx]->updateScissors(scissors);
571 
572 			vector<ColorQuad> quad = m_params.commands[commandIdx]->getQuad();
573 
574 			if (quad.empty())
575 				continue;
576 
577 			for (size_t scissorIdx = 0; scissorIdx < scissors.size(); scissorIdx++)
578 			{
579 				ColorQuad scissoredQuad = m_params.commands[commandIdx]->isScissored() ? scissorQuad(quad[0], scissors[scissorIdx], framebufferSize) : quad[0];
580 
581 				if (scissoredQuad.m_width == 0 || scissoredQuad.m_height == 0)
582 					continue;
583 
584 				clear(getSubregion(refImage.getAccess(), scissoredQuad.m_x, scissoredQuad.m_y, 0, scissoredQuad.m_width, scissoredQuad.m_height, 1), scissoredQuad.m_color);
585 			}
586 		}
587 	}
588 
589 	// Compare results
590 	qpTestResult res = QP_TEST_RESULT_PASS;
591 
592 	if (!intThresholdCompare(log, "Result", "Image comparison result", refImage.getAccess(), frame, UVec4(0), COMPARE_LOG_RESULT))
593 		res = QP_TEST_RESULT_FAIL;
594 
595 	return TestStatus(res, qpGetTestResultName(res));
596 }
597 
createTests(TestCaseGroup * testGroup,bool useDynamicRendering)598 void createTests (TestCaseGroup* testGroup, bool useDynamicRendering)
599 {
600 	TestContext&		testCtx		= testGroup->getTestContext();
601 	const Vec4			red			(1.0f, 0.0f, 0.0f, 1.0f);
602 	const Vec4			green		(0.0f, 1.0f, 0.0f, 1.0f);
603 	const Vec4			blue		(0.0f, 0.0f, 1.0f, 1.0f);
604 	const Vec4			yellow		(1.0f, 1.0f, 0.0f, 1.0f);
605 
606 	// Two quads with a single static scissor
607 	{
608 		TestParams params;
609 		params.dynamicScissor = false;
610 		params.usesDynamicRendering = useDynamicRendering;
611 		params.staticScissors.push_back(makeRect2D(30, 40, WIDTH - 60, HEIGHT - 80));
612 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(10, 10, 50, 50, red)));
613 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(WIDTH - 80, HEIGHT - 100, 30, 40, green)));
614 
615 		testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_two_quads", "", params));
616 	}
617 
618 	// Two clears with a single static scissor
619 	{
620 		TestParams params;
621 		params.dynamicScissor = false;
622 		params.usesDynamicRendering = useDynamicRendering;
623 		params.staticScissors.push_back(makeRect2D(30, 40, WIDTH - 60, HEIGHT - 80));
624 		params.commands.push_back(TestCommandSp(new RectClearTestCommand(10, 10, 50, 50, red)));
625 		params.commands.push_back(TestCommandSp(new RectClearTestCommand(WIDTH - 80, HEIGHT - 100, 30, 40, green)));
626 
627 		testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_two_clears", "", params));
628 	}
629 
630 	// One quad with two static scissors
631 	{
632 		TestParams params;
633 		params.dynamicScissor = false;
634 		params.usesDynamicRendering = useDynamicRendering;
635 		params.staticScissors.push_back(makeRect2D(30, 40, WIDTH - 60, HEIGHT - 70));
636 		params.staticScissors.push_back(makeRect2D(40, 50, WIDTH - 60, HEIGHT - 70));
637 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(10, 10, WIDTH - 10, HEIGHT - 10, red)));
638 
639 		testGroup->addChild(new ScissorTestCase(testCtx, "two_static_scissors_one_quad", "", params));
640 	}
641 
642 	// Static scissor extending outside viewport
643 	{
644 		TestParams params;
645 		params.dynamicScissor = false;
646 		params.usesDynamicRendering = useDynamicRendering;
647 		params.staticScissors.push_back(makeRect2D(30, 40, WIDTH, HEIGHT));
648 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH, HEIGHT + 30, green)));
649 
650 		testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_partially_outside_viewport", "", params));
651 	}
652 
653 	// Static scissor completely outside viewport
654 	{
655 		TestParams params;
656 		params.dynamicScissor = false;
657 		params.usesDynamicRendering = useDynamicRendering;
658 		params.staticScissors.push_back(makeRect2D(WIDTH + 30, HEIGHT + 40, WIDTH, HEIGHT));
659 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(100, 100, 20, 30, green)));
660 
661 		testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_outside_viewport", "", params));
662 	}
663 
664 	// Static scissor outside viewport and touching right border of viewport
665 	{
666 		TestParams params;
667 		params.dynamicScissor = false;
668 		params.usesDynamicRendering = useDynamicRendering;
669 		params.staticScissors.push_back(makeRect2D(WIDTH, 0, WIDTH, HEIGHT));
670 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(100, 100, 20, 30, green)));
671 
672 		testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_viewport_border", "", params));
673 	}
674 
675 	// Static scissor with offset + extent equal to largest positive int32
676 	{
677 		TestParams params;
678 		params.dynamicScissor = false;
679 		params.usesDynamicRendering = useDynamicRendering;
680 		params.staticScissors.push_back(makeRect2D(100, 100, 0x7fffffff - 100, 0x7fffffff - 100));
681 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH, HEIGHT, green)));
682 
683 		testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_max_int32", "", params));
684 	}
685 
686 	// 16 static scissors (minimum number required when multiViewport supported)
687 	{
688 		TestParams params;
689 		params.dynamicScissor = false;
690 		params.usesDynamicRendering = useDynamicRendering;
691 
692 		for (deUint32 i = 0; i < 16; i++)
693 			params.staticScissors.push_back(makeRect2D(10 + i * 3, 20 + i * 2, WIDTH / 2, HEIGHT / 2));
694 
695 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(5, 6, WIDTH - 10, HEIGHT - 2, red)));
696 
697 		testGroup->addChild(new ScissorTestCase(testCtx, "16_static_scissors", "", params));
698 	}
699 
700 	// Two quads with an empty scissor
701 	{
702 		TestParams params;
703 		params.dynamicScissor = false;
704 		params.usesDynamicRendering = useDynamicRendering;
705 		params.staticScissors.push_back(makeRect2D(0, 0, 0, 0));
706 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(10, 10, 50, 50, red)));
707 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(WIDTH - 80, HEIGHT - 100, 30, 40, green)));
708 
709 		testGroup->addChild(new ScissorTestCase(testCtx, "empty_static_scissor", "", params));
710 	}
711 
712 	// Two quads with a single dynamic scissor
713 	{
714 		TestParams params;
715 		params.dynamicScissor = true;
716 		params.usesDynamicRendering = useDynamicRendering;
717 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, 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, "dynamic_scissor_two_quads", "", params));
722 	}
723 
724 	// Empty scissor for the first draw
725 	{
726 		TestParams params;
727 		params.dynamicScissor = true;
728 		params.usesDynamicRendering = useDynamicRendering;
729 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(0, 0, 0, 0)))));
730 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(10, 10, 50, 50, red)));
731 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(30, 40, WIDTH - 60, HEIGHT - 80)))));
732 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(WIDTH - 80, HEIGHT - 100, 30, 40, green)));
733 
734 		testGroup->addChild(new ScissorTestCase(testCtx, "empty_dynamic_scissor_first_draw", "", params));
735 	}
736 
737 	// Two quads with three scissors updated in between
738 	{
739 		TestParams			params;
740 		VkRect2D			rect		= makeRect2D(10, 20, WIDTH - 60, HEIGHT - 70);
741 		vector<VkRect2D>	scissors;
742 
743 		params.dynamicScissor = true;
744 		params.usesDynamicRendering = useDynamicRendering;
745 
746 		scissors.push_back(rect);
747 		rect.offset.x += 10;
748 		rect.offset.y += 10;
749 		scissors.push_back(rect);
750 		rect.offset.x += 10;
751 		rect.offset.y += 10;
752 		scissors.push_back(rect);
753 
754 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors)));
755 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(5, 7, WIDTH - 20, HEIGHT - 9, red)));
756 
757 		for (size_t scissorIdx = 0; scissorIdx < scissors.size(); scissorIdx++)
758 			scissors[scissorIdx].offset.x += 20;
759 
760 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors)));
761 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(8, 12, WIDTH - 2, HEIGHT - 19, green)));
762 
763 		testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_updates_between_draws", "", params));
764 	}
765 
766 	// Scissor updates out of order
767 	{
768 		TestParams			params;
769 		VkRect2D			rect		= makeRect2D(10, 20, WIDTH - 60, HEIGHT - 70);
770 		vector<VkRect2D>	scissors;
771 
772 		params.dynamicScissor = true;
773 		params.usesDynamicRendering = useDynamicRendering;
774 
775 		scissors.push_back(rect);
776 		rect.offset.x += 10;
777 		rect.offset.y += 10;
778 		scissors.push_back(rect);
779 		rect.offset.x += 10;
780 		rect.offset.y += 10;
781 		scissors.push_back(rect);
782 
783 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(2, vector<VkRect2D>(1, scissors[2]))));
784 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(1, vector<VkRect2D>(1, scissors[1]))));
785 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, scissors[0]))));
786 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(5, 7, WIDTH - 20, HEIGHT - 9, red)));
787 
788 		for (size_t scissorIdx = 0; scissorIdx < scissors.size(); scissorIdx++)
789 			scissors[scissorIdx].offset.x += 20;
790 
791 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(1, vector<VkRect2D>(1, scissors[1]))));
792 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, scissors[0]))));
793 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(2, vector<VkRect2D>(1, scissors[2]))));
794 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(8, 12, WIDTH - 2, HEIGHT - 19, green)));
795 
796 		testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_out_of_order_updates", "", params));
797 	}
798 
799 	// Dynamic scissor extending outside viewport
800 	{
801 		TestParams params;
802 		params.dynamicScissor = true;
803 		params.usesDynamicRendering = useDynamicRendering;
804 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(30, 40, WIDTH, HEIGHT)))));
805 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH + 50, HEIGHT + 20, green)));
806 
807 		testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_partially_outside_viewport", "", params));
808 	}
809 
810 	// Dynamic scissor completely outside viewport
811 	{
812 		TestParams params;
813 		params.dynamicScissor = true;
814 		params.usesDynamicRendering = useDynamicRendering;
815 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(WIDTH + 30, HEIGHT + 40, WIDTH, HEIGHT)))));
816 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(100, 100, 20, 30, green)));
817 
818 		testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_outside_viewport", "", params));
819 	}
820 
821 	// Dynamic scissor outside viewport and touching right border of viewport
822 	{
823 		TestParams params;
824 		params.dynamicScissor = true;
825 		params.usesDynamicRendering = useDynamicRendering;
826 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(WIDTH, 0, WIDTH, HEIGHT)))));
827 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(100, 100, 20, 30, green)));
828 
829 		testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_viewport_border", "", params));
830 	}
831 
832 	// Dynamic scissor with offset + extent equal to largest positive int32
833 	{
834 		TestParams params;
835 		params.dynamicScissor = true;
836 		params.usesDynamicRendering = useDynamicRendering;
837 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(100, 100, 0x7fffffff - 100, 0x7fffffff - 100)))));
838 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH, HEIGHT, green)));
839 
840 		testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_max_int32", "", params));
841 	}
842 
843 	// 16 dynamic scissors (minimum number required when multiViewport supported)
844 	{
845 		TestParams			params;
846 		vector<VkRect2D>	scissors;
847 		params.dynamicScissor = true;
848 		params.usesDynamicRendering = useDynamicRendering;
849 
850 		for (deUint32 i = 0; i < 16; i++)
851 			scissors.push_back(makeRect2D(10 + i * 3, 20 + i * 2, WIDTH / 2, HEIGHT / 2));
852 
853 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors)));
854 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(5, 6, WIDTH - 10, HEIGHT - 2, red)));
855 
856 		testGroup->addChild(new ScissorTestCase(testCtx, "16_dynamic_scissors", "", params));
857 	}
858 
859 	// Two clears with a single dynamic scissor
860 	{
861 		TestParams params;
862 		params.dynamicScissor = true;
863 		params.usesDynamicRendering = useDynamicRendering;
864 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, vector<VkRect2D>(1, makeRect2D(30, 40, WIDTH - 60, HEIGHT - 80)))));
865 		params.commands.push_back(TestCommandSp(new RectClearTestCommand(10, 10, 50, 50, red)));
866 		params.commands.push_back(TestCommandSp(new RectClearTestCommand(WIDTH - 80, HEIGHT - 100, 30, 40, green)));
867 
868 		testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_two_clears", "", params));
869 	}
870 
871 	// Mixture of quad draws and clears with dynamic scissor updates
872 	{
873 		TestParams			params;
874 		vector<VkRect2D>	scissors;
875 
876 		params.dynamicScissor = true;
877 		params.usesDynamicRendering = useDynamicRendering;
878 
879 		scissors.push_back(makeRect2D(30, 40, 50, 60));
880 		scissors.push_back(makeRect2D(40, 20, 50, 50));
881 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors)));
882 		params.commands.push_back(TestCommandSp(new RectClearTestCommand(10, 10, 50, 50, red)));
883 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(40, 30, 50, 50, green)));
884 		scissors[1].extent.width -= 20;
885 		scissors[1].extent.height += 30;
886 		scissors[1].offset.x -= 20;
887 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(1, vector<VkRect2D>(1, scissors[1]))));
888 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(70, 70, 50, 50, blue)));
889 		params.commands.push_back(TestCommandSp(new RectClearTestCommand(75, 77, 50, 50, yellow)));
890 
891 		testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_mix", "", params));
892 	}
893 
894 	// Static scissor off by one, inside frame buffer border
895 	{
896 		VkExtent2D size =
897 		{
898 			WIDTH / 2 - 1,
899 			HEIGHT / 2 - 1
900 		};
901 
902 		TestParams params;
903 
904 		params.framebufferSize = size;
905 		params.dynamicScissor = false;
906 		params.usesDynamicRendering = useDynamicRendering;
907 		params.staticScissors.push_back(makeRect2D(1, 1, size.width - 2, size.height - 2));
908 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH * 4, HEIGHT * 4, red)));
909 
910 		testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_framebuffer_border_in", "", params));
911 	}
912 
913 	// Dynamic scissor off by one, inside frame buffer border
914 	{
915 		VkExtent2D size =
916 		{
917 			WIDTH / 2 - 1,
918 			HEIGHT / 2 - 1
919 		};
920 
921 		TestParams			params;
922 		vector<VkRect2D>	scissors;
923 
924 		params.framebufferSize = size;
925 		params.dynamicScissor = true;
926 		params.usesDynamicRendering = useDynamicRendering;
927 
928 		scissors.push_back(makeRect2D(1, 1, size.width - 2, size.height - 2));
929 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors)));
930 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH * 4, HEIGHT * 4, red)));
931 
932 		testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_framebuffer_border_in", "", params));
933 	}
934 
935 	// Static scissor off by one, outside frame buffer border
936 	{
937 		VkExtent2D size =
938 		{
939 			WIDTH / 2 - 1,
940 			HEIGHT / 2 - 1
941 		};
942 
943 		TestParams params;
944 
945 		params.framebufferSize = size;
946 		params.dynamicScissor = false;
947 		params.usesDynamicRendering = useDynamicRendering;
948 
949 		params.staticScissors.push_back(makeRect2D(0, 0, size.width + 1, size.height + 1));
950 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH * 4, HEIGHT * 4, red)));
951 
952 		testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_framebuffer_border_out", "", params));
953 	}
954 
955 	// Dynamic scissor off by one, outside frame buffer border
956 	{
957 		VkExtent2D size =
958 		{
959 			WIDTH / 2 - 1,
960 			HEIGHT / 2 - 1
961 		};
962 
963 		TestParams			params;
964 		vector<VkRect2D>	scissors;
965 
966 		params.framebufferSize = size;
967 		params.dynamicScissor = true;
968 		params.usesDynamicRendering = useDynamicRendering;
969 
970 		scissors.push_back(makeRect2D(0, 0, size.width + 1, size.height + 1));
971 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors)));
972 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH * 4, HEIGHT * 4, red)));
973 
974 		testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_framebuffer_border_out", "", params));
975 	}
976 
977 	// Static oversized scissor, exceeds frame buffer and image attachment sizes
978 	{
979 		VkExtent2D size =
980 		{
981 			WIDTH / 2 - 1,
982 			HEIGHT / 2 - 1
983 		};
984 
985 		TestParams params;
986 
987 		params.framebufferSize = size;
988 		params.dynamicScissor = false;
989 		params.usesDynamicRendering = useDynamicRendering;
990 
991 		params.staticScissors.push_back(makeRect2D(0, 0, WIDTH * 2, HEIGHT * 2));
992 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH * 4, HEIGHT * 4, red)));
993 
994 		testGroup->addChild(new ScissorTestCase(testCtx, "static_scissor_oversized", "", params));
995 	}
996 
997 	// Dynamic oversized scissor, exceeds frame buffer and image attachment sizes
998 	{
999 		VkExtent2D size =
1000 		{
1001 			WIDTH / 2 - 1,
1002 			HEIGHT / 2 - 1
1003 		};
1004 
1005 		TestParams			params;
1006 		vector<VkRect2D>	scissors;
1007 
1008 		params.framebufferSize = size;
1009 		params.dynamicScissor = true;
1010 		params.usesDynamicRendering = useDynamicRendering;
1011 
1012 		scissors.push_back(makeRect2D(0, 0, WIDTH * 2, HEIGHT * 2));
1013 		params.commands.push_back(TestCommandSp(new DynamicScissorTestCommand(0, scissors)));
1014 		params.commands.push_back(TestCommandSp(new QuadDrawTestCommand(0, 0, WIDTH * 4, HEIGHT * 4, red)));
1015 
1016 		testGroup->addChild(new ScissorTestCase(testCtx, "dynamic_scissor_oversized", "", params));
1017 	}
1018 }
1019 
1020 }	// anonymous
1021 
createScissorTests(TestContext & testCtx,bool useDynamicRendering)1022 TestCaseGroup*	createScissorTests (TestContext& testCtx, bool useDynamicRendering)
1023 {
1024 	return createTestGroup(testCtx, "scissor", "Scissor tests", createTests, useDynamicRendering);
1025 }
1026 
1027 }	// Draw
1028 }	// vkt
1029