1/*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2016 Google Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Texture filtering tests with explicit LOD instructions
22 *//*--------------------------------------------------------------------*/
23
24#include "vktTextureFilteringExplicitLodTests.hpp"
25
26#include "vkDefs.hpp"
27
28#include "vktSampleVerifier.hpp"
29#include "vktShaderExecutor.hpp"
30#include "vktTestCaseUtil.hpp"
31
32#include "vkDeviceUtil.hpp"
33#include "vkImageUtil.hpp"
34#include "vkPlatform.hpp"
35#include "vkRef.hpp"
36#include "vkRefUtil.hpp"
37#include "vkStrUtil.hpp"
38#include "vkTypeUtil.hpp"
39#include "vkQueryUtil.hpp"
40#include "vkMemUtil.hpp"
41
42#include "tcuTexLookupVerifier.hpp"
43#include "tcuTestLog.hpp"
44#include "tcuTexture.hpp"
45#include "tcuTextureUtil.hpp"
46#include "tcuVector.hpp"
47
48#include "deClock.h"
49#include "deMath.h"
50#include "deStringUtil.hpp"
51#include "deUniquePtr.hpp"
52
53#include <sstream>
54#include <string>
55#include <vector>
56
57namespace vkt
58{
59namespace texture
60{
61
62using namespace tcu;
63using namespace vk;
64using std::string;
65
66namespace
67{
68
69tcu::FloatFormat getConversionPrecision (VkFormat format)
70{
71	const tcu::FloatFormat	reallyLow	(0, 0, 8, false, tcu::YES);
72	const tcu::FloatFormat	fp16		(-14, 15, 10, false);
73	const tcu::FloatFormat	fp32		(-126, 127, 23, true);
74
75	switch (format)
76	{
77	    case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
78		case VK_FORMAT_R5G6B5_UNORM_PACK16:
79		case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
80			return reallyLow;
81
82		case VK_FORMAT_R8_UNORM:
83		case VK_FORMAT_R8_SNORM:
84		case VK_FORMAT_R8G8_UNORM:
85		case VK_FORMAT_R8G8_SNORM:
86		case VK_FORMAT_R8G8B8A8_UNORM:
87		case VK_FORMAT_R8G8B8A8_SNORM:
88		case VK_FORMAT_B8G8R8A8_UNORM:
89		case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
90		case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
91		case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
92			return fp16;
93
94		case VK_FORMAT_R16_SFLOAT:
95		case VK_FORMAT_R16G16_SFLOAT:
96		case VK_FORMAT_R16G16B16A16_SFLOAT:
97			return fp16;
98
99		case VK_FORMAT_R32_SFLOAT:
100		case VK_FORMAT_R32G32_SFLOAT:
101		case VK_FORMAT_R32G32B32A32_SFLOAT:
102			return fp32;
103
104		default:
105			DE_FATAL("Precision not defined for format");
106			return fp32;
107	}
108}
109
110tcu::FloatFormat getFilteringPrecision (VkFormat format)
111{
112	const tcu::FloatFormat	reallyLow	(0, 0, 6, false, tcu::YES);
113	const tcu::FloatFormat	low			(0, 0, 7, false, tcu::YES);
114	const tcu::FloatFormat	fp16		(-14, 15, 10, false);
115	const tcu::FloatFormat	fp32		(-126, 127, 23, true);
116
117	switch (format)
118	{
119	    case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
120		case VK_FORMAT_R5G6B5_UNORM_PACK16:
121		case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
122			return reallyLow;
123
124		case VK_FORMAT_R8_UNORM:
125		case VK_FORMAT_R8_SNORM:
126		case VK_FORMAT_R8G8_UNORM:
127		case VK_FORMAT_R8G8_SNORM:
128		case VK_FORMAT_R8G8B8A8_UNORM:
129		case VK_FORMAT_R8G8B8A8_SNORM:
130		case VK_FORMAT_B8G8R8A8_UNORM:
131		case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
132		case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
133		case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
134			return low;
135
136		case VK_FORMAT_R16_SFLOAT:
137		case VK_FORMAT_R16G16_SFLOAT:
138		case VK_FORMAT_R16G16B16A16_SFLOAT:
139			return fp16;
140
141		case VK_FORMAT_R32_SFLOAT:
142		case VK_FORMAT_R32G32_SFLOAT:
143		case VK_FORMAT_R32G32B32A32_SFLOAT:
144			return fp32;
145
146		default:
147			DE_FATAL("Precision not defined for format");
148			return fp32;
149	}
150}
151
152using namespace shaderexecutor;
153
154string genSamplerDeclaration(const ImageViewParameters& imParams,
155							 const SamplerParameters&	samplerParams)
156{
157	string result = "sampler";
158
159	switch (imParams.dim)
160	{
161		case IMG_DIM_1D:
162			result += "1D";
163			break;
164
165		case IMG_DIM_2D:
166			result += "2D";
167			break;
168
169		case IMG_DIM_3D:
170			result += "3D";
171			break;
172
173		case IMG_DIM_CUBE:
174			result += "Cube";
175			break;
176
177		default:
178			break;
179	}
180
181	if (imParams.isArrayed)
182	{
183		result += "Array";
184	}
185
186	if (samplerParams.isCompare)
187	{
188		result += "Shadow";
189	}
190
191	return result;
192}
193
194string genLookupCode(const ImageViewParameters&		imParams,
195					 const SamplerParameters&		samplerParams,
196					 const SampleLookupSettings&	lookupSettings)
197{
198	int dim = -1;
199
200	switch (imParams.dim)
201	{
202		case IMG_DIM_1D:
203			dim = 1;
204			break;
205
206		case IMG_DIM_2D:
207			dim = 2;
208			break;
209
210		case IMG_DIM_3D:
211			dim = 3;
212			break;
213
214		case IMG_DIM_CUBE:
215			dim = 3;
216			break;
217
218		default:
219			dim = 0;
220			break;
221	}
222
223	DE_ASSERT(dim >= 1 && dim <= 3);
224
225	int numCoordComp = dim;
226
227	if (lookupSettings.isProjective)
228	{
229		++numCoordComp;
230	}
231
232	int numArgComp = numCoordComp;
233	bool hasSeparateCompare = false;
234
235	if (imParams.isArrayed)
236	{
237		DE_ASSERT(!lookupSettings.isProjective && "Can't do a projective lookup on an arrayed image!");
238
239		++numArgComp;
240	}
241
242	if (samplerParams.isCompare && numCoordComp == 4)
243	{
244		hasSeparateCompare = true;
245	}
246	else if (samplerParams.isCompare)
247	{
248		++numArgComp;
249	}
250
251	// Build coordinate input to texture*() function
252
253	string arg	= "vec";
254	arg += (char) (numArgComp + '0');
255	arg += "(vec";
256	arg += (char) (numCoordComp + '0');
257	arg += "(coord)";
258
259    int numZero = numArgComp - numCoordComp;
260
261	if (imParams.isArrayed)
262	{
263		arg += ", layer";
264		--numZero;
265	}
266
267	if (samplerParams.isCompare && !hasSeparateCompare)
268	{
269		arg += ", dRef";
270		--numZero;
271	}
272
273	for (int ndx = 0; ndx < numZero; ++ndx)
274	{
275		arg += ", 0.0";
276	}
277
278	arg += ")";
279
280	// Build call to texture*() function
281
282	string code;
283
284	code += "result = texture";
285
286	if (lookupSettings.isProjective)
287	{
288		code += "Proj";
289	}
290
291	if (lookupSettings.lookupLodMode == LOOKUP_LOD_MODE_DERIVATIVES)
292	{
293		code += "Grad";
294	}
295	else if (lookupSettings.lookupLodMode == LOOKUP_LOD_MODE_LOD)
296	{
297		code += "Lod";
298	}
299
300	code += "(testSampler, ";
301	code += arg;
302
303	if (samplerParams.isCompare && hasSeparateCompare)
304	{
305		code += ", dRef";
306	}
307
308	if (lookupSettings.lookupLodMode == LOOKUP_LOD_MODE_DERIVATIVES)
309	{
310		code += ", vec";
311		code += (char) (numCoordComp + '0');
312		code += "(dPdx), ";
313		code += "vec";
314		code += (char) (numCoordComp + '0');
315		code += "(dPdy)";
316	}
317	else if (lookupSettings.lookupLodMode == LOOKUP_LOD_MODE_LOD)
318	{
319		code += ", lod";
320	}
321
322	code += ");";
323
324	return code;
325}
326
327void initializeImage(Context& ctx, VkImage im, const ConstPixelBufferAccess* pba, ImageViewParameters imParams)
328{
329	const DeviceInterface& vkd = ctx.getDeviceInterface();
330	const VkDevice dev = ctx.getDevice();
331	const deUint32 uqfi = ctx.getUniversalQueueFamilyIndex();
332
333	const VkDeviceSize bufSize =
334		getPixelSize(mapVkFormat(imParams.format))
335		* imParams.arrayLayers
336		* imParams.size[0]
337		* imParams.size[1]
338		* imParams.size[2]
339		* 2;
340
341    const VkBufferCreateInfo bufCreateInfo =
342	{
343		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	// sType
344		DE_NULL,								// pNext
345		0,										// flags
346		bufSize,								// size
347		VK_BUFFER_USAGE_TRANSFER_SRC_BIT,		// usage
348		VK_SHARING_MODE_EXCLUSIVE,				// sharingMode
349		1,										// queueFamilyIndexCount
350		&uqfi									// pQueueFamilyIndices
351	};
352
353	Unique<VkBuffer> buf(createBuffer(vkd, dev, &bufCreateInfo));
354
355	VkMemoryRequirements bufMemReq;
356	vkd.getBufferMemoryRequirements(dev, buf.get(), &bufMemReq);
357
358	de::UniquePtr<Allocation> bufMem(ctx.getDefaultAllocator().allocate(bufMemReq, MemoryRequirement::HostVisible));
359	VK_CHECK(vkd.bindBufferMemory(dev, buf.get(), bufMem->getMemory(), bufMem->getOffset()));
360
361	const VkCommandPoolCreateInfo copyPoolCreateInfo =
362	{
363		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
364		DE_NULL,
365		VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,
366		uqfi
367	};
368
369	Unique<VkCommandPool> copyPool(createCommandPool(vkd, dev, &copyPoolCreateInfo));
370
371	const VkCommandBufferAllocateInfo copyBufferCreateInfo =
372	{
373		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
374		DE_NULL,
375		copyPool.get(),
376		VK_COMMAND_BUFFER_LEVEL_PRIMARY,
377		1
378	};
379
380	Unique<VkCommandBuffer> copyBuffer(allocateCommandBuffer(vkd, dev, &copyBufferCreateInfo));
381
382	std::vector<VkBufferImageCopy> copyRegions;
383
384	deUint8* const bufMapPtr = reinterpret_cast<deUint8*>(bufMem->getHostPtr());
385	deUint8* bufCurPtr = bufMapPtr;
386
387	for (int level = 0; level < imParams.levels; ++level)
388	{
389		const IVec3 curLevelSize = pba[level].getSize();
390
391		const std::size_t copySize =
392			getPixelSize(mapVkFormat(imParams.format))
393			* curLevelSize[0] * curLevelSize[1] * curLevelSize[2]
394			* imParams.arrayLayers;
395
396		deMemcpy(bufCurPtr, pba[level].getDataPtr(), copySize);
397
398	    flushMappedMemoryRange(vkd, dev, bufMem->getMemory(), bufMem->getOffset() + (bufCurPtr - bufMapPtr), copySize);
399
400		const VkImageSubresourceLayers curSubresource =
401		{
402			VK_IMAGE_ASPECT_COLOR_BIT,
403			(deUint32)level,
404			0,
405			(deUint32)imParams.arrayLayers
406		};
407
408		const VkBufferImageCopy curRegion =
409		{
410			(VkDeviceSize) (bufCurPtr - bufMapPtr),
411			0,
412			0,
413			curSubresource,
414			{0U, 0U, 0U},
415			{(deUint32)curLevelSize[0], (deUint32)curLevelSize[1], (deUint32)curLevelSize[2]}
416		};
417
418		copyRegions.push_back(curRegion);
419
420		bufCurPtr += copySize;
421	}
422
423	const VkCommandBufferBeginInfo beginInfo =
424	{
425		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
426		DE_NULL,
427		VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
428		DE_NULL
429	};
430
431	VK_CHECK(vkd.beginCommandBuffer(copyBuffer.get(), &beginInfo));
432
433	const VkImageSubresourceRange imMemBarSubRange =
434	{
435		VK_IMAGE_ASPECT_COLOR_BIT,
436		0,
437		(deUint32)imParams.levels,
438		0,
439		(deUint32)imParams.arrayLayers
440	};
441
442	VkImageMemoryBarrier imMemBar =
443	{
444		VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
445		DE_NULL,
446		0,
447		VK_ACCESS_TRANSFER_WRITE_BIT,
448		VK_IMAGE_LAYOUT_UNDEFINED,
449		VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
450		VK_QUEUE_FAMILY_IGNORED,
451		VK_QUEUE_FAMILY_IGNORED,
452		im,
453		imMemBarSubRange
454	};
455
456	VkBufferMemoryBarrier bufMemBar =
457	{
458		VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
459		DE_NULL,
460		VK_ACCESS_HOST_WRITE_BIT,
461		VK_ACCESS_TRANSFER_READ_BIT,
462		VK_QUEUE_FAMILY_IGNORED,
463		VK_QUEUE_FAMILY_IGNORED,
464		buf.get(),
465		0,
466		bufSize
467	};
468
469	vkd.cmdPipelineBarrier(copyBuffer.get(),
470						   VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
471						   VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
472						   0,
473						   0,
474						   DE_NULL,
475						   1,
476						   &bufMemBar,
477						   1,
478						   &imMemBar);
479
480	vkd.cmdCopyBufferToImage(copyBuffer.get(),
481							 buf.get(),
482							 im,
483							 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
484							 (deUint32)copyRegions.size(),
485							 &copyRegions[0]);
486
487	imMemBar.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
488	imMemBar.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
489	imMemBar.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
490	imMemBar.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
491
492	vkd.cmdPipelineBarrier(copyBuffer.get(),
493						   VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
494						   VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
495						   0,
496						   0,
497						   DE_NULL,
498						   0,
499						   DE_NULL,
500						   1,
501						   &imMemBar);
502
503	VK_CHECK(vkd.endCommandBuffer(copyBuffer.get()));
504
505	const VkSubmitInfo copySubmitInfo =
506	{
507		VK_STRUCTURE_TYPE_SUBMIT_INFO,
508		DE_NULL,
509		0,
510		DE_NULL,
511		DE_NULL,
512		1,
513		&(copyBuffer.get()),
514		0,
515		DE_NULL
516	};
517
518	VK_CHECK(vkd.queueSubmit(ctx.getUniversalQueue(), 1, &copySubmitInfo, 0));
519	VK_CHECK(vkd.queueWaitIdle(ctx.getUniversalQueue()));
520}
521
522struct TestCaseData
523{
524	std::vector<ConstPixelBufferAccess>	pba;
525	ImageViewParameters					imParams;
526	SamplerParameters					samplerParams;
527	SampleLookupSettings				sampleLookupSettings;
528	glu::ShaderType						shaderType;
529};
530
531VkSamplerCreateInfo mapSamplerCreateInfo (const SamplerParameters& samplerParams)
532{
533	VkSamplerCreateInfo samplerCreateInfo =
534	{
535		VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,				// sType
536		DE_NULL,											// pNext
537		0U,													// flags
538	    samplerParams.magFilter,							// magFilter
539		samplerParams.minFilter,							// minFilter
540		samplerParams.mipmapFilter,							// mipmapMode
541	    samplerParams.wrappingModeU,						// addressModeU
542	    samplerParams.wrappingModeV,						// addressModeV
543	    samplerParams.wrappingModeW,						// addressMoveW
544		samplerParams.lodBias,								// mipLodBias
545		VK_FALSE,											// anisotropyEnable
546		1.0f,												// maxAnisotropy
547		VK_FALSE,											// compareEnable
548		VK_COMPARE_OP_NEVER,								// compareOp
549		samplerParams.minLod,								// minLod
550		samplerParams.maxLod,								// maxLod
551	    samplerParams.borderColor,							// borderColor
552		samplerParams.isUnnormalized ? VK_TRUE : VK_FALSE,	// unnormalizedCoordinates
553	};
554
555	if (samplerParams.isCompare)
556	{
557		samplerCreateInfo.compareEnable = VK_TRUE;
558
559	    DE_FATAL("Not implemented");
560	}
561
562	return samplerCreateInfo;
563}
564
565VkImageType mapImageType (ImgDim dim)
566{
567	VkImageType imType;
568
569	switch (dim)
570	{
571		case IMG_DIM_1D:
572			imType = VK_IMAGE_TYPE_1D;
573			break;
574
575		case IMG_DIM_2D:
576		case IMG_DIM_CUBE:
577			imType = VK_IMAGE_TYPE_2D;
578			break;
579
580		case IMG_DIM_3D:
581			imType = VK_IMAGE_TYPE_3D;
582			break;
583
584		default:
585			imType = VK_IMAGE_TYPE_LAST;
586			break;
587	}
588
589	return imType;
590}
591
592VkImageViewType mapImageViewType (const ImageViewParameters& imParams)
593{
594	VkImageViewType imViewType;
595
596	if (imParams.isArrayed)
597	{
598		switch (imParams.dim)
599		{
600			case IMG_DIM_1D:
601				imViewType = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
602				break;
603
604			case IMG_DIM_2D:
605				imViewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
606				break;
607
608			case IMG_DIM_CUBE:
609				imViewType = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
610				break;
611
612			default:
613				imViewType = VK_IMAGE_VIEW_TYPE_LAST;
614				break;
615		}
616	}
617	else
618	{
619		switch (imParams.dim)
620		{
621			case IMG_DIM_1D:
622				imViewType = VK_IMAGE_VIEW_TYPE_1D;
623				break;
624
625			case IMG_DIM_2D:
626				imViewType = VK_IMAGE_VIEW_TYPE_2D;
627				break;
628
629			case IMG_DIM_3D:
630				imViewType = VK_IMAGE_VIEW_TYPE_3D;
631				break;
632
633			case IMG_DIM_CUBE:
634				imViewType = VK_IMAGE_VIEW_TYPE_CUBE;
635				break;
636
637			default:
638				imViewType = VK_IMAGE_VIEW_TYPE_LAST;
639				break;
640		}
641	}
642
643	return imViewType;
644}
645
646class DataGenerator
647{
648public:
649	virtual										~DataGenerator	(void) {}
650
651	virtual bool								generate		(void) = 0;
652
653	virtual std::vector<ConstPixelBufferAccess> getPba			(void) const = 0;
654	virtual std::vector<SampleArguments>		getSampleArgs	(void) const = 0;
655
656protected:
657												DataGenerator	(void) {}
658};
659
660class TextureFilteringTestInstance : public TestInstance
661{
662public:
663										TextureFilteringTestInstance	(Context&					ctx,
664																		 const TestCaseData&		testCaseData,
665																		 const ShaderSpec&			shaderSpec,
666																		 de::MovePtr<DataGenerator>	gen);
667
668	virtual TestStatus					iterate							(void) { return runTest(); }
669
670protected:
671	TestStatus							runTest							(void);
672	bool								isSupported						(void);
673	void								createResources					(void);
674	void								execute							(void);
675	bool								verify							(void);
676
677	tcu::Sampler						mapTcuSampler					(void) const;
678
679	const glu::ShaderType				m_shaderType;
680	const ShaderSpec					m_shaderSpec;
681	const ImageViewParameters			m_imParams;
682	const SamplerParameters				m_samplerParams;
683	const SampleLookupSettings			m_sampleLookupSettings;
684
685	std::vector<SampleArguments>		m_sampleArguments;
686	deUint32							m_numSamples;
687
688	de::MovePtr<Allocation>				m_imAllocation;
689	Move<VkImage>						m_im;
690	Move<VkImageView>					m_imView;
691	Move<VkSampler>						m_sampler;
692
693	Move<VkDescriptorSetLayout>			m_extraResourcesLayout;
694	Move<VkDescriptorPool>				m_extraResourcesPool;
695	Move<VkDescriptorSet>				m_extraResourcesSet;
696
697	de::MovePtr<ShaderExecutor>			m_executor;
698
699	std::vector<ConstPixelBufferAccess> m_levels;
700	de::MovePtr<DataGenerator>			m_gen;
701
702	std::vector<Vec4>					m_resultSamples;
703	std::vector<Vec4>					m_resultCoords;
704};
705
706TextureFilteringTestInstance::TextureFilteringTestInstance (Context&					ctx,
707															const TestCaseData&			testCaseData,
708															const ShaderSpec&			shaderSpec,
709															de::MovePtr<DataGenerator>	gen)
710	: TestInstance				(ctx)
711	, m_shaderType				(testCaseData.shaderType)
712	, m_shaderSpec				(shaderSpec)
713	, m_imParams				(testCaseData.imParams)
714	, m_samplerParams			(testCaseData.samplerParams)
715	, m_sampleLookupSettings	(testCaseData.sampleLookupSettings)
716	, m_levels					(testCaseData.pba)
717	, m_gen						(gen.release())
718{
719	for (deUint8 compNdx = 0; compNdx < 3; ++compNdx)
720		DE_ASSERT(m_imParams.size[compNdx] > 0);
721}
722
723TestStatus TextureFilteringTestInstance::runTest (void)
724{
725	if (!isSupported())
726	    TCU_THROW(NotSupportedError, "Unsupported combination of filtering and image format");
727
728	TCU_CHECK(m_gen->generate());
729	m_levels = m_gen->getPba();
730
731	m_sampleArguments = m_gen->getSampleArgs();
732	m_numSamples = (deUint32)m_sampleArguments.size();
733
734	createResources();
735	initializeImage(m_context, m_im.get(), &m_levels[0], m_imParams);
736
737	deUint64 startTime, endTime;
738
739	startTime = deGetMicroseconds();
740	execute();
741	endTime = deGetMicroseconds();
742
743	m_context.getTestContext().getLog() << TestLog::Message
744										<< "Execution time: "
745										<< endTime - startTime
746										<< "us"
747										<< TestLog::EndMessage;
748
749    startTime = deGetMicroseconds();
750	bool result = verify();
751    endTime = deGetMicroseconds();
752
753	m_context.getTestContext().getLog() << TestLog::Message
754										<< "Verification time: "
755										<< endTime - startTime
756										<< "us"
757										<< TestLog::EndMessage;
758
759	if (result)
760	{
761		return TestStatus::pass("Success");
762	}
763	else
764	{
765		// \todo [2016-06-24 collinbaker] Print report if verification fails
766		return TestStatus::fail("Verification failed");
767	}
768}
769
770bool TextureFilteringTestInstance::verify (void)
771{
772	// \todo [2016-06-24 collinbaker] Handle cubemaps
773
774	const int				coordBits			= (int)m_context.getDeviceProperties().limits.subTexelPrecisionBits;
775	const int				mipmapBits			= (int)m_context.getDeviceProperties().limits.mipmapPrecisionBits;
776	const int				maxPrintedFailures	= 5;
777	int						failCount			= 0;
778
779	const SampleVerifier	verifier			(m_imParams,
780												 m_samplerParams,
781												 m_sampleLookupSettings,
782												 coordBits,
783												 mipmapBits,
784												 getConversionPrecision(m_imParams.format),
785												 getFilteringPrecision(m_imParams.format),
786												 m_levels);
787
788
789	for (deUint32 sampleNdx = 0; sampleNdx < m_numSamples; ++sampleNdx)
790	{
791		if (!verifier.verifySample(m_sampleArguments[sampleNdx], m_resultSamples[sampleNdx]))
792		{
793			if (failCount++ < maxPrintedFailures)
794			{
795				// Re-run with report logging
796				std::string report;
797				verifier.verifySampleReport(m_sampleArguments[sampleNdx], m_resultSamples[sampleNdx], report);
798
799				m_context.getTestContext().getLog()
800					<< TestLog::Section("Failed sample", "Failed sample")
801					<< TestLog::Message
802					<< "Sample " << sampleNdx << ".\n"
803					<< "\tCoordinate: " << m_sampleArguments[sampleNdx].coord << "\n"
804					<< "\tLOD: " << m_sampleArguments[sampleNdx].lod << "\n"
805					<< "\tGPU Result: " << m_resultSamples[sampleNdx] << "\n\n"
806					<< "Failure report:\n" << report << "\n"
807					<< TestLog::EndMessage
808					<< TestLog::EndSection;
809			}
810		}
811	}
812
813	m_context.getTestContext().getLog()
814		<< TestLog::Message
815		<< "Passed " << m_numSamples - failCount << " out of " << m_numSamples << "."
816		<< TestLog::EndMessage;
817
818	return failCount == 0;
819}
820
821void TextureFilteringTestInstance::execute (void)
822{
823	std::vector<float> coords, layers, dRefs, dPdxs, dPdys, lods;
824
825	for (deUint32 ndx = 0; ndx < m_numSamples; ++ndx)
826	{
827		const SampleArguments& sampleArgs = m_sampleArguments[ndx];
828
829		for (deUint8 compNdx = 0; compNdx < 4; ++compNdx)
830		{
831			coords.push_back(sampleArgs.coord[compNdx]);
832			dPdxs .push_back(sampleArgs.dPdx[compNdx]);
833			dPdys .push_back(sampleArgs.dPdy[compNdx]);
834		}
835
836		layers.push_back(sampleArgs.layer);
837		dRefs .push_back(sampleArgs.dRef);
838		lods  .push_back(sampleArgs.lod);
839	}
840
841	const void* inputs[6] =
842	{
843		reinterpret_cast<const void*>(&coords[0]),
844		reinterpret_cast<const void*>(&layers[0]),
845		reinterpret_cast<const void*>(&dRefs[0]),
846		reinterpret_cast<const void*>(&dPdxs[0]),
847		reinterpret_cast<const void*>(&dPdys[0]),
848		reinterpret_cast<const void*>(&lods[0])
849	};
850
851	// Staging buffers; data will be copied into vectors of Vec4
852	// \todo [2016-06-24 collinbaker] Figure out if I actually need to
853	// use staging buffers
854	std::vector<float> resultSamplesTemp(m_numSamples * 4);
855	std::vector<float> resultCoordsTemp (m_numSamples * 4);
856
857	void* outputs[2] =
858	{
859		reinterpret_cast<void*>(&resultSamplesTemp[0]),
860		reinterpret_cast<void*>(&resultCoordsTemp[0])
861	};
862
863	m_executor->execute(m_numSamples, inputs, outputs, *m_extraResourcesSet);
864
865	m_resultSamples.resize(m_numSamples);
866	m_resultCoords .resize(m_numSamples);
867
868	for (deUint32 ndx = 0; ndx < m_numSamples; ++ndx)
869	{
870		m_resultSamples[ndx] = Vec4(resultSamplesTemp[4 * ndx + 0],
871									resultSamplesTemp[4 * ndx + 1],
872									resultSamplesTemp[4 * ndx + 2],
873									resultSamplesTemp[4 * ndx + 3]);
874
875		m_resultCoords [ndx] = Vec4(resultCoordsTemp [4 * ndx + 0],
876									resultCoordsTemp [4 * ndx + 1],
877									resultCoordsTemp [4 * ndx + 2],
878									resultCoordsTemp [4 * ndx + 3]);
879	}
880}
881
882void TextureFilteringTestInstance::createResources (void)
883{
884	// Create VkImage
885
886	const DeviceInterface&		vkd				= m_context.getDeviceInterface();
887	const VkDevice				device			= m_context.getDevice();
888
889	const deUint32				queueFamily		= m_context.getUniversalQueueFamilyIndex();
890	const VkImageCreateFlags	imCreateFlags	=(m_imParams.dim == IMG_DIM_CUBE) ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0;
891
892	const VkImageCreateInfo		imCreateInfo	=
893	{
894		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
895		DE_NULL,
896		imCreateFlags,
897	    mapImageType(m_imParams.dim),
898	    m_imParams.format,
899		makeExtent3D(m_imParams.size[0], m_imParams.size[1], m_imParams.size[2]),
900	    (deUint32)m_imParams.levels,
901	    (deUint32)m_imParams.arrayLayers,
902		VK_SAMPLE_COUNT_1_BIT,
903		VK_IMAGE_TILING_OPTIMAL,
904		VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
905		VK_SHARING_MODE_EXCLUSIVE,
906		1,
907		&queueFamily,
908		VK_IMAGE_LAYOUT_UNDEFINED
909	};
910
911    m_im = createImage(vkd, device, &imCreateInfo);
912
913	// Allocate memory for image
914
915	VkMemoryRequirements imMemReq;
916	vkd.getImageMemoryRequirements(device, m_im.get(), &imMemReq);
917
918	m_imAllocation = m_context.getDefaultAllocator().allocate(imMemReq, MemoryRequirement::Any);
919	VK_CHECK(vkd.bindImageMemory(device, m_im.get(), m_imAllocation->getMemory(), m_imAllocation->getOffset()));
920
921	// Create VkImageView
922
923	// \todo [2016-06-23 collinbaker] Pick aspectMask based on image type (i.e. support depth and/or stencil images)
924	DE_ASSERT(m_imParams.dim != IMG_DIM_CUBE); // \todo Support cube maps
925	const VkImageSubresourceRange imViewSubresourceRange =
926	{
927		VK_IMAGE_ASPECT_COLOR_BIT,			// aspectMask
928		0,									// baseMipLevel
929		(deUint32)m_imParams.levels,		// levelCount
930		0,									// baseArrayLayer
931		(deUint32)m_imParams.arrayLayers	// layerCount
932	};
933
934	const VkComponentMapping imViewCompMap =
935	{
936		VK_COMPONENT_SWIZZLE_R,
937		VK_COMPONENT_SWIZZLE_G,
938		VK_COMPONENT_SWIZZLE_B,
939		VK_COMPONENT_SWIZZLE_A
940	};
941
942	const VkImageViewCreateInfo imViewCreateInfo =
943	{
944		VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,	// sType
945		DE_NULL,									// pNext
946		0,											// flags
947		m_im.get(),									// image
948		mapImageViewType(m_imParams),				// viewType
949	    m_imParams.format,							// format
950	    imViewCompMap,								// components
951		imViewSubresourceRange						// subresourceRange
952	};
953
954	m_imView = createImageView(vkd, device, &imViewCreateInfo);
955
956	// Create VkSampler
957
958	const VkSamplerCreateInfo samplerCreateInfo = mapSamplerCreateInfo(m_samplerParams);
959	m_sampler = createSampler(vkd, device, &samplerCreateInfo);
960
961	// Create additional descriptors
962
963	{
964		const VkDescriptorSetLayoutBinding		bindings[]	=
965		{
966			{ 0u,	VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,	1u,		VK_SHADER_STAGE_ALL,	DE_NULL		},
967		};
968		const VkDescriptorSetLayoutCreateInfo	layoutInfo	=
969		{
970			VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
971			DE_NULL,
972			(VkDescriptorSetLayoutCreateFlags)0u,
973			DE_LENGTH_OF_ARRAY(bindings),
974			bindings,
975		};
976
977		m_extraResourcesLayout = createDescriptorSetLayout(vkd, device, &layoutInfo);
978	}
979
980	{
981		const VkDescriptorPoolSize			poolSizes[]	=
982		{
983			{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,	1u	},
984		};
985		const VkDescriptorPoolCreateInfo	poolInfo	=
986		{
987			VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
988			DE_NULL,
989			(VkDescriptorPoolCreateFlags)VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
990			1u,		// maxSets
991			DE_LENGTH_OF_ARRAY(poolSizes),
992			poolSizes,
993		};
994
995		m_extraResourcesPool = createDescriptorPool(vkd, device, &poolInfo);
996	}
997
998	{
999		const VkDescriptorSetAllocateInfo	allocInfo	=
1000		{
1001			VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
1002			DE_NULL,
1003			*m_extraResourcesPool,
1004			1u,
1005			&m_extraResourcesLayout.get(),
1006		};
1007
1008		m_extraResourcesSet = allocateDescriptorSet(vkd, device, &allocInfo);
1009	}
1010
1011	{
1012		const VkDescriptorImageInfo		imageInfo			=
1013		{
1014			*m_sampler,
1015			*m_imView,
1016			VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
1017		};
1018		const VkWriteDescriptorSet		descriptorWrite		=
1019		{
1020			VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
1021			DE_NULL,
1022			*m_extraResourcesSet,
1023			0u,		// dstBinding
1024			0u,		// dstArrayElement
1025			1u,
1026			VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
1027			&imageInfo,
1028			(const VkDescriptorBufferInfo*)DE_NULL,
1029			(const VkBufferView*)DE_NULL,
1030		};
1031
1032		vkd.updateDescriptorSets(device, 1u, &descriptorWrite, 0u, DE_NULL);
1033	}
1034
1035	m_executor = de::MovePtr<ShaderExecutor>(createExecutor(m_context, m_shaderType, m_shaderSpec, *m_extraResourcesLayout));
1036}
1037
1038VkFormatFeatureFlags getRequiredFormatFeatures (const SamplerParameters& samplerParams)
1039{
1040	VkFormatFeatureFlags	features	= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
1041
1042	if (samplerParams.minFilter	 == VK_FILTER_LINEAR ||
1043		samplerParams.magFilter	 == VK_FILTER_LINEAR ||
1044		samplerParams.mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
1045	{
1046		features |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
1047	}
1048
1049	return features;
1050}
1051
1052bool TextureFilteringTestInstance::isSupported (void)
1053{
1054	const VkImageCreateFlags		imCreateFlags		= (m_imParams.dim == IMG_DIM_CUBE) ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0;
1055	const VkFormatFeatureFlags		reqImFeatures		= getRequiredFormatFeatures(m_samplerParams);
1056
1057	const VkImageFormatProperties	imFormatProperties	= getPhysicalDeviceImageFormatProperties(m_context.getInstanceInterface(),
1058																								 m_context.getPhysicalDevice(),
1059																								 m_imParams.format,
1060																								 mapImageType(m_imParams.dim),
1061																								 VK_IMAGE_TILING_OPTIMAL,
1062																								 VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
1063																								 imCreateFlags);
1064	const VkFormatProperties		formatProperties	= getPhysicalDeviceFormatProperties(m_context.getInstanceInterface(),
1065																							m_context.getPhysicalDevice(),
1066																							m_imParams.format);
1067
1068	// \todo [2016-06-23 collinbaker] Check image parameters against imFormatProperties
1069	DE_UNREF(imFormatProperties);
1070
1071	return (formatProperties.optimalTilingFeatures & reqImFeatures) == reqImFeatures;
1072}
1073
1074class TextureFilteringTestCase : public TestCase
1075{
1076public:
1077	TextureFilteringTestCase (tcu::TestContext&	testCtx,
1078							  const char*		name,
1079							  const char*		description)
1080		: TestCase(testCtx, name, description)
1081	{
1082	}
1083
1084	void initSpec (void);
1085
1086	virtual void initPrograms (vk::SourceCollections& programCollection) const
1087	{
1088		generateSources(m_testCaseData.shaderType, m_shaderSpec, programCollection);
1089	}
1090
1091	virtual de::MovePtr<DataGenerator> createGenerator (void) const = 0;
1092
1093	virtual TestInstance* createInstance (Context& ctx) const
1094	{
1095		return new TextureFilteringTestInstance(ctx, m_testCaseData, m_shaderSpec, createGenerator());
1096	}
1097
1098protected:
1099	de::MovePtr<ShaderExecutor> m_executor;
1100	TestCaseData				m_testCaseData;
1101	ShaderSpec					m_shaderSpec;
1102};
1103
1104void TextureFilteringTestCase::initSpec (void)
1105{
1106	m_shaderSpec.source = genLookupCode(m_testCaseData.imParams,
1107										m_testCaseData.samplerParams,
1108										m_testCaseData.sampleLookupSettings);
1109	m_shaderSpec.source += "\nsampledCoord = coord;";
1110
1111	m_shaderSpec.outputs.push_back(Symbol("result", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
1112	m_shaderSpec.outputs.push_back(Symbol("sampledCoord", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
1113	m_shaderSpec.inputs .push_back(Symbol("coord", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
1114	m_shaderSpec.inputs .push_back(Symbol("layer", glu::VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP)));
1115	m_shaderSpec.inputs .push_back(Symbol("dRef", glu::VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP)));
1116	m_shaderSpec.inputs .push_back(Symbol("dPdx", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
1117	m_shaderSpec.inputs .push_back(Symbol("dPdy", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
1118	m_shaderSpec.inputs .push_back(Symbol("lod", glu::VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP)));
1119
1120	m_shaderSpec.globalDeclarations = "layout(set=" + de::toString((int)EXTRA_RESOURCES_DESCRIPTOR_SET_INDEX) + ", binding=0) uniform highp ";
1121	m_shaderSpec.globalDeclarations += genSamplerDeclaration(m_testCaseData.imParams,
1122														   m_testCaseData.samplerParams);
1123	m_shaderSpec.globalDeclarations += " testSampler;";
1124}
1125
1126class Texture2DGradientTestCase : public TextureFilteringTestCase
1127{
1128public:
1129	Texture2DGradientTestCase (TestContext&			testCtx,
1130							   const char*			name,
1131							   const char*			desc,
1132							   TextureFormat		format,
1133							   IVec3				dimensions,
1134							   VkFilter				magFilter,
1135							   VkFilter				minFilter,
1136							   VkSamplerMipmapMode	mipmapFilter,
1137							   VkSamplerAddressMode	wrappingMode,
1138							   bool					useDerivatives)
1139
1140		: TextureFilteringTestCase	(testCtx, name, desc)
1141		, m_format					(format)
1142		, m_dimensions				(dimensions)
1143		, m_magFilter				(magFilter)
1144		, m_minFilter				(minFilter)
1145		, m_mipmapFilter			(mipmapFilter)
1146		, m_wrappingMode			(wrappingMode)
1147		, m_useDerivatives			(useDerivatives)
1148	{
1149		m_testCaseData = genTestCaseData();
1150		initSpec();
1151	}
1152
1153protected:
1154	class Generator;
1155
1156	virtual de::MovePtr<DataGenerator> createGenerator (void) const;
1157
1158	TestCaseData genTestCaseData()
1159	{
1160		// Generate grid
1161
1162		const SampleLookupSettings sampleLookupSettings =
1163		{
1164			m_useDerivatives ? LOOKUP_LOD_MODE_DERIVATIVES : LOOKUP_LOD_MODE_LOD, // lookupLodMode
1165			false, // hasLodBias
1166			false, // isProjective
1167		};
1168
1169		const SamplerParameters samplerParameters =
1170		{
1171			m_magFilter,
1172			m_minFilter,
1173			m_mipmapFilter,
1174			m_wrappingMode,
1175			m_wrappingMode,
1176			m_wrappingMode,
1177			VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE,
1178			0.0f,
1179			-1.0f,
1180			50.0f,
1181			false,
1182			false
1183		};
1184
1185		const deUint8 numLevels = (deUint8) (1 + deLog2Floor32(de::max(m_dimensions[0],
1186																	   m_dimensions[1])));
1187
1188		const ImageViewParameters imParameters =
1189		{
1190			IMG_DIM_2D,
1191			mapTextureFormat(m_format),
1192			m_dimensions,
1193			numLevels,
1194			false,
1195			1,
1196		};
1197
1198		const TestCaseData data =
1199		{
1200			std::vector<ConstPixelBufferAccess>(),
1201			imParameters,
1202			samplerParameters,
1203			sampleLookupSettings,
1204			glu::SHADERTYPE_FRAGMENT
1205		};
1206
1207		return data;
1208	}
1209
1210private:
1211	const TextureFormat			m_format;
1212	const IVec3					m_dimensions;
1213	const VkFilter				m_magFilter;
1214	const VkFilter				m_minFilter;
1215	const VkSamplerMipmapMode	m_mipmapFilter;
1216	const VkSamplerAddressMode	m_wrappingMode;
1217	const bool					m_useDerivatives;
1218};
1219
1220class Texture2DGradientTestCase::Generator : public DataGenerator
1221{
1222public:
1223	Generator (const Texture2DGradientTestCase* testCase) : m_testCase(testCase) {}
1224
1225	virtual ~Generator (void)
1226	{
1227		delete m_tex.release();
1228	}
1229
1230	virtual bool generate (void)
1231	{
1232		m_tex = de::MovePtr<Texture2D>(new Texture2D(m_testCase->m_format,
1233													 m_testCase->m_dimensions[0],
1234													 m_testCase->m_dimensions[1]));
1235
1236		const deUint8 numLevels = (deUint8) (1 + deLog2Floor32(de::max(m_testCase->m_dimensions[0],
1237																	   m_testCase->m_dimensions[1])));
1238
1239		const TextureFormatInfo fmtInfo = getTextureFormatInfo(m_testCase->m_format);
1240
1241		const Vec4 cBias  = fmtInfo.valueMin;
1242		const Vec4 cScale = fmtInfo.valueMax - fmtInfo.valueMin;
1243
1244		for (deUint8 levelNdx = 0; levelNdx < numLevels; ++levelNdx)
1245		{
1246			const Vec4 gMin = Vec4(0.0f, 0.0f, 0.0f, 1.0f) * cScale + cBias;
1247			const Vec4 gMax = Vec4(1.0f, 1.0f, 1.0f, 0.0f) * cScale + cBias;
1248
1249			m_tex->allocLevel(levelNdx);
1250			fillWithComponentGradients(m_tex->getLevel(levelNdx), gMin, gMax);
1251		}
1252
1253		return true;
1254	}
1255
1256	virtual std::vector<ConstPixelBufferAccess> getPba (void) const
1257	{
1258		std::vector<ConstPixelBufferAccess> pba;
1259
1260		const deUint8 numLevels = (deUint8) m_tex->getNumLevels();
1261
1262		for (deUint8 levelNdx = 0; levelNdx < numLevels; ++levelNdx)
1263		{
1264			pba.push_back(m_tex->getLevel(levelNdx));
1265		}
1266
1267		return pba;
1268	}
1269
1270	virtual std::vector<SampleArguments> getSampleArgs (void) const
1271	{
1272		std::vector<SampleArguments> args;
1273
1274		if (m_testCase->m_useDerivatives)
1275		{
1276			struct
1277			{
1278				Vec4 dPdx;
1279				Vec4 dPdy;
1280			}
1281			derivativePairs[] =
1282			{
1283				{Vec4(0.0f, 0.0f, 0.0f, 0.0f), Vec4(0.0f, 0.0f, 0.0f, 0.0f)},
1284				{Vec4(1.0f, 1.0f, 1.0f, 0.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f)},
1285				{Vec4(0.0f, 0.0f, 0.0f, 0.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f)},
1286				{Vec4(1.0f, 1.0f, 1.0f, 0.0f), Vec4(0.0f, 0.0f, 0.0f, 0.0f)},
1287				{Vec4(2.0f, 2.0f, 2.0f, 0.0f), Vec4(2.0f, 2.0f, 2.0f, 0.0f)}
1288			};
1289
1290			for (deInt32 i = 0; i < 2 * m_testCase->m_dimensions[0] + 1; ++i)
1291			{
1292				for (deInt32 j = 0; j < 2 * m_testCase->m_dimensions[1] + 1; ++j)
1293				{
1294				    for (deUint32 derivNdx = 0; derivNdx < DE_LENGTH_OF_ARRAY(derivativePairs); ++derivNdx)
1295					{
1296						SampleArguments cur;
1297						cur.coord = Vec4((float)i / (float)(2 * m_testCase->m_dimensions[0]),
1298										 (float)j / (float)(2 * m_testCase->m_dimensions[1]),
1299										 0.0f, 0.0f);
1300						cur.dPdx = derivativePairs[derivNdx].dPdx;
1301						cur.dPdy = derivativePairs[derivNdx].dPdy;
1302
1303						args.push_back(cur);
1304					}
1305				}
1306			}
1307		}
1308		else
1309		{
1310			const float lodList[] = {-1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0};
1311
1312			for (deInt32 i = 0; i < 2 * m_testCase->m_dimensions[0] + 1; ++i)
1313			{
1314				for (deInt32 j = 0; j < 2 * m_testCase->m_dimensions[1] + 1; ++j)
1315				{
1316					for (deUint32 lodNdx = 0; lodNdx < DE_LENGTH_OF_ARRAY(lodList); ++lodNdx)
1317					{
1318						SampleArguments cur;
1319						cur.coord = Vec4((float)i / (float)(2 * m_testCase->m_dimensions[0]),
1320										 (float)j / (float)(2 * m_testCase->m_dimensions[1]),
1321										 0.0f, 0.0f);
1322						cur.lod = lodList[lodNdx];
1323
1324						args.push_back(cur);
1325					}
1326				}
1327			}
1328		}
1329
1330		return args;
1331	}
1332
1333private:
1334	const Texture2DGradientTestCase*	m_testCase;
1335	de::MovePtr<Texture2D>				m_tex;
1336};
1337
1338de::MovePtr<DataGenerator> Texture2DGradientTestCase::createGenerator (void) const
1339{
1340	return de::MovePtr<DataGenerator>(new Generator(this));
1341}
1342
1343TestCaseGroup* create2DFormatTests (TestContext& testCtx)
1344{
1345	de::MovePtr<TestCaseGroup> tests(
1346		new TestCaseGroup(testCtx, "formats", "Various image formats"));
1347
1348    const VkFormat formats[] =
1349	{
1350	    VK_FORMAT_B4G4R4A4_UNORM_PACK16,
1351		VK_FORMAT_R5G6B5_UNORM_PACK16,
1352		VK_FORMAT_A1R5G5B5_UNORM_PACK16,
1353		VK_FORMAT_R8_UNORM,
1354		VK_FORMAT_R8_SNORM,
1355		VK_FORMAT_R8G8_UNORM,
1356		VK_FORMAT_R8G8_SNORM,
1357		VK_FORMAT_R8G8B8A8_UNORM,
1358		VK_FORMAT_R8G8B8A8_SNORM,
1359//		VK_FORMAT_R8G8B8A8_SRGB,
1360		VK_FORMAT_B8G8R8A8_UNORM,
1361//		VK_FORMAT_B8G8R8A8_SRGB,
1362		VK_FORMAT_A8B8G8R8_UNORM_PACK32,
1363		VK_FORMAT_A8B8G8R8_SNORM_PACK32,
1364//		VK_FORMAT_A8B8G8R8_SRGB_PACK32,
1365		VK_FORMAT_A2B10G10R10_UNORM_PACK32,
1366		VK_FORMAT_R16_SFLOAT,
1367		VK_FORMAT_R16G16_SFLOAT,
1368		VK_FORMAT_R16G16B16A16_SFLOAT,
1369		VK_FORMAT_R32_SFLOAT,
1370		VK_FORMAT_R32G32_SFLOAT,
1371		VK_FORMAT_R32G32B32A32_SFLOAT,
1372//		VK_FORMAT_B10G11R11_UFLOAT_PACK32,
1373//		VK_FORMAT_E5B9G9R9_UFLOAT_PACK32
1374	};
1375
1376	const IVec3 size(32, 32, 1);
1377
1378	for (deUint32 formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); ++formatNdx)
1379	{
1380		const std::string prefix = de::toLower(std::string(getFormatName(formats[formatNdx])).substr(10));
1381
1382		Texture2DGradientTestCase* testCaseNearest =
1383			new Texture2DGradientTestCase(
1384				testCtx,
1385			    (prefix + "_nearest").c_str(),
1386				"...",
1387				mapVkFormat(formats[formatNdx]),
1388				size,
1389				VK_FILTER_NEAREST,
1390				VK_FILTER_NEAREST,
1391				VK_SAMPLER_MIPMAP_MODE_NEAREST,
1392				VK_SAMPLER_ADDRESS_MODE_REPEAT,
1393				false);
1394
1395		tests->addChild(testCaseNearest);
1396
1397	    Texture2DGradientTestCase* testCaseLinear =
1398			new Texture2DGradientTestCase(
1399				testCtx,
1400			    (prefix + "_linear").c_str(),
1401				"...",
1402				mapVkFormat(formats[formatNdx]),
1403				size,
1404				VK_FILTER_LINEAR,
1405				VK_FILTER_LINEAR,
1406				VK_SAMPLER_MIPMAP_MODE_LINEAR,
1407				VK_SAMPLER_ADDRESS_MODE_REPEAT,
1408				false);
1409
1410		tests->addChild(testCaseLinear);
1411	}
1412
1413	return tests.release();
1414}
1415
1416TestCaseGroup* create2DDerivTests (TestContext& testCtx)
1417{
1418	de::MovePtr<TestCaseGroup> tests(
1419		new TestCaseGroup(testCtx, "derivatives", "Explicit derivative tests"));
1420
1421	const VkFormat				format		 = VK_FORMAT_R8G8B8A8_UNORM;
1422	const VkSamplerAddressMode	wrappingMode = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
1423	const IVec3					size		 = IVec3(16, 16, 1);
1424
1425	const VkFilter filters[2] =
1426	{
1427		VK_FILTER_NEAREST,
1428		VK_FILTER_LINEAR
1429	};
1430
1431	const VkSamplerMipmapMode mipmapFilters[2] =
1432	{
1433		VK_SAMPLER_MIPMAP_MODE_NEAREST,
1434		VK_SAMPLER_MIPMAP_MODE_LINEAR,
1435	};
1436
1437	for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(filters); ++magFilterNdx)
1438	{
1439		for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(filters); ++minFilterNdx)
1440		{
1441			for (int mipmapFilterNdx = 0; mipmapFilterNdx < DE_LENGTH_OF_ARRAY(mipmapFilters); ++mipmapFilterNdx)
1442			{
1443				std::ostringstream caseName;
1444
1445				switch (filters[magFilterNdx])
1446				{
1447					case VK_FILTER_NEAREST:
1448						caseName << "nearest";
1449						break;
1450
1451					case VK_FILTER_LINEAR:
1452						caseName << "linear";
1453						break;
1454
1455					default:
1456						break;
1457				}
1458
1459				switch (filters[minFilterNdx])
1460				{
1461					case VK_FILTER_NEAREST:
1462						caseName << "_nearest";
1463						break;
1464
1465					case VK_FILTER_LINEAR:
1466						caseName << "_linear";
1467						break;
1468
1469					default:
1470						break;
1471				}
1472
1473				caseName << "_mipmap";
1474
1475				switch (mipmapFilters[mipmapFilterNdx])
1476				{
1477					case VK_SAMPLER_MIPMAP_MODE_NEAREST:
1478						caseName << "_nearest";
1479						break;
1480
1481					case VK_SAMPLER_MIPMAP_MODE_LINEAR:
1482						caseName << "_linear";
1483						break;
1484
1485					default:
1486						break;
1487				}
1488
1489				Texture2DGradientTestCase* testCase =
1490					new Texture2DGradientTestCase(
1491						testCtx,
1492						caseName.str().c_str(),
1493						"...",
1494						mapVkFormat(format),
1495						size,
1496						filters[magFilterNdx],
1497						filters[minFilterNdx],
1498						mipmapFilters[mipmapFilterNdx],
1499						wrappingMode,
1500						true);
1501
1502				tests->addChild(testCase);
1503			}
1504		}
1505	}
1506
1507	return tests.release();
1508}
1509
1510TestCaseGroup* create2DSizeTests (TestContext& testCtx)
1511{
1512	de::MovePtr<TestCaseGroup> tests(
1513		new TestCaseGroup(testCtx, "sizes", "Various size and filtering combinations"));
1514
1515	const VkFilter filters[2] =
1516	{
1517		VK_FILTER_NEAREST,
1518		VK_FILTER_LINEAR
1519	};
1520
1521	const VkSamplerMipmapMode mipmapFilters[2] =
1522	{
1523		VK_SAMPLER_MIPMAP_MODE_NEAREST,
1524		VK_SAMPLER_MIPMAP_MODE_LINEAR
1525	};
1526
1527	const VkSamplerAddressMode wrappingModes[2] =
1528	{
1529		VK_SAMPLER_ADDRESS_MODE_REPEAT,
1530		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE
1531	};
1532
1533	const IVec3 sizes[] =
1534	{
1535		IVec3(2, 2, 1),
1536		IVec3(2, 3, 1),
1537		IVec3(3, 7, 1),
1538		IVec3(4, 8, 1),
1539		IVec3(31, 55, 1),
1540		IVec3(32, 32, 1),
1541		IVec3(32, 64, 1),
1542		IVec3(57, 35, 1),
1543		IVec3(128, 128, 1)
1544	};
1545
1546
1547	for (deUint32 sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes); ++sizeNdx)
1548	{
1549		for (deUint32 magFilterNdx = 0; magFilterNdx < 2; ++magFilterNdx)
1550		{
1551			for (deUint32 minFilterNdx = 0; minFilterNdx < 2; ++minFilterNdx)
1552			{
1553				for (deUint32 mipmapFilterNdx = 0; mipmapFilterNdx < 2; ++mipmapFilterNdx)
1554				{
1555					for (deUint32 wrappingModeNdx = 0; wrappingModeNdx < 2; ++wrappingModeNdx)
1556					{
1557						std::ostringstream caseName;
1558
1559						caseName << sizes[sizeNdx][0] << "x" << sizes[sizeNdx][1];
1560
1561						switch (filters[magFilterNdx])
1562						{
1563							case VK_FILTER_NEAREST:
1564								caseName << "_nearest";
1565								break;
1566
1567							case VK_FILTER_LINEAR:
1568								caseName << "_linear";
1569								break;
1570
1571							default:
1572								break;
1573						}
1574
1575						switch (filters[minFilterNdx])
1576						{
1577							case VK_FILTER_NEAREST:
1578								caseName << "_nearest";
1579								break;
1580
1581							case VK_FILTER_LINEAR:
1582								caseName << "_linear";
1583								break;
1584
1585							default:
1586								break;
1587						}
1588
1589						switch (mipmapFilters[mipmapFilterNdx])
1590						{
1591							case VK_SAMPLER_MIPMAP_MODE_NEAREST:
1592								caseName << "_mipmap_nearest";
1593								break;
1594
1595							case VK_SAMPLER_MIPMAP_MODE_LINEAR:
1596								caseName << "_mipmap_linear";
1597								break;
1598
1599							default:
1600								break;
1601						}
1602
1603						switch (wrappingModes[wrappingModeNdx])
1604						{
1605							case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE:
1606								caseName << "_clamp";
1607								break;
1608
1609							case VK_SAMPLER_ADDRESS_MODE_REPEAT:
1610								caseName << "_repeat";
1611								break;
1612
1613							default:
1614								break;
1615						}
1616
1617						Texture2DGradientTestCase* testCase =
1618							new Texture2DGradientTestCase(
1619								testCtx,
1620								caseName.str().c_str(),
1621								"...",
1622								mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM),
1623								sizes[sizeNdx],
1624								filters[magFilterNdx],
1625								filters[minFilterNdx],
1626								mipmapFilters[mipmapFilterNdx],
1627								wrappingModes[wrappingModeNdx],
1628								false);
1629
1630						tests->addChild(testCase);
1631					}
1632				}
1633			}
1634		}
1635	}
1636
1637	return tests.release();
1638}
1639
1640TestCaseGroup* create2DTests (TestContext& testCtx)
1641{
1642	de::MovePtr<TestCaseGroup> tests(
1643		new TestCaseGroup(testCtx, "2d", "2D Image filtering tests"));
1644
1645	tests->addChild(create2DSizeTests(testCtx));
1646	tests->addChild(create2DFormatTests(testCtx));
1647	tests->addChild(create2DDerivTests(testCtx));
1648
1649	return tests.release();
1650}
1651
1652} // anonymous
1653
1654TestCaseGroup* createExplicitLodTests (TestContext& testCtx)
1655{
1656	de::MovePtr<TestCaseGroup> tests(
1657		new TestCaseGroup(testCtx, "explicit_lod", "Texture filtering with explicit LOD"));
1658
1659	tests->addChild(create2DTests(testCtx));
1660
1661	return tests.release();
1662}
1663
1664} // texture
1665} // vkt
1666