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 #include "vktFragmentOperationsMakeUtil.hpp"
30 
31 #include "vkDefs.hpp"
32 #include "vkRefUtil.hpp"
33 #include "vkTypeUtil.hpp"
34 #include "vkMemUtil.hpp"
35 #include "vkPrograms.hpp"
36 #include "vkImageUtil.hpp"
37 #include "vkCmdUtil.hpp"
38 #include "vkObjUtil.hpp"
39 
40 #include "tcuTestLog.hpp"
41 #include "tcuVector.hpp"
42 #include "tcuImageCompare.hpp"
43 
44 #include "deUniquePtr.hpp"
45 #include "deRandom.hpp"
46 
47 namespace vkt
48 {
49 namespace FragmentOperations
50 {
51 using namespace vk;
52 using de::UniquePtr;
53 using de::MovePtr;
54 using tcu::Vec4;
55 using tcu::Vec2;
56 using tcu::IVec2;
57 using tcu::IVec4;
58 
59 namespace
60 {
61 
62 //! What primitives will be drawn by the test case.
63 enum TestPrimitive
64 {
65 	TEST_PRIMITIVE_POINTS,			//!< Many points.
66 	TEST_PRIMITIVE_LINES,			//!< Many short lines.
67 	TEST_PRIMITIVE_TRIANGLES,		//!< Many small triangles.
68 	TEST_PRIMITIVE_BIG_LINE,		//!< One line crossing the whole render area.
69 	TEST_PRIMITIVE_BIG_TRIANGLE,	//!< One triangle covering the whole render area.
70 };
71 
72 struct VertexData
73 {
74 	Vec4	position;
75 	Vec4	color;
76 };
77 
78 //! Parameters used by the test case.
79 struct CaseDef
80 {
81 	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].
82 	Vec4			scissorArea;	//!< scissored area (ox, oy, w, h)
83 	TestPrimitive	primitive;
84 };
85 
86 template<typename T>
sizeInBytes(const std::vector<T> & vec)87 inline VkDeviceSize sizeInBytes(const std::vector<T>& vec)
88 {
89 	return vec.size() * sizeof(vec[0]);
90 }
91 
makeImageCreateInfo(const VkFormat format,const IVec2 & size,VkImageUsageFlags usage)92 VkImageCreateInfo makeImageCreateInfo (const VkFormat format, const IVec2& size, VkImageUsageFlags usage)
93 {
94 	const VkImageCreateInfo imageParams =
95 	{
96 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,			// VkStructureType			sType;
97 		DE_NULL,										// const void*				pNext;
98 		(VkImageCreateFlags)0,							// VkImageCreateFlags		flags;
99 		VK_IMAGE_TYPE_2D,								// VkImageType				imageType;
100 		format,											// VkFormat					format;
101 		makeExtent3D(size.x(), size.y(), 1),			// VkExtent3D				extent;
102 		1u,												// deUint32					mipLevels;
103 		1u,												// deUint32					arrayLayers;
104 		VK_SAMPLE_COUNT_1_BIT,							// VkSampleCountFlagBits	samples;
105 		VK_IMAGE_TILING_OPTIMAL,						// VkImageTiling			tiling;
106 		usage,											// VkImageUsageFlags		usage;
107 		VK_SHARING_MODE_EXCLUSIVE,						// VkSharingMode			sharingMode;
108 		0u,												// deUint32					queueFamilyIndexCount;
109 		DE_NULL,										// const deUint32*			pQueueFamilyIndices;
110 		VK_IMAGE_LAYOUT_UNDEFINED,						// VkImageLayout			initialLayout;
111 	};
112 	return imageParams;
113 }
114 
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)115 Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface&		vk,
116 									   const VkDevice				device,
117 									   const VkPipelineLayout		pipelineLayout,
118 									   const VkRenderPass			renderPass,
119 									   const VkShaderModule			vertexModule,
120 									   const VkShaderModule			fragmentModule,
121 									   const IVec2					renderSize,
122 									   const IVec4					scissorArea,	//!< (ox, oy, w, h)
123 									   const VkPrimitiveTopology	topology)
124 {
125 	const VkVertexInputBindingDescription vertexInputBindingDescription =
126 	{
127 		0u,								// uint32_t				binding;
128 		sizeof(VertexData),				// uint32_t				stride;
129 		VK_VERTEX_INPUT_RATE_VERTEX,	// VkVertexInputRate	inputRate;
130 	};
131 
132 	const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] =
133 	{
134 		{
135 			0u,								// uint32_t		location;
136 			0u,								// uint32_t		binding;
137 			VK_FORMAT_R32G32B32A32_SFLOAT,	// VkFormat		format;
138 			0u,								// uint32_t		offset;
139 		},
140 		{
141 			1u,								// uint32_t		location;
142 			0u,								// uint32_t		binding;
143 			VK_FORMAT_R32G32B32A32_SFLOAT,	// VkFormat		format;
144 			sizeof(Vec4),					// uint32_t		offset;
145 		},
146 	};
147 
148 	const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
149 	{
150 		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	// VkStructureType                             sType;
151 		DE_NULL,													// const void*                                 pNext;
152 		(VkPipelineVertexInputStateCreateFlags)0,					// VkPipelineVertexInputStateCreateFlags       flags;
153 		1u,															// uint32_t                                    vertexBindingDescriptionCount;
154 		&vertexInputBindingDescription,								// const VkVertexInputBindingDescription*      pVertexBindingDescriptions;
155 		DE_LENGTH_OF_ARRAY(vertexInputAttributeDescriptions),		// uint32_t                                    vertexAttributeDescriptionCount;
156 		vertexInputAttributeDescriptions,							// const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions;
157 	};
158 
159 	const VkRect2D			scissor		=
160 	{
161 		makeOffset2D(scissorArea.x(), scissorArea.y()),
162 		makeExtent2D(scissorArea.z(), scissorArea.w())
163 	};
164 
165 	const std::vector<VkViewport>	viewports	(1, makeViewport(renderSize));
166 	const std::vector<VkRect2D>		scissors	(1, scissor);
167 
168 	return vk::makeGraphicsPipeline(vk,						// const DeviceInterface&                        vk
169 									device,					// const VkDevice                                device
170 									pipelineLayout,			// const VkPipelineLayout                        pipelineLayout
171 									vertexModule,			// const VkShaderModule                          vertexShaderModule
172 									DE_NULL,				// const VkShaderModule                          tessellationControlModule
173 									DE_NULL,				// const VkShaderModule                          tessellationEvalModule
174 									DE_NULL,				// const VkShaderModule                          geometryShaderModule
175 									fragmentModule,			// const VkShaderModule                          fragmentShaderModule
176 									renderPass,				// const VkRenderPass                            renderPass
177 									viewports,				// const std::vector<VkViewport>&                viewports
178 									scissors,				// const std::vector<VkRect2D>&                  scissors
179 									topology,				// const VkPrimitiveTopology                     topology
180 									0u,						// const deUint32                                subpass
181 									0u,						// const deUint32                                patchControlPoints
182 									&vertexInputStateInfo);	// const VkPipelineVertexInputStateCreateInfo*   vertexInputStateCreateInfo
183 }
184 
makeVertex(const float x,const float y,const Vec4 & color)185 inline VertexData makeVertex (const float x, const float y, const Vec4& color)
186 {
187 	const VertexData data = { Vec4(x, y, 0.0f, 1.0f), color };
188 	return data;
189 }
190 
genVertices(const TestPrimitive primitive,const Vec4 & renderArea,const Vec4 & primitiveColor)191 std::vector<VertexData> genVertices (const TestPrimitive primitive, const Vec4& renderArea, const Vec4& primitiveColor)
192 {
193 	std::vector<VertexData> vertices;
194 	de::Random				rng			(1234);
195 
196 	const float	x0		= 2.0f * renderArea.x() - 1.0f;
197 	const float y0		= 2.0f * renderArea.y() - 1.0f;
198 	const float	rx		= 2.0f * renderArea.z();
199 	const float	ry		= 2.0f * renderArea.w();
200 	const float	size	= 0.2f;
201 
202 	switch (primitive)
203 	{
204 		case TEST_PRIMITIVE_POINTS:
205 			for (int i = 0; i < 50; ++i)
206 			{
207 				const float x = x0 + rng.getFloat(0.0f, rx);
208 				const float y = y0 + rng.getFloat(0.0f, ry);
209 				vertices.push_back(makeVertex(x, y, primitiveColor));
210 			}
211 			break;
212 
213 		case TEST_PRIMITIVE_LINES:
214 			for (int i = 0; i < 30; ++i)
215 			{
216 				const float x = x0 + rng.getFloat(0.0f, rx - size);
217 				const float y = y0 + rng.getFloat(0.0f, ry - size);
218 				vertices.push_back(makeVertex(x,        y,        primitiveColor));
219 				vertices.push_back(makeVertex(x + size, y + size, primitiveColor));
220 			}
221 			break;
222 
223 		case TEST_PRIMITIVE_TRIANGLES:
224 			for (int i = 0; i < 20; ++i)
225 			{
226 				const float x = x0 + rng.getFloat(0.0f, rx - size);
227 				const float y = y0 + rng.getFloat(0.0f, ry - size);
228 				vertices.push_back(makeVertex(x,             y,        primitiveColor));
229 				vertices.push_back(makeVertex(x + size/2.0f, y + size, primitiveColor));
230 				vertices.push_back(makeVertex(x + size,      y,        primitiveColor));
231 			}
232 			break;
233 
234 		case TEST_PRIMITIVE_BIG_LINE:
235 			vertices.push_back(makeVertex(x0,      y0,      primitiveColor));
236 			vertices.push_back(makeVertex(x0 + rx, y0 + ry, primitiveColor));
237 			break;
238 
239 		case TEST_PRIMITIVE_BIG_TRIANGLE:
240 			vertices.push_back(makeVertex(x0,           y0,      primitiveColor));
241 			vertices.push_back(makeVertex(x0 + rx/2.0f, y0 + ry, primitiveColor));
242 			vertices.push_back(makeVertex(x0 + rx,      y0,      primitiveColor));
243 			break;
244 	}
245 
246 	return vertices;
247 }
248 
getTopology(const TestPrimitive primitive)249 VkPrimitiveTopology	getTopology (const TestPrimitive primitive)
250 {
251 	switch (primitive)
252 	{
253 		case TEST_PRIMITIVE_POINTS:			return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
254 
255 		case TEST_PRIMITIVE_LINES:
256 		case TEST_PRIMITIVE_BIG_LINE:		return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
257 
258 		case TEST_PRIMITIVE_TRIANGLES:
259 		case TEST_PRIMITIVE_BIG_TRIANGLE:	return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
260 
261 		default:
262 			DE_ASSERT(0);
263 			return VK_PRIMITIVE_TOPOLOGY_LAST;
264 	}
265 }
266 
267 //! Transform from normalized coords to framebuffer space.
getAreaRect(const Vec4 & area,const int width,const int height)268 inline IVec4 getAreaRect (const Vec4& area, const int width, const int height)
269 {
270 	return IVec4(static_cast<deInt32>(static_cast<float>(width)  * area.x()),
271 				 static_cast<deInt32>(static_cast<float>(height) * area.y()),
272 				 static_cast<deInt32>(static_cast<float>(width)  * area.z()),
273 				 static_cast<deInt32>(static_cast<float>(height) * area.w()));
274 }
275 
applyScissor(tcu::PixelBufferAccess imageAccess,const Vec4 & floatScissorArea,const Vec4 & clearColor)276 void applyScissor (tcu::PixelBufferAccess imageAccess, const Vec4& floatScissorArea, const Vec4& clearColor)
277 {
278 	const IVec4	scissorRect	(getAreaRect(floatScissorArea, imageAccess.getWidth(), imageAccess.getHeight()));
279 	const int	sx0			= scissorRect.x();
280 	const int	sx1			= scissorRect.x() + scissorRect.z();
281 	const int	sy0			= scissorRect.y();
282 	const int	sy1			= scissorRect.y() + scissorRect.w();
283 
284 	for (int y = 0; y < imageAccess.getHeight(); ++y)
285 	for (int x = 0; x < imageAccess.getWidth(); ++x)
286 	{
287 		// Fragments outside fail the scissor test.
288 		if (x < sx0 || x >= sx1 || y < sy0 || y >= sy1)
289 			imageAccess.setPixel(clearColor, x, y);
290 	}
291 }
292 
initPrograms(SourceCollections & programCollection,const CaseDef caseDef)293 void initPrograms (SourceCollections& programCollection, const CaseDef caseDef)
294 {
295 	DE_UNREF(caseDef);
296 
297 	// Vertex shader
298 	{
299 		const bool usePointSize = (caseDef.primitive == TEST_PRIMITIVE_POINTS);
300 
301 		std::ostringstream src;
302 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
303 			<< "\n"
304 			<< "layout(location = 0) in  vec4 in_position;\n"
305 			<< "layout(location = 1) in  vec4 in_color;\n"
306 			<< "layout(location = 0) out vec4 o_color;\n"
307 			<< "\n"
308 			<< "out gl_PerVertex {\n"
309 			<< "    vec4  gl_Position;\n"
310 			<< (usePointSize ? "    float gl_PointSize;\n" : "")
311 			<< "};\n"
312 			<< "\n"
313 			<< "void main(void)\n"
314 			<< "{\n"
315 			<< "    gl_Position  = in_position;\n"
316 			<< (usePointSize ? "    gl_PointSize = 1.0;\n" : "")
317 			<< "    o_color      = in_color;\n"
318 			<< "}\n";
319 
320 		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
321 	}
322 
323 	// Fragment shader
324 	{
325 		std::ostringstream src;
326 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
327 			<< "\n"
328 			<< "layout(location = 0) in  vec4 in_color;\n"
329 			<< "layout(location = 0) out vec4 o_color;\n"
330 			<< "\n"
331 			<< "void main(void)\n"
332 			<< "{\n"
333 			<< "    o_color = in_color;\n"
334 			<< "}\n";
335 
336 		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
337 	}
338 }
339 
340 class ScissorRenderer
341 {
342 public:
ScissorRenderer(Context & context,const CaseDef caseDef,const IVec2 & renderSize,const VkFormat colorFormat,const Vec4 & primitiveColor,const Vec4 & clearColor)343 	ScissorRenderer (Context& context, const CaseDef caseDef, const IVec2& renderSize, const VkFormat colorFormat, const Vec4& primitiveColor, const Vec4& clearColor)
344 		: m_renderSize				(renderSize)
345 		, m_colorFormat				(colorFormat)
346 		, m_colorSubresourceRange	(makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u))
347 		, m_primitiveColor			(primitiveColor)
348 		, m_clearColor				(clearColor)
349 		, m_vertices				(genVertices(caseDef.primitive, caseDef.renderArea, m_primitiveColor))
350 		, m_vertexBufferSize		(sizeInBytes(m_vertices))
351 		, m_topology				(getTopology(caseDef.primitive))
352 	{
353 		const DeviceInterface&		vk					= context.getDeviceInterface();
354 		const VkDevice				device				= context.getDevice();
355 		const deUint32				queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
356 		Allocator&					allocator			= context.getDefaultAllocator();
357 
358 		m_colorImage			= makeImage(vk, device, makeImageCreateInfo(m_colorFormat, m_renderSize, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
359 		m_colorImageAlloc		= bindImage(vk, device, allocator, *m_colorImage, MemoryRequirement::Any);
360 		m_colorAttachment		= makeImageView(vk, device, *m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, m_colorSubresourceRange);
361 
362 		m_vertexBuffer			= makeBuffer(vk, device, m_vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
363 		m_vertexBufferAlloc		= bindBuffer(vk, device, allocator, *m_vertexBuffer, MemoryRequirement::HostVisible);
364 
365 		{
366 			deMemcpy(m_vertexBufferAlloc->getHostPtr(), &m_vertices[0], static_cast<std::size_t>(m_vertexBufferSize));
367 			flushAlloc(vk, device, *m_vertexBufferAlloc);
368 		}
369 
370 		m_vertexModule				= createShaderModule	(vk, device, context.getBinaryCollection().get("vert"), 0u);
371 		m_fragmentModule			= createShaderModule	(vk, device, context.getBinaryCollection().get("frag"), 0u);
372 		m_renderPass				= makeRenderPass		(vk, device, m_colorFormat);
373 		m_framebuffer				= makeFramebuffer		(vk, device, *m_renderPass, m_colorAttachment.get(),
374 															 static_cast<deUint32>(m_renderSize.x()),  static_cast<deUint32>(m_renderSize.y()));
375 		m_pipelineLayout			= makePipelineLayout	(vk, device);
376 		m_cmdPool					= createCommandPool		(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
377 		m_cmdBuffer					= allocateCommandBuffer	(vk, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
378 
379 	}
380 
draw(Context & context,const Vec4 & scissorAreaFloat,const VkBuffer colorBuffer) const381 	void draw (Context& context, const Vec4& scissorAreaFloat, const VkBuffer colorBuffer) const
382 	{
383 		const DeviceInterface&		vk			= context.getDeviceInterface();
384 		const VkDevice				device		= context.getDevice();
385 		const VkQueue				queue		= context.getUniversalQueue();
386 
387 		// New pipeline, because we're modifying scissor (we don't use dynamic state).
388 		const Unique<VkPipeline>	pipeline	(makeGraphicsPipeline(vk, device, *m_pipelineLayout, *m_renderPass, *m_vertexModule, *m_fragmentModule,
389 												 m_renderSize, getAreaRect(scissorAreaFloat, m_renderSize.x(), m_renderSize.y()), m_topology));
390 
391 		beginCommandBuffer(vk, *m_cmdBuffer);
392 
393 		beginRenderPass(vk, *m_cmdBuffer, *m_renderPass, *m_framebuffer, makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), m_clearColor);
394 
395 		vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
396 		{
397 			const VkDeviceSize vertexBufferOffset = 0ull;
398 			vk.cmdBindVertexBuffers(*m_cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &vertexBufferOffset);
399 		}
400 
401 		vk.cmdDraw(*m_cmdBuffer, static_cast<deUint32>(m_vertices.size()), 1u, 0u, 0u);
402 		endRenderPass(vk, *m_cmdBuffer);
403 
404 		copyImageToBuffer(vk, *m_cmdBuffer, *m_colorImage, colorBuffer, m_renderSize);
405 
406 		endCommandBuffer(vk, *m_cmdBuffer);
407 		submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
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