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