1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2015 The Khronos Group Inc.
6 * Copyright (c) 2015 Intel Corporation
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 Draw Indexed Tests
23 *//*--------------------------------------------------------------------*/
24
25#include "vktDrawIndexedTest.hpp"
26
27#include "vktTestCaseUtil.hpp"
28#include "vktDrawTestCaseUtil.hpp"
29
30#include "vktDrawBaseClass.hpp"
31
32#include "tcuTestLog.hpp"
33#include "tcuResource.hpp"
34#include "tcuImageCompare.hpp"
35#include "tcuTextureUtil.hpp"
36#include "tcuRGBA.hpp"
37
38#include "vkDefs.hpp"
39
40enum
41{
42	VERTEX_OFFSET = 13
43};
44
45namespace vkt
46{
47namespace Draw
48{
49namespace
50{
51class DrawIndexed : public DrawTestsBaseClass
52{
53public:
54	typedef		TestSpecBase	TestSpec;
55
56								DrawIndexed				(Context &context, TestSpec testSpec);
57	virtual		tcu::TestStatus iterate					(void);
58protected:
59	std::vector<deUint32>		m_indexes;
60	de::SharedPtr<Buffer>		m_indexBuffer;
61};
62
63class DrawInstancedIndexed : public DrawIndexed
64{
65public:
66								DrawInstancedIndexed	(Context &context, TestSpec testSpec);
67	virtual		tcu::TestStatus	iterate					(void);
68};
69
70DrawIndexed::DrawIndexed (Context &context, TestSpec testSpec)
71	: DrawTestsBaseClass(context, testSpec.shaders[glu::SHADERTYPE_VERTEX], testSpec.shaders[glu::SHADERTYPE_FRAGMENT], testSpec.topology)
72{
73	switch (m_topology)
74	{
75		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
76			m_indexes.push_back(0);
77			m_indexes.push_back(0);
78			m_indexes.push_back(2);
79			m_indexes.push_back(0);
80			m_indexes.push_back(6);
81			m_indexes.push_back(6);
82			m_indexes.push_back(0);
83			m_indexes.push_back(7);
84			break;
85		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
86			m_indexes.push_back(0);
87			m_indexes.push_back(0);
88			m_indexes.push_back(2);
89			m_indexes.push_back(0);
90			m_indexes.push_back(6);
91			m_indexes.push_back(5);
92			m_indexes.push_back(0);
93			m_indexes.push_back(7);
94			break;
95
96		case vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
97		case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
98		case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
99		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
100		case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
101		case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
102		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
103		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
104		case vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
105		case vk::VK_PRIMITIVE_TOPOLOGY_LAST:
106			DE_FATAL("Topology not implemented");
107			break;
108		default:
109			DE_FATAL("Unknown topology");
110			break;
111	}
112
113	for (int unusedIdx = 0; unusedIdx < VERTEX_OFFSET; unusedIdx++)
114	{
115		m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
116	}
117
118	int vertexIndex = VERTEX_OFFSET;
119
120	m_data.push_back(VertexElementData(tcu::Vec4(	-0.3f,	 0.3f,	1.0f,	1.0f), tcu::RGBA::blue().toVec(), vertexIndex++));
121	m_data.push_back(VertexElementData(tcu::Vec4(	-1.0f,	 1.0f,	1.0f,	1.0f), tcu::RGBA::blue().toVec(), vertexIndex++));
122	m_data.push_back(VertexElementData(tcu::Vec4(	-0.3f,	-0.3f,	1.0f,	1.0f), tcu::RGBA::blue().toVec(), vertexIndex++));
123	m_data.push_back(VertexElementData(tcu::Vec4(	 1.0f,	-1.0f,	1.0f,	1.0f), tcu::RGBA::blue().toVec(), vertexIndex++));
124	m_data.push_back(VertexElementData(tcu::Vec4(	-0.3f,	-0.3f,	1.0f,	1.0f), tcu::RGBA::blue().toVec(), vertexIndex++));
125	m_data.push_back(VertexElementData(tcu::Vec4(	 0.3f,	 0.3f,	1.0f,	1.0f), tcu::RGBA::blue().toVec(), vertexIndex++));
126	m_data.push_back(VertexElementData(tcu::Vec4(	 0.3f,	-0.3f,	1.0f,	1.0f), tcu::RGBA::blue().toVec(), vertexIndex++));
127	m_data.push_back(VertexElementData(tcu::Vec4(	 0.3f,	 0.3f,	1.0f,	1.0f), tcu::RGBA::blue().toVec(), vertexIndex++));
128
129	m_data.push_back(VertexElementData(tcu::Vec4(	-1.0f,	 1.0f,	1.0f,	1.0f), tcu::RGBA::blue().toVec(), -1));
130
131	initialize();
132};
133
134tcu::TestStatus DrawIndexed::iterate (void)
135{
136	tcu::TestLog &log			= m_context.getTestContext().getLog();
137	const vk::VkQueue queue		= m_context.getUniversalQueue();
138
139	beginRenderPass();
140
141	const vk::VkDeviceSize dataSize = m_indexes.size() * sizeof(deUint32);
142	m_indexBuffer = Buffer::createAndAlloc(	m_vk, m_context.getDevice(),
143											BufferCreateInfo(dataSize,
144															 vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT),
145											m_context.getDefaultAllocator(),
146											vk::MemoryRequirement::HostVisible);
147
148	deUint8* ptr = reinterpret_cast<deUint8*>(m_indexBuffer->getBoundMemory().getHostPtr());
149
150	deMemcpy(ptr, &m_indexes[0], static_cast<size_t>(dataSize));
151
152	vk::flushMappedMemoryRange(m_vk, m_context.getDevice(),
153							   m_indexBuffer->getBoundMemory().getMemory(),
154							   m_indexBuffer->getBoundMemory().getOffset(),
155							   dataSize);
156
157	const vk::VkDeviceSize vertexBufferOffset = 0;
158	const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
159	const vk::VkBuffer indexBuffer = m_indexBuffer->object();
160
161	m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
162	m_vk.cmdBindIndexBuffer(*m_cmdBuffer, indexBuffer, 0, vk::VK_INDEX_TYPE_UINT32);
163
164	m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
165
166	m_vk.cmdDrawIndexed(*m_cmdBuffer, 6, 1, 2, VERTEX_OFFSET, 0);
167
168	m_vk.cmdEndRenderPass(*m_cmdBuffer);
169	m_vk.endCommandBuffer(*m_cmdBuffer);
170
171	vk::VkSubmitInfo submitInfo =
172	{
173		vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,	// VkStructureType			sType;
174		DE_NULL,							// const void*				pNext;
175		0,										// deUint32					waitSemaphoreCount;
176		DE_NULL,								// const VkSemaphore*		pWaitSemaphores;
177		(const vk::VkPipelineStageFlags*)DE_NULL,
178		1,										// deUint32					commandBufferCount;
179		&m_cmdBuffer.get(),					// const VkCommandBuffer*	pCommandBuffers;
180		0,										// deUint32					signalSemaphoreCount;
181		DE_NULL								// const VkSemaphore*		pSignalSemaphores;
182	};
183
184	VK_CHECK(m_vk.queueSubmit(queue, 1, &submitInfo, DE_NULL));
185
186	VK_CHECK(m_vk.queueWaitIdle(queue));
187
188	// Validation
189	tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5 + WIDTH), (int)(0.5 + HEIGHT));
190								  referenceFrame.allocLevel(0);
191
192	const deInt32 frameWidth	= referenceFrame.getWidth();
193	const deInt32 frameHeight	= referenceFrame.getHeight();
194
195	tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
196
197	ReferenceImageCoordinates refCoords;
198
199	for (int y = 0; y < frameHeight; y++)
200	{
201		const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f;
202
203		for (int x = 0; x < frameWidth; x++)
204		{
205			const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f;
206
207			if ((yCoord >= refCoords.bottom &&
208				 yCoord <= refCoords.top	&&
209				 xCoord >= refCoords.left	&&
210				 xCoord <= refCoords.right))
211				referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), x, y);
212		}
213	}
214
215	const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
216	const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
217		vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
218
219	qpTestResult res = QP_TEST_RESULT_PASS;
220
221	if (!tcu::fuzzyCompare(log, "Result", "Image comparison result",
222		referenceFrame.getLevel(0), renderedFrame, 0.05f,
223		tcu::COMPARE_LOG_RESULT)) {
224		res = QP_TEST_RESULT_FAIL;
225	}
226
227	return tcu::TestStatus(res, qpGetTestResultName(res));
228};
229
230DrawInstancedIndexed::DrawInstancedIndexed (Context &context, TestSpec testSpec)
231	: DrawIndexed	(context, testSpec)
232{
233}
234
235tcu::TestStatus DrawInstancedIndexed::iterate (void)
236{
237	tcu::TestLog &log		= m_context.getTestContext().getLog();
238	const vk::VkQueue queue = m_context.getUniversalQueue();
239
240	beginRenderPass();
241
242	const vk::VkDeviceSize dataSize = m_indexes.size() * sizeof(deUint32);
243	m_indexBuffer = Buffer::createAndAlloc(	m_vk, m_context.getDevice(),
244											BufferCreateInfo(dataSize,
245															 vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT),
246											m_context.getDefaultAllocator(),
247											vk::MemoryRequirement::HostVisible);
248
249	deUint8* ptr = reinterpret_cast<deUint8*>(m_indexBuffer->getBoundMemory().getHostPtr());
250
251	deMemcpy(ptr, &m_indexes[0], static_cast<size_t>(dataSize));
252	vk::flushMappedMemoryRange(m_vk, m_context.getDevice(),
253							   m_indexBuffer->getBoundMemory().getMemory(),
254							   m_indexBuffer->getBoundMemory().getOffset(),
255							   dataSize);
256
257	const vk::VkDeviceSize vertexBufferOffset = 0;
258	const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
259	const vk::VkBuffer indexBuffer = m_indexBuffer->object();
260
261	m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
262	m_vk.cmdBindIndexBuffer(*m_cmdBuffer, indexBuffer, 0, vk::VK_INDEX_TYPE_UINT32);
263	m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
264
265	switch (m_topology)
266	{
267		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
268			m_vk.cmdDrawIndexed(*m_cmdBuffer, 6, 4, 2, VERTEX_OFFSET, 2);
269			break;
270		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
271			m_vk.cmdDrawIndexed(*m_cmdBuffer, 4, 4, 2, VERTEX_OFFSET, 2);
272			break;
273		case vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
274		case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
275		case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
276		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
277		case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
278		case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
279		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
280		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
281		case vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
282		case vk::VK_PRIMITIVE_TOPOLOGY_LAST:
283			DE_FATAL("Topology not implemented");
284			break;
285		default:
286			DE_FATAL("Unknown topology");
287			break;
288	}
289
290	m_vk.cmdEndRenderPass(*m_cmdBuffer);
291	m_vk.endCommandBuffer(*m_cmdBuffer);
292
293	vk::VkSubmitInfo submitInfo =
294	{
295		vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,	// VkStructureType			sType;
296		DE_NULL,							// const void*				pNext;
297		0,										// deUint32					waitSemaphoreCount;
298		DE_NULL,								// const VkSemaphore*		pWaitSemaphores;
299		(const vk::VkPipelineStageFlags*)DE_NULL,
300		1,										// deUint32					commandBufferCount;
301		&m_cmdBuffer.get(),					// const VkCommandBuffer*	pCommandBuffers;
302		0,										// deUint32					signalSemaphoreCount;
303		DE_NULL								// const VkSemaphore*		pSignalSemaphores;
304	};
305	VK_CHECK(m_vk.queueSubmit(queue, 1, &submitInfo, DE_NULL));
306
307	VK_CHECK(m_vk.queueWaitIdle(queue));
308
309	// Validation
310	VK_CHECK(m_vk.queueWaitIdle(queue));
311
312	tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5 + WIDTH), (int)(0.5 + HEIGHT));
313	referenceFrame.allocLevel(0);
314
315	const deInt32 frameWidth = referenceFrame.getWidth();
316	const deInt32 frameHeight = referenceFrame.getHeight();
317
318	tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
319
320	ReferenceImageInstancedCoordinates refInstancedCoords;
321
322	for (int y = 0; y < frameHeight; y++)
323	{
324		const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f;
325
326		for (int x = 0; x < frameWidth; x++)
327		{
328			const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f;
329
330			if ((yCoord >= refInstancedCoords.bottom	&&
331				 yCoord <= refInstancedCoords.top		&&
332				 xCoord >= refInstancedCoords.left		&&
333				 xCoord <= refInstancedCoords.right))
334				referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), x, y);
335		}
336	}
337
338	const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
339	const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
340		vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
341
342	qpTestResult res = QP_TEST_RESULT_PASS;
343
344	if (!tcu::fuzzyCompare(log, "Result", "Image comparison result",
345		referenceFrame.getLevel(0), renderedFrame, 0.05f,
346		tcu::COMPARE_LOG_RESULT)) {
347		res = QP_TEST_RESULT_FAIL;
348	}
349
350	return tcu::TestStatus(res, qpGetTestResultName(res));
351
352}
353
354}	// anonymous
355
356DrawIndexedTests::DrawIndexedTests (tcu::TestContext &testCtx)
357	: TestCaseGroup	(testCtx, "indexed_draw", "drawing indexed geometry")
358{
359	/* Left blank on purpose */
360}
361
362DrawIndexedTests::~DrawIndexedTests (void) {}
363
364void DrawIndexedTests::init (void)
365{
366	{
367		DrawIndexed::TestSpec testSpec;
368		testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetch.vert";
369		testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
370
371		testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
372		addChild(new InstanceFactory<DrawIndexed>(m_testCtx, "draw_indexed_triangle_list", "Draws indexed triangle list", testSpec));
373		testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
374		addChild(new InstanceFactory<DrawIndexed>(m_testCtx, "draw_indexed_triangle_strip", "Draws indexed triangle strip", testSpec));
375	}
376	{
377		DrawInstancedIndexed::TestSpec testSpec;
378		testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetchInstancedFirstInstance.vert";
379		testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
380
381		testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
382		addChild(new InstanceFactory<DrawInstancedIndexed>(m_testCtx, "draw_instanced_indexed_triangle_list", "Draws indexed triangle list", testSpec));
383		testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
384		addChild(new InstanceFactory<DrawInstancedIndexed>(m_testCtx, "draw_instanced_indexed_triangle_strip", "Draws indexed triangle strip", testSpec));
385	}
386}
387
388}	// DrawTests
389}	// vkt
390