• 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 	TestStatus result = verify();
597     endTime = deGetMicroseconds();
598 
599 	m_context.getTestContext().getLog() << TestLog::Message
600 										<< "Verification time: "
601 										<< endTime - startTime
602 										<< "us"
603 										<< TestLog::EndMessage;
604 
605 	return result;
606 }
607 
verify(void)608 TestStatus TextureFilteringTestInstance::verify (void)
609 {
610 	// \todo [2016-06-24 collinbaker] Handle cubemaps
611 
612 	const int										coordBits			= (int)m_context.getDeviceProperties().limits.subTexelPrecisionBits;
613 	const int										mipmapBits			= (int)m_context.getDeviceProperties().limits.mipmapPrecisionBits;
614 	const int										maxPrintedFailures	= 5;
615 	int												failCount			= 0;
616 	int												warningCount		= 0;
617 	const tcu::TextureFormat						tcuFormat			= mapVkFormat(m_imParams.format);
618 	std::vector<de::SharedPtr<tcu::FloatFormat>>	strictPrecision		= getPrecision(m_imParams.format, 0);
619 	std::vector<de::SharedPtr<tcu::FloatFormat>>	relaxedPrecision	= tcuFormat.type == tcu::TextureFormat::HALF_FLOAT ? getPrecision(m_imParams.format, -6) : getPrecision(m_imParams.format, -2);
620 	const bool										allowRelaxedPrecision	= (tcuFormat.type == tcu::TextureFormat::HALF_FLOAT || tcuFormat.type == tcu::TextureFormat::SNORM_INT8) &&
621 		(m_samplerParams.minFilter == VK_FILTER_LINEAR || m_samplerParams.magFilter == VK_FILTER_LINEAR);
622 
623 	const SampleVerifier			verifier			(m_imParams,
624 														 m_samplerParams,
625 														 m_sampleLookupSettings,
626 														 coordBits,
627 														 mipmapBits,
628 														 strictPrecision,
629 														 strictPrecision,
630 														 m_levels);
631 
632 	const SampleVerifier			relaxedVerifier		(m_imParams,
633 														 m_samplerParams,
634 														 m_sampleLookupSettings,
635 														 coordBits,
636 														 mipmapBits,
637 														 strictPrecision,
638 														 relaxedPrecision,
639 														 m_levels);
640 
641 	for (deUint32 sampleNdx = 0; sampleNdx < m_numSamples; ++sampleNdx)
642 	{
643 		bool compareOK = verifier.verifySample(m_sampleArguments[sampleNdx], m_resultSamples[sampleNdx]);
644 		if (compareOK)
645 			continue;
646 		if (allowRelaxedPrecision)
647 		{
648 			m_context.getTestContext().getLog()
649 				<< tcu::TestLog::Message
650 				<< "Warning: Strict validation failed, re-trying with lower precision for SNORM8 format or half float"
651 				<< tcu::TestLog::EndMessage;
652 
653 			compareOK = relaxedVerifier.verifySample(m_sampleArguments[sampleNdx], m_resultSamples[sampleNdx]);
654 			if (compareOK)
655 			{
656 				warningCount++;
657 				continue;
658 			}
659 		}
660 		if ( failCount++ < maxPrintedFailures )
661 		{
662 			// Re-run with report logging
663 			std::string report;
664 			verifier.verifySampleReport(m_sampleArguments[sampleNdx], m_resultSamples[sampleNdx], report);
665 
666 			m_context.getTestContext().getLog()
667 				<< TestLog::Section("Failed sample", "Failed sample")
668 				<< TestLog::Message
669 				<< "Sample " << sampleNdx << ".\n"
670 				<< "\tCoordinate: " << m_sampleArguments[sampleNdx].coord << "\n"
671 				<< "\tLOD: " << m_sampleArguments[sampleNdx].lod << "\n"
672 				<< "\tGPU Result: " << m_resultSamples[sampleNdx] << "\n\n"
673 				<< "Failure report:\n" << report << "\n"
674 				<< TestLog::EndMessage
675 				<< TestLog::EndSection;
676 		}
677 	}
678 
679 	m_context.getTestContext().getLog()
680 		<< TestLog::Message
681 		<< "Passed " << m_numSamples - failCount << " out of " << m_numSamples << "."
682 		<< TestLog::EndMessage;
683 
684 	if (failCount > 0)
685 		return TestStatus::fail("Verification failed");
686 	else if (warningCount > 0)
687 		return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Inaccurate filtering results");
688 
689 	return TestStatus::pass("Success");
690 }
691 
execute(void)692 void TextureFilteringTestInstance::execute (void)
693 {
694 	std::vector<float> coords, layers, dRefs, dPdxs, dPdys, lods;
695 
696 	for (deUint32 ndx = 0; ndx < m_numSamples; ++ndx)
697 	{
698 		const SampleArguments& sampleArgs = m_sampleArguments[ndx];
699 
700 		for (deUint8 compNdx = 0; compNdx < 4; ++compNdx)
701 		{
702 			coords.push_back(sampleArgs.coord[compNdx]);
703 			dPdxs .push_back(sampleArgs.dPdx[compNdx]);
704 			dPdys .push_back(sampleArgs.dPdy[compNdx]);
705 		}
706 
707 		layers.push_back(sampleArgs.layer);
708 		dRefs .push_back(sampleArgs.dRef);
709 		lods  .push_back(sampleArgs.lod);
710 	}
711 
712 	const void* inputs[6] =
713 	{
714 		reinterpret_cast<const void*>(&coords[0]),
715 		reinterpret_cast<const void*>(&layers[0]),
716 		reinterpret_cast<const void*>(&dRefs[0]),
717 		reinterpret_cast<const void*>(&dPdxs[0]),
718 		reinterpret_cast<const void*>(&dPdys[0]),
719 		reinterpret_cast<const void*>(&lods[0])
720 	};
721 
722 	// Staging buffers; data will be copied into vectors of Vec4
723 	// \todo [2016-06-24 collinbaker] Figure out if I actually need to
724 	// use staging buffers
725 	std::vector<float> resultSamplesTemp(m_numSamples * 4);
726 	std::vector<float> resultCoordsTemp (m_numSamples * 4);
727 
728 	void* outputs[2] =
729 	{
730 		reinterpret_cast<void*>(&resultSamplesTemp[0]),
731 		reinterpret_cast<void*>(&resultCoordsTemp[0])
732 	};
733 
734 	m_executor->execute(m_numSamples, inputs, outputs, *m_extraResourcesSet);
735 
736 	m_resultSamples.resize(m_numSamples);
737 	m_resultCoords .resize(m_numSamples);
738 
739 	for (deUint32 ndx = 0; ndx < m_numSamples; ++ndx)
740 	{
741 		m_resultSamples[ndx] = Vec4(resultSamplesTemp[4 * ndx + 0],
742 									resultSamplesTemp[4 * ndx + 1],
743 									resultSamplesTemp[4 * ndx + 2],
744 									resultSamplesTemp[4 * ndx + 3]);
745 
746 		m_resultCoords [ndx] = Vec4(resultCoordsTemp [4 * ndx + 0],
747 									resultCoordsTemp [4 * ndx + 1],
748 									resultCoordsTemp [4 * ndx + 2],
749 									resultCoordsTemp [4 * ndx + 3]);
750 	}
751 }
752 
createResources(void)753 void TextureFilteringTestInstance::createResources (void)
754 {
755 	// Create VkImage
756 
757 	const DeviceInterface&		vkd				= m_context.getDeviceInterface();
758 	const VkDevice				device			= m_context.getDevice();
759 
760 	const deUint32				queueFamily		= m_context.getUniversalQueueFamilyIndex();
761 	const VkImageCreateFlags	imCreateFlags	=(m_imParams.dim == IMG_DIM_CUBE) ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0;
762 
763 	const VkImageCreateInfo		imCreateInfo	=
764 	{
765 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
766 		DE_NULL,
767 		imCreateFlags,
768 	    mapImageType(m_imParams.dim),
769 	    m_imParams.format,
770 		makeExtent3D(m_imParams.size[0], m_imParams.size[1], m_imParams.size[2]),
771 	    (deUint32)m_imParams.levels,
772 	    (deUint32)m_imParams.arrayLayers,
773 		VK_SAMPLE_COUNT_1_BIT,
774 		VK_IMAGE_TILING_OPTIMAL,
775 		VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
776 		VK_SHARING_MODE_EXCLUSIVE,
777 		1,
778 		&queueFamily,
779 		VK_IMAGE_LAYOUT_UNDEFINED
780 	};
781 
782     m_im = createImage(vkd, device, &imCreateInfo);
783 
784 	// Allocate memory for image
785 
786 	VkMemoryRequirements imMemReq;
787 	vkd.getImageMemoryRequirements(device, m_im.get(), &imMemReq);
788 
789 	m_imAllocation = m_context.getDefaultAllocator().allocate(imMemReq, MemoryRequirement::Any);
790 	VK_CHECK(vkd.bindImageMemory(device, m_im.get(), m_imAllocation->getMemory(), m_imAllocation->getOffset()));
791 
792 	// Create VkImageView
793 
794 	// \todo [2016-06-23 collinbaker] Pick aspectMask based on image type (i.e. support depth and/or stencil images)
795 	DE_ASSERT(m_imParams.dim != IMG_DIM_CUBE); // \todo Support cube maps
796 	const VkImageSubresourceRange imViewSubresourceRange =
797 	{
798 		VK_IMAGE_ASPECT_COLOR_BIT,			// aspectMask
799 		0,									// baseMipLevel
800 		(deUint32)m_imParams.levels,		// levelCount
801 		0,									// baseArrayLayer
802 		(deUint32)m_imParams.arrayLayers	// layerCount
803 	};
804 
805 	const VkComponentMapping imViewCompMap =
806 	{
807 		VK_COMPONENT_SWIZZLE_R,
808 		VK_COMPONENT_SWIZZLE_G,
809 		VK_COMPONENT_SWIZZLE_B,
810 		VK_COMPONENT_SWIZZLE_A
811 	};
812 
813 	const VkImageViewCreateInfo imViewCreateInfo =
814 	{
815 		VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,	// sType
816 		DE_NULL,									// pNext
817 		0,											// flags
818 		m_im.get(),									// image
819 		mapImageViewType(m_imParams),				// viewType
820 	    m_imParams.format,							// format
821 	    imViewCompMap,								// components
822 		imViewSubresourceRange						// subresourceRange
823 	};
824 
825 	m_imView = createImageView(vkd, device, &imViewCreateInfo);
826 
827 	// Create VkSampler
828 
829 	const VkSamplerCreateInfo samplerCreateInfo = mapSamplerCreateInfo(m_samplerParams);
830 	m_sampler = createSampler(vkd, device, &samplerCreateInfo);
831 
832 	// Create additional descriptors
833 
834 	{
835 		const VkDescriptorSetLayoutBinding		bindings[]	=
836 		{
837 			{ 0u,	VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,	1u,		VK_SHADER_STAGE_ALL,	DE_NULL		},
838 		};
839 		const VkDescriptorSetLayoutCreateInfo	layoutInfo	=
840 		{
841 			VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
842 			DE_NULL,
843 			(VkDescriptorSetLayoutCreateFlags)0u,
844 			DE_LENGTH_OF_ARRAY(bindings),
845 			bindings,
846 		};
847 
848 		m_extraResourcesLayout = createDescriptorSetLayout(vkd, device, &layoutInfo);
849 	}
850 
851 	{
852 		const VkDescriptorPoolSize			poolSizes[]	=
853 		{
854 			{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,	1u	},
855 		};
856 		const VkDescriptorPoolCreateInfo	poolInfo	=
857 		{
858 			VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
859 			DE_NULL,
860 			(VkDescriptorPoolCreateFlags)VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
861 			1u,		// maxSets
862 			DE_LENGTH_OF_ARRAY(poolSizes),
863 			poolSizes,
864 		};
865 
866 		m_extraResourcesPool = createDescriptorPool(vkd, device, &poolInfo);
867 	}
868 
869 	{
870 		const VkDescriptorSetAllocateInfo	allocInfo	=
871 		{
872 			VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
873 			DE_NULL,
874 			*m_extraResourcesPool,
875 			1u,
876 			&m_extraResourcesLayout.get(),
877 		};
878 
879 		m_extraResourcesSet = allocateDescriptorSet(vkd, device, &allocInfo);
880 	}
881 
882 	{
883 		const VkDescriptorImageInfo		imageInfo			=
884 		{
885 			*m_sampler,
886 			*m_imView,
887 			VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
888 		};
889 		const VkWriteDescriptorSet		descriptorWrite		=
890 		{
891 			VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
892 			DE_NULL,
893 			*m_extraResourcesSet,
894 			0u,		// dstBinding
895 			0u,		// dstArrayElement
896 			1u,
897 			VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
898 			&imageInfo,
899 			(const VkDescriptorBufferInfo*)DE_NULL,
900 			(const VkBufferView*)DE_NULL,
901 		};
902 
903 		vkd.updateDescriptorSets(device, 1u, &descriptorWrite, 0u, DE_NULL);
904 	}
905 
906 	m_executor = de::MovePtr<ShaderExecutor>(createExecutor(m_context, m_shaderType, m_shaderSpec, *m_extraResourcesLayout));
907 }
908 
getRequiredFormatFeatures(const SamplerParameters & samplerParams)909 VkFormatFeatureFlags getRequiredFormatFeatures (const SamplerParameters& samplerParams)
910 {
911 	VkFormatFeatureFlags	features	= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
912 
913 	if (samplerParams.minFilter	 == VK_FILTER_LINEAR ||
914 		samplerParams.magFilter	 == VK_FILTER_LINEAR ||
915 		samplerParams.mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
916 	{
917 		features |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
918 	}
919 
920 	return features;
921 }
922 
isSupported(void)923 bool TextureFilteringTestInstance::isSupported (void)
924 {
925 	const VkImageCreateFlags		imCreateFlags		= (m_imParams.dim == IMG_DIM_CUBE) ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0;
926 	const VkFormatFeatureFlags		reqImFeatures		= getRequiredFormatFeatures(m_samplerParams);
927 
928 	const VkImageFormatProperties	imFormatProperties	= getPhysicalDeviceImageFormatProperties(m_context.getInstanceInterface(),
929 																								 m_context.getPhysicalDevice(),
930 																								 m_imParams.format,
931 																								 mapImageType(m_imParams.dim),
932 																								 VK_IMAGE_TILING_OPTIMAL,
933 																								 VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
934 																								 imCreateFlags);
935 	const VkFormatProperties		formatProperties	= getPhysicalDeviceFormatProperties(m_context.getInstanceInterface(),
936 																							m_context.getPhysicalDevice(),
937 																							m_imParams.format);
938 
939 	// \todo [2016-06-23 collinbaker] Check image parameters against imFormatProperties
940 	DE_UNREF(imFormatProperties);
941 
942 	return (formatProperties.optimalTilingFeatures & reqImFeatures) == reqImFeatures;
943 }
944 
945 class TextureFilteringTestCase : public TestCase
946 {
947 public:
TextureFilteringTestCase(tcu::TestContext & testCtx,const char * name,const char * description)948 	TextureFilteringTestCase (tcu::TestContext&	testCtx,
949 							  const char*		name,
950 							  const char*		description)
951 		: TestCase(testCtx, name, description)
952 	{
953 	}
954 
955 	void initSpec (void);
956 
checkSupport(Context & context) const957 	void checkSupport (Context& context) const
958 	{
959 		util::checkTextureSupport(context, m_testCaseData.imParams.format);
960 	}
961 
initPrograms(vk::SourceCollections & programCollection) const962 	virtual void initPrograms (vk::SourceCollections& programCollection) const
963 	{
964 		generateSources(m_testCaseData.shaderType, m_shaderSpec, programCollection);
965 	}
966 
967 	virtual de::MovePtr<DataGenerator> createGenerator (void) const = 0;
968 
createInstance(Context & ctx) const969 	virtual TestInstance* createInstance (Context& ctx) const
970 	{
971 		return new TextureFilteringTestInstance(ctx, m_testCaseData, m_shaderSpec, createGenerator());
972 	}
973 
974 protected:
975 	de::MovePtr<ShaderExecutor> m_executor;
976 	TestCaseData				m_testCaseData;
977 	ShaderSpec					m_shaderSpec;
978 };
979 
initSpec(void)980 void TextureFilteringTestCase::initSpec (void)
981 {
982 	m_shaderSpec.source = genLookupCode(m_testCaseData.imParams,
983 										m_testCaseData.samplerParams,
984 										m_testCaseData.sampleLookupSettings);
985 	m_shaderSpec.source += "\nsampledCoord = coord;";
986 
987 	m_shaderSpec.outputs.push_back(Symbol("result", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
988 	m_shaderSpec.outputs.push_back(Symbol("sampledCoord", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
989 	m_shaderSpec.inputs .push_back(Symbol("coord", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
990 	m_shaderSpec.inputs .push_back(Symbol("layer", glu::VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP)));
991 	m_shaderSpec.inputs .push_back(Symbol("dRef", glu::VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP)));
992 	m_shaderSpec.inputs .push_back(Symbol("dPdx", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
993 	m_shaderSpec.inputs .push_back(Symbol("dPdy", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
994 	m_shaderSpec.inputs .push_back(Symbol("lod", glu::VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP)));
995 
996 	m_shaderSpec.globalDeclarations = "layout(set=" + de::toString((int)EXTRA_RESOURCES_DESCRIPTOR_SET_INDEX) + ", binding=0) uniform highp ";
997 	m_shaderSpec.globalDeclarations += genSamplerDeclaration(m_testCaseData.imParams,
998 														   m_testCaseData.samplerParams);
999 	m_shaderSpec.globalDeclarations += " testSampler;";
1000 }
1001 
1002 class Texture2DGradientTestCase : public TextureFilteringTestCase
1003 {
1004 public:
Texture2DGradientTestCase(TestContext & testCtx,const char * name,const char * desc,TextureFormat format,IVec3 dimensions,VkFilter magFilter,VkFilter minFilter,VkSamplerMipmapMode mipmapFilter,VkSamplerAddressMode wrappingMode,bool useDerivatives)1005 	Texture2DGradientTestCase (TestContext&			testCtx,
1006 							   const char*			name,
1007 							   const char*			desc,
1008 							   TextureFormat		format,
1009 							   IVec3				dimensions,
1010 							   VkFilter				magFilter,
1011 							   VkFilter				minFilter,
1012 							   VkSamplerMipmapMode	mipmapFilter,
1013 							   VkSamplerAddressMode	wrappingMode,
1014 							   bool					useDerivatives)
1015 
1016 		: TextureFilteringTestCase	(testCtx, name, desc)
1017 		, m_format					(format)
1018 		, m_dimensions				(dimensions)
1019 		, m_magFilter				(magFilter)
1020 		, m_minFilter				(minFilter)
1021 		, m_mipmapFilter			(mipmapFilter)
1022 		, m_wrappingMode			(wrappingMode)
1023 		, m_useDerivatives			(useDerivatives)
1024 	{
1025 		m_testCaseData = genTestCaseData();
1026 		initSpec();
1027 	}
1028 
1029 protected:
1030 	class Generator;
1031 
1032 	virtual de::MovePtr<DataGenerator> createGenerator (void) const;
1033 
genTestCaseData()1034 	TestCaseData genTestCaseData()
1035 	{
1036 		// Generate grid
1037 
1038 		const SampleLookupSettings sampleLookupSettings =
1039 		{
1040 			m_useDerivatives ? LOOKUP_LOD_MODE_DERIVATIVES : LOOKUP_LOD_MODE_LOD, // lookupLodMode
1041 			false, // hasLodBias
1042 			false, // isProjective
1043 		};
1044 
1045 		const SamplerParameters samplerParameters =
1046 		{
1047 			m_magFilter,
1048 			m_minFilter,
1049 			m_mipmapFilter,
1050 			m_wrappingMode,
1051 			m_wrappingMode,
1052 			m_wrappingMode,
1053 			VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE,
1054 			0.0f,
1055 			-1.0f,
1056 			50.0f,
1057 			false,
1058 			false
1059 		};
1060 
1061 		const deUint8 numLevels = (deUint8) (1 + deLog2Floor32(de::max(m_dimensions[0],
1062 																	   m_dimensions[1])));
1063 
1064 		const ImageViewParameters imParameters =
1065 		{
1066 			IMG_DIM_2D,
1067 			mapTextureFormat(m_format),
1068 			m_dimensions,
1069 			numLevels,
1070 			false,
1071 			1,
1072 		};
1073 
1074 		const TestCaseData data =
1075 		{
1076 			std::vector<ConstPixelBufferAccess>(),
1077 			imParameters,
1078 			samplerParameters,
1079 			sampleLookupSettings,
1080 			glu::SHADERTYPE_FRAGMENT
1081 		};
1082 
1083 		return data;
1084 	}
1085 
1086 private:
1087 	const TextureFormat			m_format;
1088 	const IVec3					m_dimensions;
1089 	const VkFilter				m_magFilter;
1090 	const VkFilter				m_minFilter;
1091 	const VkSamplerMipmapMode	m_mipmapFilter;
1092 	const VkSamplerAddressMode	m_wrappingMode;
1093 	const bool					m_useDerivatives;
1094 };
1095 
1096 class Texture2DGradientTestCase::Generator : public DataGenerator
1097 {
1098 public:
Generator(const Texture2DGradientTestCase * testCase)1099 	Generator (const Texture2DGradientTestCase* testCase) : m_testCase(testCase) {}
1100 
~Generator(void)1101 	virtual ~Generator (void)
1102 	{
1103 		delete m_tex.release();
1104 	}
1105 
generate(void)1106 	virtual bool generate (void)
1107 	{
1108 		m_tex = de::MovePtr<Texture2D>(new Texture2D(m_testCase->m_format,
1109 													 m_testCase->m_dimensions[0],
1110 													 m_testCase->m_dimensions[1]));
1111 
1112 		const deUint8 numLevels = (deUint8) (1 + deLog2Floor32(de::max(m_testCase->m_dimensions[0],
1113 																	   m_testCase->m_dimensions[1])));
1114 
1115 		const TextureFormatInfo fmtInfo = getTextureFormatInfo(m_testCase->m_format);
1116 
1117 		const Vec4 cBias  = fmtInfo.valueMin;
1118 		const Vec4 cScale = fmtInfo.valueMax - fmtInfo.valueMin;
1119 
1120 		for (deUint8 levelNdx = 0; levelNdx < numLevels; ++levelNdx)
1121 		{
1122 			const Vec4 gMin = Vec4(0.0f, 0.0f, 0.0f, 1.0f) * cScale + cBias;
1123 			const Vec4 gMax = Vec4(1.0f, 1.0f, 1.0f, 0.0f) * cScale + cBias;
1124 
1125 			m_tex->allocLevel(levelNdx);
1126 			fillWithComponentGradients(m_tex->getLevel(levelNdx), gMin, gMax);
1127 		}
1128 
1129 		return true;
1130 	}
1131 
getPba(void) const1132 	virtual std::vector<ConstPixelBufferAccess> getPba (void) const
1133 	{
1134 		std::vector<ConstPixelBufferAccess> pba;
1135 
1136 		const deUint8 numLevels = (deUint8) m_tex->getNumLevels();
1137 
1138 		for (deUint8 levelNdx = 0; levelNdx < numLevels; ++levelNdx)
1139 		{
1140 			pba.push_back(m_tex->getLevel(levelNdx));
1141 		}
1142 
1143 		return pba;
1144 	}
1145 
getSampleArgs(void) const1146 	virtual std::vector<SampleArguments> getSampleArgs (void) const
1147 	{
1148 		std::vector<SampleArguments> args;
1149 
1150 		if (m_testCase->m_useDerivatives)
1151 		{
1152 			struct
1153 			{
1154 				Vec4 dPdx;
1155 				Vec4 dPdy;
1156 			}
1157 			derivativePairs[] =
1158 			{
1159 				{Vec4(0.0f, 0.0f, 0.0f, 0.0f), Vec4(0.0f, 0.0f, 0.0f, 0.0f)},
1160 				{Vec4(1.0f, 1.0f, 1.0f, 0.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f)},
1161 				{Vec4(0.0f, 0.0f, 0.0f, 0.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f)},
1162 				{Vec4(1.0f, 1.0f, 1.0f, 0.0f), Vec4(0.0f, 0.0f, 0.0f, 0.0f)},
1163 				{Vec4(2.0f, 2.0f, 2.0f, 0.0f), Vec4(2.0f, 2.0f, 2.0f, 0.0f)}
1164 			};
1165 
1166 			for (deInt32 i = 0; i < 2 * m_testCase->m_dimensions[0] + 1; ++i)
1167 			{
1168 				for (deInt32 j = 0; j < 2 * m_testCase->m_dimensions[1] + 1; ++j)
1169 				{
1170 				    for (deUint32 derivNdx = 0; derivNdx < DE_LENGTH_OF_ARRAY(derivativePairs); ++derivNdx)
1171 					{
1172 						SampleArguments cur = SampleArguments();
1173 						cur.coord = Vec4((float)i / (float)(2 * m_testCase->m_dimensions[0]),
1174 										 (float)j / (float)(2 * m_testCase->m_dimensions[1]),
1175 										 0.0f, 0.0f);
1176 						cur.dPdx = derivativePairs[derivNdx].dPdx;
1177 						cur.dPdy = derivativePairs[derivNdx].dPdy;
1178 
1179 						args.push_back(cur);
1180 					}
1181 				}
1182 			}
1183 		}
1184 		else
1185 		{
1186 			const float lodList[] = {-1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0};
1187 
1188 			for (deInt32 i = 0; i < 2 * m_testCase->m_dimensions[0] + 1; ++i)
1189 			{
1190 				for (deInt32 j = 0; j < 2 * m_testCase->m_dimensions[1] + 1; ++j)
1191 				{
1192 					for (deUint32 lodNdx = 0; lodNdx < DE_LENGTH_OF_ARRAY(lodList); ++lodNdx)
1193 					{
1194 						SampleArguments cur = SampleArguments();
1195 						cur.coord = Vec4((float)i / (float)(2 * m_testCase->m_dimensions[0]),
1196 										 (float)j / (float)(2 * m_testCase->m_dimensions[1]),
1197 										 0.0f, 0.0f);
1198 						cur.lod = lodList[lodNdx];
1199 
1200 						args.push_back(cur);
1201 					}
1202 				}
1203 			}
1204 		}
1205 
1206 		return args;
1207 	}
1208 
1209 private:
1210 	const Texture2DGradientTestCase*	m_testCase;
1211 	de::MovePtr<Texture2D>				m_tex;
1212 };
1213 
createGenerator(void) const1214 de::MovePtr<DataGenerator> Texture2DGradientTestCase::createGenerator (void) const
1215 {
1216 	return de::MovePtr<DataGenerator>(new Generator(this));
1217 }
1218 
create2DFormatTests(TestContext & testCtx)1219 TestCaseGroup* create2DFormatTests (TestContext& testCtx)
1220 {
1221 	de::MovePtr<TestCaseGroup> tests(
1222 		new TestCaseGroup(testCtx, "formats", "Various image formats"));
1223 
1224     const VkFormat formats[] =
1225 	{
1226 	    VK_FORMAT_B4G4R4A4_UNORM_PACK16,
1227 		VK_FORMAT_R5G6B5_UNORM_PACK16,
1228 		VK_FORMAT_A1R5G5B5_UNORM_PACK16,
1229 		VK_FORMAT_R8_UNORM,
1230 		VK_FORMAT_R8_SNORM,
1231 		VK_FORMAT_R8G8_UNORM,
1232 		VK_FORMAT_R8G8_SNORM,
1233 		VK_FORMAT_R8G8B8A8_UNORM,
1234 		VK_FORMAT_R8G8B8A8_SNORM,
1235 //		VK_FORMAT_R8G8B8A8_SRGB,
1236 		VK_FORMAT_B8G8R8A8_UNORM,
1237 //		VK_FORMAT_B8G8R8A8_SRGB,
1238 		VK_FORMAT_A8B8G8R8_UNORM_PACK32,
1239 		VK_FORMAT_A8B8G8R8_SNORM_PACK32,
1240 //		VK_FORMAT_A8B8G8R8_SRGB_PACK32,
1241 		VK_FORMAT_A2B10G10R10_UNORM_PACK32,
1242 		VK_FORMAT_R16_SFLOAT,
1243 		VK_FORMAT_R16G16_SFLOAT,
1244 		VK_FORMAT_R16G16B16A16_SFLOAT,
1245 		VK_FORMAT_R32_SFLOAT,
1246 		VK_FORMAT_R32G32_SFLOAT,
1247 		VK_FORMAT_R32G32B32A32_SFLOAT,
1248 //		VK_FORMAT_B10G11R11_UFLOAT_PACK32,
1249 //		VK_FORMAT_E5B9G9R9_UFLOAT_PACK32
1250 	};
1251 
1252 	const IVec3 size(32, 32, 1);
1253 
1254 	for (deUint32 formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); ++formatNdx)
1255 	{
1256 		const std::string prefix = de::toLower(std::string(getFormatName(formats[formatNdx])).substr(10));
1257 
1258 		Texture2DGradientTestCase* testCaseNearest =
1259 			new Texture2DGradientTestCase(
1260 				testCtx,
1261 			    (prefix + "_nearest").c_str(),
1262 				"...",
1263 				mapVkFormat(formats[formatNdx]),
1264 				size,
1265 				VK_FILTER_NEAREST,
1266 				VK_FILTER_NEAREST,
1267 				VK_SAMPLER_MIPMAP_MODE_NEAREST,
1268 				VK_SAMPLER_ADDRESS_MODE_REPEAT,
1269 				false);
1270 
1271 		tests->addChild(testCaseNearest);
1272 
1273 	    Texture2DGradientTestCase* testCaseLinear =
1274 			new Texture2DGradientTestCase(
1275 				testCtx,
1276 			    (prefix + "_linear").c_str(),
1277 				"...",
1278 				mapVkFormat(formats[formatNdx]),
1279 				size,
1280 				VK_FILTER_LINEAR,
1281 				VK_FILTER_LINEAR,
1282 				VK_SAMPLER_MIPMAP_MODE_LINEAR,
1283 				VK_SAMPLER_ADDRESS_MODE_REPEAT,
1284 				false);
1285 
1286 		tests->addChild(testCaseLinear);
1287 	}
1288 
1289 	return tests.release();
1290 }
1291 
create2DDerivTests(TestContext & testCtx)1292 TestCaseGroup* create2DDerivTests (TestContext& testCtx)
1293 {
1294 	de::MovePtr<TestCaseGroup> tests(
1295 		new TestCaseGroup(testCtx, "derivatives", "Explicit derivative tests"));
1296 
1297 	const VkFormat				format		 = VK_FORMAT_R8G8B8A8_UNORM;
1298 	const VkSamplerAddressMode	wrappingMode = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
1299 	const IVec3					size		 = IVec3(16, 16, 1);
1300 
1301 	const VkFilter filters[2] =
1302 	{
1303 		VK_FILTER_NEAREST,
1304 		VK_FILTER_LINEAR
1305 	};
1306 
1307 	const VkSamplerMipmapMode mipmapFilters[2] =
1308 	{
1309 		VK_SAMPLER_MIPMAP_MODE_NEAREST,
1310 		VK_SAMPLER_MIPMAP_MODE_LINEAR,
1311 	};
1312 
1313 	for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(filters); ++magFilterNdx)
1314 	{
1315 		for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(filters); ++minFilterNdx)
1316 		{
1317 			for (int mipmapFilterNdx = 0; mipmapFilterNdx < DE_LENGTH_OF_ARRAY(mipmapFilters); ++mipmapFilterNdx)
1318 			{
1319 				std::ostringstream caseName;
1320 
1321 				switch (filters[magFilterNdx])
1322 				{
1323 					case VK_FILTER_NEAREST:
1324 						caseName << "nearest";
1325 						break;
1326 
1327 					case VK_FILTER_LINEAR:
1328 						caseName << "linear";
1329 						break;
1330 
1331 					default:
1332 						break;
1333 				}
1334 
1335 				switch (filters[minFilterNdx])
1336 				{
1337 					case VK_FILTER_NEAREST:
1338 						caseName << "_nearest";
1339 						break;
1340 
1341 					case VK_FILTER_LINEAR:
1342 						caseName << "_linear";
1343 						break;
1344 
1345 					default:
1346 						break;
1347 				}
1348 
1349 				caseName << "_mipmap";
1350 
1351 				switch (mipmapFilters[mipmapFilterNdx])
1352 				{
1353 					case VK_SAMPLER_MIPMAP_MODE_NEAREST:
1354 						caseName << "_nearest";
1355 						break;
1356 
1357 					case VK_SAMPLER_MIPMAP_MODE_LINEAR:
1358 						caseName << "_linear";
1359 						break;
1360 
1361 					default:
1362 						break;
1363 				}
1364 
1365 				Texture2DGradientTestCase* testCase =
1366 					new Texture2DGradientTestCase(
1367 						testCtx,
1368 						caseName.str().c_str(),
1369 						"...",
1370 						mapVkFormat(format),
1371 						size,
1372 						filters[magFilterNdx],
1373 						filters[minFilterNdx],
1374 						mipmapFilters[mipmapFilterNdx],
1375 						wrappingMode,
1376 						true);
1377 
1378 				tests->addChild(testCase);
1379 			}
1380 		}
1381 	}
1382 
1383 	return tests.release();
1384 }
1385 
create2DSizeTests(TestContext & testCtx)1386 TestCaseGroup* create2DSizeTests (TestContext& testCtx)
1387 {
1388 	de::MovePtr<TestCaseGroup> tests(
1389 		new TestCaseGroup(testCtx, "sizes", "Various size and filtering combinations"));
1390 
1391 	const VkFilter filters[2] =
1392 	{
1393 		VK_FILTER_NEAREST,
1394 		VK_FILTER_LINEAR
1395 	};
1396 
1397 	const VkSamplerMipmapMode mipmapFilters[2] =
1398 	{
1399 		VK_SAMPLER_MIPMAP_MODE_NEAREST,
1400 		VK_SAMPLER_MIPMAP_MODE_LINEAR
1401 	};
1402 
1403 	const VkSamplerAddressMode wrappingModes[2] =
1404 	{
1405 		VK_SAMPLER_ADDRESS_MODE_REPEAT,
1406 		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE
1407 	};
1408 
1409 	const IVec3 sizes[] =
1410 	{
1411 		IVec3(2, 2, 1),
1412 		IVec3(2, 3, 1),
1413 		IVec3(3, 7, 1),
1414 		IVec3(4, 8, 1),
1415 		IVec3(31, 55, 1),
1416 		IVec3(32, 32, 1),
1417 		IVec3(32, 64, 1),
1418 		IVec3(57, 35, 1),
1419 		IVec3(128, 128, 1)
1420 	};
1421 
1422 
1423 	for (deUint32 sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes); ++sizeNdx)
1424 	{
1425 		for (deUint32 magFilterNdx = 0; magFilterNdx < 2; ++magFilterNdx)
1426 		{
1427 			for (deUint32 minFilterNdx = 0; minFilterNdx < 2; ++minFilterNdx)
1428 			{
1429 				for (deUint32 mipmapFilterNdx = 0; mipmapFilterNdx < 2; ++mipmapFilterNdx)
1430 				{
1431 					for (deUint32 wrappingModeNdx = 0; wrappingModeNdx < 2; ++wrappingModeNdx)
1432 					{
1433 						std::ostringstream caseName;
1434 
1435 						caseName << sizes[sizeNdx][0] << "x" << sizes[sizeNdx][1];
1436 
1437 						switch (filters[magFilterNdx])
1438 						{
1439 							case VK_FILTER_NEAREST:
1440 								caseName << "_nearest";
1441 								break;
1442 
1443 							case VK_FILTER_LINEAR:
1444 								caseName << "_linear";
1445 								break;
1446 
1447 							default:
1448 								break;
1449 						}
1450 
1451 						switch (filters[minFilterNdx])
1452 						{
1453 							case VK_FILTER_NEAREST:
1454 								caseName << "_nearest";
1455 								break;
1456 
1457 							case VK_FILTER_LINEAR:
1458 								caseName << "_linear";
1459 								break;
1460 
1461 							default:
1462 								break;
1463 						}
1464 
1465 						switch (mipmapFilters[mipmapFilterNdx])
1466 						{
1467 							case VK_SAMPLER_MIPMAP_MODE_NEAREST:
1468 								caseName << "_mipmap_nearest";
1469 								break;
1470 
1471 							case VK_SAMPLER_MIPMAP_MODE_LINEAR:
1472 								caseName << "_mipmap_linear";
1473 								break;
1474 
1475 							default:
1476 								break;
1477 						}
1478 
1479 						switch (wrappingModes[wrappingModeNdx])
1480 						{
1481 							case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE:
1482 								caseName << "_clamp";
1483 								break;
1484 
1485 							case VK_SAMPLER_ADDRESS_MODE_REPEAT:
1486 								caseName << "_repeat";
1487 								break;
1488 
1489 							default:
1490 								break;
1491 						}
1492 
1493 						Texture2DGradientTestCase* testCase =
1494 							new Texture2DGradientTestCase(
1495 								testCtx,
1496 								caseName.str().c_str(),
1497 								"...",
1498 								mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM),
1499 								sizes[sizeNdx],
1500 								filters[magFilterNdx],
1501 								filters[minFilterNdx],
1502 								mipmapFilters[mipmapFilterNdx],
1503 								wrappingModes[wrappingModeNdx],
1504 								false);
1505 
1506 						tests->addChild(testCase);
1507 					}
1508 				}
1509 			}
1510 		}
1511 	}
1512 
1513 	return tests.release();
1514 }
1515 
create2DTests(TestContext & testCtx)1516 TestCaseGroup* create2DTests (TestContext& testCtx)
1517 {
1518 	de::MovePtr<TestCaseGroup> tests(
1519 		new TestCaseGroup(testCtx, "2d", "2D Image filtering tests"));
1520 
1521 	tests->addChild(create2DSizeTests(testCtx));
1522 	tests->addChild(create2DFormatTests(testCtx));
1523 	tests->addChild(create2DDerivTests(testCtx));
1524 
1525 	return tests.release();
1526 }
1527 
1528 } // anonymous
1529 
createExplicitLodTests(TestContext & testCtx)1530 TestCaseGroup* createExplicitLodTests (TestContext& testCtx)
1531 {
1532 	de::MovePtr<TestCaseGroup> tests(
1533 		new TestCaseGroup(testCtx, "explicit_lod", "Texture filtering with explicit LOD"));
1534 
1535 	tests->addChild(create2DTests(testCtx));
1536 
1537 	return tests.release();
1538 }
1539 
1540 } // texture
1541 } // vkt
1542