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