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