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