• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 The Khronos Group Inc.
6  * Copyright (c) 2014 The Android Open Source Project
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 Scissor tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktFragmentOperationsScissorTests.hpp"
26 #include "vktFragmentOperationsScissorMultiViewportTests.hpp"
27 #include "vktTestCaseUtil.hpp"
28 #include "vktTestGroupUtil.hpp"
29 
30 #include "vkDefs.hpp"
31 #include "vkRefUtil.hpp"
32 #include "vkTypeUtil.hpp"
33 #include "vkMemUtil.hpp"
34 #include "vkPrograms.hpp"
35 #include "vkImageUtil.hpp"
36 #include "vkCmdUtil.hpp"
37 #include "vkObjUtil.hpp"
38 
39 #include "tcuTestLog.hpp"
40 #include "tcuVector.hpp"
41 #include "tcuImageCompare.hpp"
42 
43 #include "deUniquePtr.hpp"
44 #include "deRandom.hpp"
45 
46 namespace vkt
47 {
48 namespace FragmentOperations
49 {
50 using namespace vk;
51 using de::UniquePtr;
52 using de::MovePtr;
53 using tcu::Vec4;
54 using tcu::Vec2;
55 using tcu::IVec2;
56 using tcu::IVec4;
57 
58 namespace
59 {
60 
61 //! What primitives will be drawn by the test case.
62 enum TestPrimitive
63 {
64 	TEST_PRIMITIVE_POINTS,			//!< Many points.
65 	TEST_PRIMITIVE_LINES,			//!< Many short lines.
66 	TEST_PRIMITIVE_TRIANGLES,		//!< Many small triangles.
67 	TEST_PRIMITIVE_BIG_LINE,		//!< One line crossing the whole render area.
68 	TEST_PRIMITIVE_BIG_TRIANGLE,	//!< One triangle covering the whole render area.
69 };
70 
71 struct VertexData
72 {
73 	Vec4	position;
74 	Vec4	color;
75 };
76 
77 //! Parameters used by the test case.
78 struct CaseDef
79 {
80 	Vec4			renderArea;		//!< (ox, oy, w, h), where origin (0,0) is the top-left corner of the viewport. Width and height are in range [0, 1].
81 	Vec4			scissorArea;	//!< scissored area (ox, oy, w, h)
82 	TestPrimitive	primitive;
83 };
84 
85 template<typename T>
sizeInBytes(const std::vector<T> & vec)86 inline VkDeviceSize sizeInBytes(const std::vector<T>& vec)
87 {
88 	return vec.size() * sizeof(vec[0]);
89 }
90 
makeImageCreateInfo(const VkFormat format,const IVec2 & size,VkImageUsageFlags usage)91 VkImageCreateInfo makeImageCreateInfo (const VkFormat format, const IVec2& size, VkImageUsageFlags usage)
92 {
93 	const VkImageCreateInfo imageParams =
94 	{
95 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,			// VkStructureType			sType;
96 		DE_NULL,										// const void*				pNext;
97 		(VkImageCreateFlags)0,							// VkImageCreateFlags		flags;
98 		VK_IMAGE_TYPE_2D,								// VkImageType				imageType;
99 		format,											// VkFormat					format;
100 		makeExtent3D(size.x(), size.y(), 1),			// VkExtent3D				extent;
101 		1u,												// deUint32					mipLevels;
102 		1u,												// deUint32					arrayLayers;
103 		VK_SAMPLE_COUNT_1_BIT,							// VkSampleCountFlagBits	samples;
104 		VK_IMAGE_TILING_OPTIMAL,						// VkImageTiling			tiling;
105 		usage,											// VkImageUsageFlags		usage;
106 		VK_SHARING_MODE_EXCLUSIVE,						// VkSharingMode			sharingMode;
107 		0u,												// deUint32					queueFamilyIndexCount;
108 		DE_NULL,										// const deUint32*			pQueueFamilyIndices;
109 		VK_IMAGE_LAYOUT_UNDEFINED,						// VkImageLayout			initialLayout;
110 	};
111 	return imageParams;
112 }
113 
makeGraphicsPipeline(const DeviceInterface & vk,const VkDevice device,const VkPipelineLayout pipelineLayout,const VkRenderPass renderPass,const VkShaderModule vertexModule,const VkShaderModule fragmentModule,const IVec2 renderSize,const IVec4 scissorArea,const VkPrimitiveTopology topology)114 Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface&		vk,
115 									   const VkDevice				device,
116 									   const VkPipelineLayout		pipelineLayout,
117 									   const VkRenderPass			renderPass,
118 									   const VkShaderModule			vertexModule,
119 									   const VkShaderModule			fragmentModule,
120 									   const IVec2					renderSize,
121 									   const IVec4					scissorArea,	//!< (ox, oy, w, h)
122 									   const VkPrimitiveTopology	topology)
123 {
124 	const VkVertexInputBindingDescription vertexInputBindingDescription =
125 	{
126 		0u,								// uint32_t				binding;
127 		sizeof(VertexData),				// uint32_t				stride;
128 		VK_VERTEX_INPUT_RATE_VERTEX,	// VkVertexInputRate	inputRate;
129 	};
130 
131 	const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] =
132 	{
133 		{
134 			0u,								// uint32_t		location;
135 			0u,								// uint32_t		binding;
136 			VK_FORMAT_R32G32B32A32_SFLOAT,	// VkFormat		format;
137 			0u,								// uint32_t		offset;
138 		},
139 		{
140 			1u,								// uint32_t		location;
141 			0u,								// uint32_t		binding;
142 			VK_FORMAT_R32G32B32A32_SFLOAT,	// VkFormat		format;
143 			sizeof(Vec4),					// uint32_t		offset;
144 		},
145 	};
146 
147 	const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
148 	{
149 		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	// VkStructureType                             sType;
150 		DE_NULL,													// const void*                                 pNext;
151 		(VkPipelineVertexInputStateCreateFlags)0,					// VkPipelineVertexInputStateCreateFlags       flags;
152 		1u,															// uint32_t                                    vertexBindingDescriptionCount;
153 		&vertexInputBindingDescription,								// const VkVertexInputBindingDescription*      pVertexBindingDescriptions;
154 		DE_LENGTH_OF_ARRAY(vertexInputAttributeDescriptions),		// uint32_t                                    vertexAttributeDescriptionCount;
155 		vertexInputAttributeDescriptions,							// const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions;
156 	};
157 
158 	const VkRect2D			scissor		=
159 	{
160 		makeOffset2D(scissorArea.x(), scissorArea.y()),
161 		makeExtent2D(scissorArea.z(), scissorArea.w())
162 	};
163 
164 	const std::vector<VkViewport>	viewports	(1, makeViewport(renderSize));
165 	const std::vector<VkRect2D>		scissors	(1, scissor);
166 
167 	return vk::makeGraphicsPipeline(vk,						// const DeviceInterface&                        vk
168 									device,					// const VkDevice                                device
169 									pipelineLayout,			// const VkPipelineLayout                        pipelineLayout
170 									vertexModule,			// const VkShaderModule                          vertexShaderModule
171 									DE_NULL,				// const VkShaderModule                          tessellationControlModule
172 									DE_NULL,				// const VkShaderModule                          tessellationEvalModule
173 									DE_NULL,				// const VkShaderModule                          geometryShaderModule
174 									fragmentModule,			// const VkShaderModule                          fragmentShaderModule
175 									renderPass,				// const VkRenderPass                            renderPass
176 									viewports,				// const std::vector<VkViewport>&                viewports
177 									scissors,				// const std::vector<VkRect2D>&                  scissors
178 									topology,				// const VkPrimitiveTopology                     topology
179 									0u,						// const deUint32                                subpass
180 									0u,						// const deUint32                                patchControlPoints
181 									&vertexInputStateInfo);	// const VkPipelineVertexInputStateCreateInfo*   vertexInputStateCreateInfo
182 }
183 
makeVertex(const float x,const float y,const Vec4 & color)184 inline VertexData makeVertex (const float x, const float y, const Vec4& color)
185 {
186 	const VertexData data = { Vec4(x, y, 0.0f, 1.0f), color };
187 	return data;
188 }
189 
genVertices(const TestPrimitive primitive,const Vec4 & renderArea,const Vec4 & primitiveColor)190 std::vector<VertexData> genVertices (const TestPrimitive primitive, const Vec4& renderArea, const Vec4& primitiveColor)
191 {
192 	std::vector<VertexData> vertices;
193 	de::Random				rng			(1234);
194 
195 	const float	x0		= 2.0f * renderArea.x() - 1.0f;
196 	const float y0		= 2.0f * renderArea.y() - 1.0f;
197 	const float	rx		= 2.0f * renderArea.z();
198 	const float	ry		= 2.0f * renderArea.w();
199 	const float	size	= 0.2f;
200 
201 	switch (primitive)
202 	{
203 		case TEST_PRIMITIVE_POINTS:
204 			for (int i = 0; i < 50; ++i)
205 			{
206 				const float x = x0 + rng.getFloat(0.0f, rx);
207 				const float y = y0 + rng.getFloat(0.0f, ry);
208 				vertices.push_back(makeVertex(x, y, primitiveColor));
209 			}
210 			break;
211 
212 		case TEST_PRIMITIVE_LINES:
213 			for (int i = 0; i < 30; ++i)
214 			{
215 				const float x = x0 + rng.getFloat(0.0f, rx - size);
216 				const float y = y0 + rng.getFloat(0.0f, ry - size);
217 				vertices.push_back(makeVertex(x,        y,        primitiveColor));
218 				vertices.push_back(makeVertex(x + size, y + size, primitiveColor));
219 			}
220 			break;
221 
222 		case TEST_PRIMITIVE_TRIANGLES:
223 			for (int i = 0; i < 20; ++i)
224 			{
225 				const float x = x0 + rng.getFloat(0.0f, rx - size);
226 				const float y = y0 + rng.getFloat(0.0f, ry - size);
227 				vertices.push_back(makeVertex(x,             y,        primitiveColor));
228 				vertices.push_back(makeVertex(x + size/2.0f, y + size, primitiveColor));
229 				vertices.push_back(makeVertex(x + size,      y,        primitiveColor));
230 			}
231 			break;
232 
233 		case TEST_PRIMITIVE_BIG_LINE:
234 			vertices.push_back(makeVertex(x0,      y0,      primitiveColor));
235 			vertices.push_back(makeVertex(x0 + rx, y0 + ry, primitiveColor));
236 			break;
237 
238 		case TEST_PRIMITIVE_BIG_TRIANGLE:
239 			vertices.push_back(makeVertex(x0,           y0,      primitiveColor));
240 			vertices.push_back(makeVertex(x0 + rx/2.0f, y0 + ry, primitiveColor));
241 			vertices.push_back(makeVertex(x0 + rx,      y0,      primitiveColor));
242 			break;
243 	}
244 
245 	return vertices;
246 }
247 
getTopology(const TestPrimitive primitive)248 VkPrimitiveTopology	getTopology (const TestPrimitive primitive)
249 {
250 	switch (primitive)
251 	{
252 		case TEST_PRIMITIVE_POINTS:			return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
253 
254 		case TEST_PRIMITIVE_LINES:
255 		case TEST_PRIMITIVE_BIG_LINE:		return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
256 
257 		case TEST_PRIMITIVE_TRIANGLES:
258 		case TEST_PRIMITIVE_BIG_TRIANGLE:	return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
259 
260 		default:
261 			DE_ASSERT(0);
262 			return VK_PRIMITIVE_TOPOLOGY_LAST;
263 	}
264 }
265 
266 //! Transform from normalized coords to framebuffer space.
getAreaRect(const Vec4 & area,const int width,const int height)267 inline IVec4 getAreaRect (const Vec4& area, const int width, const int height)
268 {
269 	return IVec4(static_cast<deInt32>(static_cast<float>(width)  * area.x()),
270 				 static_cast<deInt32>(static_cast<float>(height) * area.y()),
271 				 static_cast<deInt32>(static_cast<float>(width)  * area.z()),
272 				 static_cast<deInt32>(static_cast<float>(height) * area.w()));
273 }
274 
applyScissor(tcu::PixelBufferAccess imageAccess,const Vec4 & floatScissorArea,const Vec4 & clearColor)275 void applyScissor (tcu::PixelBufferAccess imageAccess, const Vec4& floatScissorArea, const Vec4& clearColor)
276 {
277 	const IVec4	scissorRect	(getAreaRect(floatScissorArea, imageAccess.getWidth(), imageAccess.getHeight()));
278 	const int	sx0			= scissorRect.x();
279 	const int	sx1			= scissorRect.x() + scissorRect.z();
280 	const int	sy0			= scissorRect.y();
281 	const int	sy1			= scissorRect.y() + scissorRect.w();
282 
283 	for (int y = 0; y < imageAccess.getHeight(); ++y)
284 	for (int x = 0; x < imageAccess.getWidth(); ++x)
285 	{
286 		// Fragments outside fail the scissor test.
287 		if (x < sx0 || x >= sx1 || y < sy0 || y >= sy1)
288 			imageAccess.setPixel(clearColor, x, y);
289 	}
290 }
291 
initPrograms(SourceCollections & programCollection,const CaseDef caseDef)292 void initPrograms (SourceCollections& programCollection, const CaseDef caseDef)
293 {
294 	DE_UNREF(caseDef);
295 
296 	// Vertex shader
297 	{
298 		const bool usePointSize = (caseDef.primitive == TEST_PRIMITIVE_POINTS);
299 
300 		std::ostringstream src;
301 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
302 			<< "\n"
303 			<< "layout(location = 0) in  vec4 in_position;\n"
304 			<< "layout(location = 1) in  vec4 in_color;\n"
305 			<< "layout(location = 0) out vec4 o_color;\n"
306 			<< "\n"
307 			<< "out gl_PerVertex {\n"
308 			<< "    vec4  gl_Position;\n"
309 			<< (usePointSize ? "    float gl_PointSize;\n" : "")
310 			<< "};\n"
311 			<< "\n"
312 			<< "void main(void)\n"
313 			<< "{\n"
314 			<< "    gl_Position  = in_position;\n"
315 			<< (usePointSize ? "    gl_PointSize = 1.0;\n" : "")
316 			<< "    o_color      = in_color;\n"
317 			<< "}\n";
318 
319 		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
320 	}
321 
322 	// Fragment shader
323 	{
324 		std::ostringstream src;
325 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
326 			<< "\n"
327 			<< "layout(location = 0) in  vec4 in_color;\n"
328 			<< "layout(location = 0) out vec4 o_color;\n"
329 			<< "\n"
330 			<< "void main(void)\n"
331 			<< "{\n"
332 			<< "    o_color = in_color;\n"
333 			<< "}\n";
334 
335 		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
336 	}
337 }
338 
339 class ScissorRenderer
340 {
341 public:
ScissorRenderer(Context & context,const CaseDef caseDef,const IVec2 & renderSize,const VkFormat colorFormat,const Vec4 & primitiveColor,const Vec4 & clearColor)342 	ScissorRenderer (Context& context, const CaseDef caseDef, const IVec2& renderSize, const VkFormat colorFormat, const Vec4& primitiveColor, const Vec4& clearColor)
343 		: m_renderSize				(renderSize)
344 		, m_colorFormat				(colorFormat)
345 		, m_colorSubresourceRange	(makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u))
346 		, m_primitiveColor			(primitiveColor)
347 		, m_clearColor				(clearColor)
348 		, m_vertices				(genVertices(caseDef.primitive, caseDef.renderArea, m_primitiveColor))
349 		, m_vertexBufferSize		(sizeInBytes(m_vertices))
350 		, m_topology				(getTopology(caseDef.primitive))
351 	{
352 		const DeviceInterface&		vk					= context.getDeviceInterface();
353 		const VkDevice				device				= context.getDevice();
354 		const deUint32				queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
355 		Allocator&					allocator			= context.getDefaultAllocator();
356 
357 		m_colorImage			= makeImage(vk, device, makeImageCreateInfo(m_colorFormat, m_renderSize, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
358 		m_colorImageAlloc		= bindImage(vk, device, allocator, *m_colorImage, MemoryRequirement::Any);
359 		m_colorAttachment		= makeImageView(vk, device, *m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, m_colorSubresourceRange);
360 
361 		m_vertexBuffer			= makeBuffer(vk, device, m_vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
362 		m_vertexBufferAlloc		= bindBuffer(vk, device, allocator, *m_vertexBuffer, MemoryRequirement::HostVisible);
363 
364 		{
365 			deMemcpy(m_vertexBufferAlloc->getHostPtr(), &m_vertices[0], static_cast<std::size_t>(m_vertexBufferSize));
366 			flushAlloc(vk, device, *m_vertexBufferAlloc);
367 		}
368 
369 		m_vertexModule				= createShaderModule	(vk, device, context.getBinaryCollection().get("vert"), 0u);
370 		m_fragmentModule			= createShaderModule	(vk, device, context.getBinaryCollection().get("frag"), 0u);
371 		m_renderPass				= makeRenderPass		(vk, device, m_colorFormat);
372 		m_framebuffer				= makeFramebuffer		(vk, device, *m_renderPass, m_colorAttachment.get(),
373 															 static_cast<deUint32>(m_renderSize.x()),  static_cast<deUint32>(m_renderSize.y()));
374 		m_pipelineLayout			= makePipelineLayout	(vk, device);
375 		m_cmdPool					= createCommandPool		(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
376 		m_cmdBuffer					= allocateCommandBuffer	(vk, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
377 
378 	}
379 
draw(Context & context,const Vec4 & scissorAreaFloat,const VkBuffer colorBuffer) const380 	void draw (Context& context, const Vec4& scissorAreaFloat, const VkBuffer colorBuffer) const
381 	{
382 		const DeviceInterface&		vk			= context.getDeviceInterface();
383 		const VkDevice				device		= context.getDevice();
384 		const VkQueue				queue		= context.getUniversalQueue();
385 
386 		// New pipeline, because we're modifying scissor (we don't use dynamic state).
387 		const Unique<VkPipeline>	pipeline	(makeGraphicsPipeline(vk, device, *m_pipelineLayout, *m_renderPass, *m_vertexModule, *m_fragmentModule,
388 												 m_renderSize, getAreaRect(scissorAreaFloat, m_renderSize.x(), m_renderSize.y()), m_topology));
389 
390 		beginCommandBuffer(vk, *m_cmdBuffer);
391 
392 		beginRenderPass(vk, *m_cmdBuffer, *m_renderPass, *m_framebuffer, makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), m_clearColor);
393 
394 		vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
395 		{
396 			const VkDeviceSize vertexBufferOffset = 0ull;
397 			vk.cmdBindVertexBuffers(*m_cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &vertexBufferOffset);
398 		}
399 
400 		vk.cmdDraw(*m_cmdBuffer, static_cast<deUint32>(m_vertices.size()), 1u, 0u, 0u);
401 		endRenderPass(vk, *m_cmdBuffer);
402 
403 		copyImageToBuffer(vk, *m_cmdBuffer, *m_colorImage, colorBuffer, m_renderSize);
404 
405 		endCommandBuffer(vk, *m_cmdBuffer);
406 		submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
407 		context.resetCommandPoolForVKSC(device, *m_cmdPool);
408 	}
409 
410 private:
411 	const IVec2						m_renderSize;
412 	const VkFormat					m_colorFormat;
413 	const VkImageSubresourceRange	m_colorSubresourceRange;
414 	const Vec4						m_primitiveColor;
415 	const Vec4						m_clearColor;
416 	const std::vector<VertexData>	m_vertices;
417 	const VkDeviceSize				m_vertexBufferSize;
418 	const VkPrimitiveTopology		m_topology;
419 
420 	Move<VkImage>					m_colorImage;
421 	MovePtr<Allocation>				m_colorImageAlloc;
422 	Move<VkImageView>				m_colorAttachment;
423 	Move<VkBuffer>					m_vertexBuffer;
424 	MovePtr<Allocation>				m_vertexBufferAlloc;
425 	Move<VkShaderModule>			m_vertexModule;
426 	Move<VkShaderModule>			m_fragmentModule;
427 	Move<VkRenderPass>				m_renderPass;
428 	Move<VkFramebuffer>				m_framebuffer;
429 	Move<VkPipelineLayout>			m_pipelineLayout;
430 	Move<VkCommandPool>				m_cmdPool;
431 	Move<VkCommandBuffer>			m_cmdBuffer;
432 
433 	// "deleted"
434 						ScissorRenderer	(const ScissorRenderer&);
435 	ScissorRenderer&	operator=		(const ScissorRenderer&);
436 };
437 
test(Context & context,const CaseDef caseDef)438 tcu::TestStatus test (Context& context, const CaseDef caseDef)
439 {
440 	const DeviceInterface&			vk							= context.getDeviceInterface();
441 	const VkDevice					device						= context.getDevice();
442 	Allocator&						allocator					= context.getDefaultAllocator();
443 
444 	const IVec2						renderSize					(128, 128);
445 	const VkFormat					colorFormat					= VK_FORMAT_R8G8B8A8_UNORM;
446 	const Vec4						scissorFullArea				(0.0f, 0.0f, 1.0f, 1.0f);
447 	const Vec4						primitiveColor				(1.0f, 1.0f, 1.0f, 1.0f);
448 	const Vec4						clearColor					(0.5f, 0.5f, 1.0f, 1.0f);
449 
450 	const VkDeviceSize				colorBufferSize				= renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
451 	const Unique<VkBuffer>			colorBufferFull				(makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
452 	const UniquePtr<Allocation>		colorBufferFullAlloc		(bindBuffer(vk, device, allocator, *colorBufferFull, MemoryRequirement::HostVisible));
453 
454 	const Unique<VkBuffer>			colorBufferScissored		(makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
455 	const UniquePtr<Allocation>		colorBufferScissoredAlloc	(bindBuffer(vk, device, allocator, *colorBufferScissored, MemoryRequirement::HostVisible));
456 
457 	zeroBuffer(vk, device, *colorBufferFullAlloc, colorBufferSize);
458 	zeroBuffer(vk, device, *colorBufferScissoredAlloc, colorBufferSize);
459 
460 	// Draw
461 	{
462 		const ScissorRenderer renderer (context, caseDef, renderSize, colorFormat, primitiveColor, clearColor);
463 
464 		renderer.draw(context, scissorFullArea, *colorBufferFull);
465 		renderer.draw(context, caseDef.scissorArea, *colorBufferScissored);
466 	}
467 
468 	// Log image
469 	{
470 		invalidateAlloc(vk, device, *colorBufferFullAlloc);
471 		invalidateAlloc(vk, device, *colorBufferScissoredAlloc);
472 
473 		const tcu::ConstPixelBufferAccess	resultImage		(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1u, colorBufferScissoredAlloc->getHostPtr());
474 		tcu::PixelBufferAccess				referenceImage	(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1u, colorBufferFullAlloc->getHostPtr());
475 
476 		// Apply scissor to the full image, so we can compare it with the result image.
477 		applyScissor (referenceImage, caseDef.scissorArea, clearColor);
478 
479 		// Images should now match.
480 		if (!tcu::floatThresholdCompare(context.getTestContext().getLog(), "color", "Image compare", referenceImage, resultImage, Vec4(0.02f), tcu::COMPARE_LOG_RESULT))
481 			return tcu::TestStatus::fail("Rendered image is not correct");
482 	}
483 
484 	return tcu::TestStatus::pass("OK");
485 }
486 
487 //! \note The ES 2.0 scissoring tests included color/depth/stencil clear cases, but these operations are not affected by scissor test in Vulkan.
488 //!       Scissor is part of the pipeline state and pipeline only affects the drawing commands.
createTestsInGroup(tcu::TestCaseGroup * scissorGroup)489 void createTestsInGroup (tcu::TestCaseGroup* scissorGroup)
490 {
491 	tcu::TestContext& testCtx = scissorGroup->getTestContext();
492 
493 	struct TestSpec
494 	{
495 		const char*		name;
496 		const char*		description;
497 		CaseDef			caseDef;
498 	};
499 
500 	const Vec4	areaFull			(0.0f, 0.0f, 1.0f, 1.0f);
501 	const Vec4	areaCropped			(0.2f, 0.2f, 0.6f, 0.6f);
502 	const Vec4	areaCroppedMore		(0.4f, 0.4f, 0.2f, 0.2f);
503 	const Vec4	areaLeftHalf		(0.0f, 0.0f, 0.5f, 1.0f);
504 	const Vec4	areaRightHalf		(0.5f, 0.0f, 0.5f, 1.0f);
505 
506 	// Points
507 	{
508 		MovePtr<tcu::TestCaseGroup> primitiveGroup (new tcu::TestCaseGroup(testCtx, "points", ""));
509 
510 		const TestSpec	cases[] =
511 		{
512 			{ "inside",				"Points fully inside the scissor area",		{ areaFull,		areaFull,		TEST_PRIMITIVE_POINTS } },
513 			{ "partially_inside",	"Points partially inside the scissor area",	{ areaFull,		areaCropped,	TEST_PRIMITIVE_POINTS } },
514 			{ "outside",			"Points fully outside the scissor area",	{ areaLeftHalf,	areaRightHalf,	TEST_PRIMITIVE_POINTS } },
515 		};
516 
517 		for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
518 			addFunctionCaseWithPrograms(primitiveGroup.get(), cases[i].name, cases[i].description, initPrograms, test, cases[i].caseDef);
519 
520 		scissorGroup->addChild(primitiveGroup.release());
521 	}
522 
523 	// Lines
524 	{
525 		MovePtr<tcu::TestCaseGroup> primitiveGroup (new tcu::TestCaseGroup(testCtx, "lines", ""));
526 
527 		const TestSpec	cases[] =
528 		{
529 			{ "inside",				"Lines fully inside the scissor area",		{ areaFull,		areaFull,			TEST_PRIMITIVE_LINES	} },
530 			{ "partially_inside",	"Lines partially inside the scissor area",	{ areaFull,		areaCropped,		TEST_PRIMITIVE_LINES	} },
531 			{ "outside",			"Lines fully outside the scissor area",		{ areaLeftHalf,	areaRightHalf,		TEST_PRIMITIVE_LINES	} },
532 			{ "crossing",			"A line crossing the scissor area",			{ areaFull,		areaCroppedMore,	TEST_PRIMITIVE_BIG_LINE	} },
533 		};
534 
535 		for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
536 			addFunctionCaseWithPrograms(primitiveGroup.get(), cases[i].name, cases[i].description, initPrograms, test, cases[i].caseDef);
537 
538 		scissorGroup->addChild(primitiveGroup.release());
539 	}
540 
541 	// Triangles
542 	{
543 		MovePtr<tcu::TestCaseGroup> primitiveGroup (new tcu::TestCaseGroup(testCtx, "triangles", ""));
544 
545 		const TestSpec	cases[] =
546 		{
547 			{ "inside",				"Triangles fully inside the scissor area",		{ areaFull,		areaFull,			TEST_PRIMITIVE_TRIANGLES	} },
548 			{ "partially_inside",	"Triangles partially inside the scissor area",	{ areaFull,		areaCropped,		TEST_PRIMITIVE_TRIANGLES	} },
549 			{ "outside",			"Triangles fully outside the scissor area",		{ areaLeftHalf,	areaRightHalf,		TEST_PRIMITIVE_TRIANGLES	} },
550 			{ "crossing",			"A triangle crossing the scissor area",			{ areaFull,		areaCroppedMore,	TEST_PRIMITIVE_BIG_TRIANGLE	} },
551 		};
552 
553 		for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
554 			addFunctionCaseWithPrograms(primitiveGroup.get(), cases[i].name, cases[i].description, initPrograms, test, cases[i].caseDef);
555 
556 		scissorGroup->addChild(primitiveGroup.release());
557 	}
558 
559 	// Mulit-viewport scissor
560 	{
561 		scissorGroup->addChild(createScissorMultiViewportTests(testCtx));
562 	}
563 }
564 
565 } // anonymous
566 
createScissorTests(tcu::TestContext & testCtx)567 tcu::TestCaseGroup* createScissorTests (tcu::TestContext& testCtx)
568 {
569 	return createTestGroup(testCtx, "scissor", "Scissor tests", createTestsInGroup);
570 }
571 
572 } // FragmentOperations
573 } // vkt
574