Home | History | Annotate | Download | only in texture
      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 
     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 
    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 
    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 
    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 
    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 	Unique<VkCommandPool> copyPool(createCommandPool(vkd, dev, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, uqfi));
    362 
    363 	Unique<VkCommandBuffer> copyBuffer(allocateCommandBuffer(vkd, dev, *copyPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
    364 
    365 	std::vector<VkBufferImageCopy> copyRegions;
    366 
    367 	deUint8* const bufMapPtr = reinterpret_cast<deUint8*>(bufMem->getHostPtr());
    368 	deUint8* bufCurPtr = bufMapPtr;
    369 
    370 	for (int level = 0; level < imParams.levels; ++level)
    371 	{
    372 		const IVec3 curLevelSize = pba[level].getSize();
    373 
    374 		const std::size_t copySize =
    375 			getPixelSize(mapVkFormat(imParams.format))
    376 			* curLevelSize[0] * curLevelSize[1] * curLevelSize[2]
    377 			* imParams.arrayLayers;
    378 
    379 		deMemcpy(bufCurPtr, pba[level].getDataPtr(), copySize);
    380 
    381 	    flushMappedMemoryRange(vkd, dev, bufMem->getMemory(), bufMem->getOffset() + (bufCurPtr - bufMapPtr), copySize);
    382 
    383 		const VkImageSubresourceLayers curSubresource =
    384 		{
    385 			VK_IMAGE_ASPECT_COLOR_BIT,
    386 			(deUint32)level,
    387 			0,
    388 			(deUint32)imParams.arrayLayers
    389 		};
    390 
    391 		const VkBufferImageCopy curRegion =
    392 		{
    393 			(VkDeviceSize) (bufCurPtr - bufMapPtr),
    394 			0,
    395 			0,
    396 			curSubresource,
    397 			{0U, 0U, 0U},
    398 			{(deUint32)curLevelSize[0], (deUint32)curLevelSize[1], (deUint32)curLevelSize[2]}
    399 		};
    400 
    401 		copyRegions.push_back(curRegion);
    402 
    403 		bufCurPtr += copySize;
    404 	}
    405 
    406 	const VkCommandBufferBeginInfo beginInfo =
    407 	{
    408 		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
    409 		DE_NULL,
    410 		VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
    411 		DE_NULL
    412 	};
    413 
    414 	VK_CHECK(vkd.beginCommandBuffer(copyBuffer.get(), &beginInfo));
    415 
    416 	const VkImageSubresourceRange imMemBarSubRange =
    417 	{
    418 		VK_IMAGE_ASPECT_COLOR_BIT,
    419 		0,
    420 		(deUint32)imParams.levels,
    421 		0,
    422 		(deUint32)imParams.arrayLayers
    423 	};
    424 
    425 	VkImageMemoryBarrier imMemBar =
    426 	{
    427 		VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
    428 		DE_NULL,
    429 		0,
    430 		VK_ACCESS_TRANSFER_WRITE_BIT,
    431 		VK_IMAGE_LAYOUT_UNDEFINED,
    432 		VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
    433 		VK_QUEUE_FAMILY_IGNORED,
    434 		VK_QUEUE_FAMILY_IGNORED,
    435 		im,
    436 		imMemBarSubRange
    437 	};
    438 
    439 	VkBufferMemoryBarrier bufMemBar =
    440 	{
    441 		VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
    442 		DE_NULL,
    443 		VK_ACCESS_HOST_WRITE_BIT,
    444 		VK_ACCESS_TRANSFER_READ_BIT,
    445 		VK_QUEUE_FAMILY_IGNORED,
    446 		VK_QUEUE_FAMILY_IGNORED,
    447 		buf.get(),
    448 		0,
    449 		bufSize
    450 	};
    451 
    452 	vkd.cmdPipelineBarrier(copyBuffer.get(),
    453 						   VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
    454 						   VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
    455 						   0,
    456 						   0,
    457 						   DE_NULL,
    458 						   1,
    459 						   &bufMemBar,
    460 						   1,
    461 						   &imMemBar);
    462 
    463 	vkd.cmdCopyBufferToImage(copyBuffer.get(),
    464 							 buf.get(),
    465 							 im,
    466 							 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
    467 							 (deUint32)copyRegions.size(),
    468 							 &copyRegions[0]);
    469 
    470 	imMemBar.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
    471 	imMemBar.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
    472 	imMemBar.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
    473 	imMemBar.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
    474 
    475 	vkd.cmdPipelineBarrier(copyBuffer.get(),
    476 						   VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
    477 						   VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
    478 						   0,
    479 						   0,
    480 						   DE_NULL,
    481 						   0,
    482 						   DE_NULL,
    483 						   1,
    484 						   &imMemBar);
    485 
    486 	VK_CHECK(vkd.endCommandBuffer(copyBuffer.get()));
    487 
    488 	const VkSubmitInfo copySubmitInfo =
    489 	{
    490 		VK_STRUCTURE_TYPE_SUBMIT_INFO,
    491 		DE_NULL,
    492 		0,
    493 		DE_NULL,
    494 		DE_NULL,
    495 		1,
    496 		&(copyBuffer.get()),
    497 		0,
    498 		DE_NULL
    499 	};
    500 
    501 	VK_CHECK(vkd.queueSubmit(ctx.getUniversalQueue(), 1, &copySubmitInfo, 0));
    502 	VK_CHECK(vkd.queueWaitIdle(ctx.getUniversalQueue()));
    503 }
    504 
    505 struct TestCaseData
    506 {
    507 	std::vector<ConstPixelBufferAccess>	pba;
    508 	ImageViewParameters					imParams;
    509 	SamplerParameters					samplerParams;
    510 	SampleLookupSettings				sampleLookupSettings;
    511 	glu::ShaderType						shaderType;
    512 };
    513 
    514 VkSamplerCreateInfo mapSamplerCreateInfo (const SamplerParameters& samplerParams)
    515 {
    516 	VkSamplerCreateInfo samplerCreateInfo =
    517 	{
    518 		VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,				// sType
    519 		DE_NULL,											// pNext
    520 		0U,													// flags
    521 	    samplerParams.magFilter,							// magFilter
    522 		samplerParams.minFilter,							// minFilter
    523 		samplerParams.mipmapFilter,							// mipmapMode
    524 	    samplerParams.wrappingModeU,						// addressModeU
    525 	    samplerParams.wrappingModeV,						// addressModeV
    526 	    samplerParams.wrappingModeW,						// addressMoveW
    527 		samplerParams.lodBias,								// mipLodBias
    528 		VK_FALSE,											// anisotropyEnable
    529 		1.0f,												// maxAnisotropy
    530 		VK_FALSE,											// compareEnable
    531 		VK_COMPARE_OP_NEVER,								// compareOp
    532 		samplerParams.minLod,								// minLod
    533 		samplerParams.maxLod,								// maxLod
    534 	    samplerParams.borderColor,							// borderColor
    535 		samplerParams.isUnnormalized ? VK_TRUE : VK_FALSE,	// unnormalizedCoordinates
    536 	};
    537 
    538 	if (samplerParams.isCompare)
    539 	{
    540 		samplerCreateInfo.compareEnable = VK_TRUE;
    541 
    542 	    DE_FATAL("Not implemented");
    543 	}
    544 
    545 	return samplerCreateInfo;
    546 }
    547 
    548 VkImageType mapImageType (ImgDim dim)
    549 {
    550 	VkImageType imType;
    551 
    552 	switch (dim)
    553 	{
    554 		case IMG_DIM_1D:
    555 			imType = VK_IMAGE_TYPE_1D;
    556 			break;
    557 
    558 		case IMG_DIM_2D:
    559 		case IMG_DIM_CUBE:
    560 			imType = VK_IMAGE_TYPE_2D;
    561 			break;
    562 
    563 		case IMG_DIM_3D:
    564 			imType = VK_IMAGE_TYPE_3D;
    565 			break;
    566 
    567 		default:
    568 			imType = VK_IMAGE_TYPE_LAST;
    569 			break;
    570 	}
    571 
    572 	return imType;
    573 }
    574 
    575 VkImageViewType mapImageViewType (const ImageViewParameters& imParams)
    576 {
    577 	VkImageViewType imViewType;
    578 
    579 	if (imParams.isArrayed)
    580 	{
    581 		switch (imParams.dim)
    582 		{
    583 			case IMG_DIM_1D:
    584 				imViewType = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
    585 				break;
    586 
    587 			case IMG_DIM_2D:
    588 				imViewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
    589 				break;
    590 
    591 			case IMG_DIM_CUBE:
    592 				imViewType = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
    593 				break;
    594 
    595 			default:
    596 				imViewType = VK_IMAGE_VIEW_TYPE_LAST;
    597 				break;
    598 		}
    599 	}
    600 	else
    601 	{
    602 		switch (imParams.dim)
    603 		{
    604 			case IMG_DIM_1D:
    605 				imViewType = VK_IMAGE_VIEW_TYPE_1D;
    606 				break;
    607 
    608 			case IMG_DIM_2D:
    609 				imViewType = VK_IMAGE_VIEW_TYPE_2D;
    610 				break;
    611 
    612 			case IMG_DIM_3D:
    613 				imViewType = VK_IMAGE_VIEW_TYPE_3D;
    614 				break;
    615 
    616 			case IMG_DIM_CUBE:
    617 				imViewType = VK_IMAGE_VIEW_TYPE_CUBE;
    618 				break;
    619 
    620 			default:
    621 				imViewType = VK_IMAGE_VIEW_TYPE_LAST;
    622 				break;
    623 		}
    624 	}
    625 
    626 	return imViewType;
    627 }
    628 
    629 class DataGenerator
    630 {
    631 public:
    632 	virtual										~DataGenerator	(void) {}
    633 
    634 	virtual bool								generate		(void) = 0;
    635 
    636 	virtual std::vector<ConstPixelBufferAccess> getPba			(void) const = 0;
    637 	virtual std::vector<SampleArguments>		getSampleArgs	(void) const = 0;
    638 
    639 protected:
    640 												DataGenerator	(void) {}
    641 };
    642 
    643 class TextureFilteringTestInstance : public TestInstance
    644 {
    645 public:
    646 										TextureFilteringTestInstance	(Context&					ctx,
    647 																		 const TestCaseData&		testCaseData,
    648 																		 const ShaderSpec&			shaderSpec,
    649 																		 de::MovePtr<DataGenerator>	gen);
    650 
    651 	virtual TestStatus					iterate							(void) { return runTest(); }
    652 
    653 protected:
    654 	TestStatus							runTest							(void);
    655 	bool								isSupported						(void);
    656 	void								createResources					(void);
    657 	void								execute							(void);
    658 	bool								verify							(void);
    659 
    660 	tcu::Sampler						mapTcuSampler					(void) const;
    661 
    662 	const glu::ShaderType				m_shaderType;
    663 	const ShaderSpec					m_shaderSpec;
    664 	const ImageViewParameters			m_imParams;
    665 	const SamplerParameters				m_samplerParams;
    666 	const SampleLookupSettings			m_sampleLookupSettings;
    667 
    668 	std::vector<SampleArguments>		m_sampleArguments;
    669 	deUint32							m_numSamples;
    670 
    671 	de::MovePtr<Allocation>				m_imAllocation;
    672 	Move<VkImage>						m_im;
    673 	Move<VkImageView>					m_imView;
    674 	Move<VkSampler>						m_sampler;
    675 
    676 	Move<VkDescriptorSetLayout>			m_extraResourcesLayout;
    677 	Move<VkDescriptorPool>				m_extraResourcesPool;
    678 	Move<VkDescriptorSet>				m_extraResourcesSet;
    679 
    680 	de::MovePtr<ShaderExecutor>			m_executor;
    681 
    682 	std::vector<ConstPixelBufferAccess> m_levels;
    683 	de::MovePtr<DataGenerator>			m_gen;
    684 
    685 	std::vector<Vec4>					m_resultSamples;
    686 	std::vector<Vec4>					m_resultCoords;
    687 };
    688 
    689 TextureFilteringTestInstance::TextureFilteringTestInstance (Context&					ctx,
    690 															const TestCaseData&			testCaseData,
    691 															const ShaderSpec&			shaderSpec,
    692 															de::MovePtr<DataGenerator>	gen)
    693 	: TestInstance				(ctx)
    694 	, m_shaderType				(testCaseData.shaderType)
    695 	, m_shaderSpec				(shaderSpec)
    696 	, m_imParams				(testCaseData.imParams)
    697 	, m_samplerParams			(testCaseData.samplerParams)
    698 	, m_sampleLookupSettings	(testCaseData.sampleLookupSettings)
    699 	, m_levels					(testCaseData.pba)
    700 	, m_gen						(gen.release())
    701 {
    702 	for (deUint8 compNdx = 0; compNdx < 3; ++compNdx)
    703 		DE_ASSERT(m_imParams.size[compNdx] > 0);
    704 }
    705 
    706 TestStatus TextureFilteringTestInstance::runTest (void)
    707 {
    708 	if (!isSupported())
    709 	    TCU_THROW(NotSupportedError, "Unsupported combination of filtering and image format");
    710 
    711 	TCU_CHECK(m_gen->generate());
    712 	m_levels = m_gen->getPba();
    713 
    714 	m_sampleArguments = m_gen->getSampleArgs();
    715 	m_numSamples = (deUint32)m_sampleArguments.size();
    716 
    717 	createResources();
    718 	initializeImage(m_context, m_im.get(), &m_levels[0], m_imParams);
    719 
    720 	deUint64 startTime, endTime;
    721 
    722 	startTime = deGetMicroseconds();
    723 	execute();
    724 	endTime = deGetMicroseconds();
    725 
    726 	m_context.getTestContext().getLog() << TestLog::Message
    727 										<< "Execution time: "
    728 										<< endTime - startTime
    729 										<< "us"
    730 										<< TestLog::EndMessage;
    731 
    732     startTime = deGetMicroseconds();
    733 	bool result = verify();
    734     endTime = deGetMicroseconds();
    735 
    736 	m_context.getTestContext().getLog() << TestLog::Message
    737 										<< "Verification time: "
    738 										<< endTime - startTime
    739 										<< "us"
    740 										<< TestLog::EndMessage;
    741 
    742 	if (result)
    743 	{
    744 		return TestStatus::pass("Success");
    745 	}
    746 	else
    747 	{
    748 		// \todo [2016-06-24 collinbaker] Print report if verification fails
    749 		return TestStatus::fail("Verification failed");
    750 	}
    751 }
    752 
    753 bool TextureFilteringTestInstance::verify (void)
    754 {
    755 	// \todo [2016-06-24 collinbaker] Handle cubemaps
    756 
    757 	const int				coordBits			= (int)m_context.getDeviceProperties().limits.subTexelPrecisionBits;
    758 	const int				mipmapBits			= (int)m_context.getDeviceProperties().limits.mipmapPrecisionBits;
    759 	const int				maxPrintedFailures	= 5;
    760 	int						failCount			= 0;
    761 
    762 	const SampleVerifier	verifier			(m_imParams,
    763 												 m_samplerParams,
    764 												 m_sampleLookupSettings,
    765 												 coordBits,
    766 												 mipmapBits,
    767 												 getConversionPrecision(m_imParams.format),
    768 												 getFilteringPrecision(m_imParams.format),
    769 												 m_levels);
    770 
    771 
    772 	for (deUint32 sampleNdx = 0; sampleNdx < m_numSamples; ++sampleNdx)
    773 	{
    774 		if (!verifier.verifySample(m_sampleArguments[sampleNdx], m_resultSamples[sampleNdx]))
    775 		{
    776 			if (failCount++ < maxPrintedFailures)
    777 			{
    778 				// Re-run with report logging
    779 				std::string report;
    780 				verifier.verifySampleReport(m_sampleArguments[sampleNdx], m_resultSamples[sampleNdx], report);
    781 
    782 				m_context.getTestContext().getLog()
    783 					<< TestLog::Section("Failed sample", "Failed sample")
    784 					<< TestLog::Message
    785 					<< "Sample " << sampleNdx << ".\n"
    786 					<< "\tCoordinate: " << m_sampleArguments[sampleNdx].coord << "\n"
    787 					<< "\tLOD: " << m_sampleArguments[sampleNdx].lod << "\n"
    788 					<< "\tGPU Result: " << m_resultSamples[sampleNdx] << "\n\n"
    789 					<< "Failure report:\n" << report << "\n"
    790 					<< TestLog::EndMessage
    791 					<< TestLog::EndSection;
    792 			}
    793 		}
    794 	}
    795 
    796 	m_context.getTestContext().getLog()
    797 		<< TestLog::Message
    798 		<< "Passed " << m_numSamples - failCount << " out of " << m_numSamples << "."
    799 		<< TestLog::EndMessage;
    800 
    801 	return failCount == 0;
    802 }
    803 
    804 void TextureFilteringTestInstance::execute (void)
    805 {
    806 	std::vector<float> coords, layers, dRefs, dPdxs, dPdys, lods;
    807 
    808 	for (deUint32 ndx = 0; ndx < m_numSamples; ++ndx)
    809 	{
    810 		const SampleArguments& sampleArgs = m_sampleArguments[ndx];
    811 
    812 		for (deUint8 compNdx = 0; compNdx < 4; ++compNdx)
    813 		{
    814 			coords.push_back(sampleArgs.coord[compNdx]);
    815 			dPdxs .push_back(sampleArgs.dPdx[compNdx]);
    816 			dPdys .push_back(sampleArgs.dPdy[compNdx]);
    817 		}
    818 
    819 		layers.push_back(sampleArgs.layer);
    820 		dRefs .push_back(sampleArgs.dRef);
    821 		lods  .push_back(sampleArgs.lod);
    822 	}
    823 
    824 	const void* inputs[6] =
    825 	{
    826 		reinterpret_cast<const void*>(&coords[0]),
    827 		reinterpret_cast<const void*>(&layers[0]),
    828 		reinterpret_cast<const void*>(&dRefs[0]),
    829 		reinterpret_cast<const void*>(&dPdxs[0]),
    830 		reinterpret_cast<const void*>(&dPdys[0]),
    831 		reinterpret_cast<const void*>(&lods[0])
    832 	};
    833 
    834 	// Staging buffers; data will be copied into vectors of Vec4
    835 	// \todo [2016-06-24 collinbaker] Figure out if I actually need to
    836 	// use staging buffers
    837 	std::vector<float> resultSamplesTemp(m_numSamples * 4);
    838 	std::vector<float> resultCoordsTemp (m_numSamples * 4);
    839 
    840 	void* outputs[2] =
    841 	{
    842 		reinterpret_cast<void*>(&resultSamplesTemp[0]),
    843 		reinterpret_cast<void*>(&resultCoordsTemp[0])
    844 	};
    845 
    846 	m_executor->execute(m_numSamples, inputs, outputs, *m_extraResourcesSet);
    847 
    848 	m_resultSamples.resize(m_numSamples);
    849 	m_resultCoords .resize(m_numSamples);
    850 
    851 	for (deUint32 ndx = 0; ndx < m_numSamples; ++ndx)
    852 	{
    853 		m_resultSamples[ndx] = Vec4(resultSamplesTemp[4 * ndx + 0],
    854 									resultSamplesTemp[4 * ndx + 1],
    855 									resultSamplesTemp[4 * ndx + 2],
    856 									resultSamplesTemp[4 * ndx + 3]);
    857 
    858 		m_resultCoords [ndx] = Vec4(resultCoordsTemp [4 * ndx + 0],
    859 									resultCoordsTemp [4 * ndx + 1],
    860 									resultCoordsTemp [4 * ndx + 2],
    861 									resultCoordsTemp [4 * ndx + 3]);
    862 	}
    863 }
    864 
    865 void TextureFilteringTestInstance::createResources (void)
    866 {
    867 	// Create VkImage
    868 
    869 	const DeviceInterface&		vkd				= m_context.getDeviceInterface();
    870 	const VkDevice				device			= m_context.getDevice();
    871 
    872 	const deUint32				queueFamily		= m_context.getUniversalQueueFamilyIndex();
    873 	const VkImageCreateFlags	imCreateFlags	=(m_imParams.dim == IMG_DIM_CUBE) ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0;
    874 
    875 	const VkImageCreateInfo		imCreateInfo	=
    876 	{
    877 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
    878 		DE_NULL,
    879 		imCreateFlags,
    880 	    mapImageType(m_imParams.dim),
    881 	    m_imParams.format,
    882 		makeExtent3D(m_imParams.size[0], m_imParams.size[1], m_imParams.size[2]),
    883 	    (deUint32)m_imParams.levels,
    884 	    (deUint32)m_imParams.arrayLayers,
    885 		VK_SAMPLE_COUNT_1_BIT,
    886 		VK_IMAGE_TILING_OPTIMAL,
    887 		VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
    888 		VK_SHARING_MODE_EXCLUSIVE,
    889 		1,
    890 		&queueFamily,
    891 		VK_IMAGE_LAYOUT_UNDEFINED
    892 	};
    893 
    894     m_im = createImage(vkd, device, &imCreateInfo);
    895 
    896 	// Allocate memory for image
    897 
    898 	VkMemoryRequirements imMemReq;
    899 	vkd.getImageMemoryRequirements(device, m_im.get(), &imMemReq);
    900 
    901 	m_imAllocation = m_context.getDefaultAllocator().allocate(imMemReq, MemoryRequirement::Any);
    902 	VK_CHECK(vkd.bindImageMemory(device, m_im.get(), m_imAllocation->getMemory(), m_imAllocation->getOffset()));
    903 
    904 	// Create VkImageView
    905 
    906 	// \todo [2016-06-23 collinbaker] Pick aspectMask based on image type (i.e. support depth and/or stencil images)
    907 	DE_ASSERT(m_imParams.dim != IMG_DIM_CUBE); // \todo Support cube maps
    908 	const VkImageSubresourceRange imViewSubresourceRange =
    909 	{
    910 		VK_IMAGE_ASPECT_COLOR_BIT,			// aspectMask
    911 		0,									// baseMipLevel
    912 		(deUint32)m_imParams.levels,		// levelCount
    913 		0,									// baseArrayLayer
    914 		(deUint32)m_imParams.arrayLayers	// layerCount
    915 	};
    916 
    917 	const VkComponentMapping imViewCompMap =
    918 	{
    919 		VK_COMPONENT_SWIZZLE_R,
    920 		VK_COMPONENT_SWIZZLE_G,
    921 		VK_COMPONENT_SWIZZLE_B,
    922 		VK_COMPONENT_SWIZZLE_A
    923 	};
    924 
    925 	const VkImageViewCreateInfo imViewCreateInfo =
    926 	{
    927 		VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,	// sType
    928 		DE_NULL,									// pNext
    929 		0,											// flags
    930 		m_im.get(),									// image
    931 		mapImageViewType(m_imParams),				// viewType
    932 	    m_imParams.format,							// format
    933 	    imViewCompMap,								// components
    934 		imViewSubresourceRange						// subresourceRange
    935 	};
    936 
    937 	m_imView = createImageView(vkd, device, &imViewCreateInfo);
    938 
    939 	// Create VkSampler
    940 
    941 	const VkSamplerCreateInfo samplerCreateInfo = mapSamplerCreateInfo(m_samplerParams);
    942 	m_sampler = createSampler(vkd, device, &samplerCreateInfo);
    943 
    944 	// Create additional descriptors
    945 
    946 	{
    947 		const VkDescriptorSetLayoutBinding		bindings[]	=
    948 		{
    949 			{ 0u,	VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,	1u,		VK_SHADER_STAGE_ALL,	DE_NULL		},
    950 		};
    951 		const VkDescriptorSetLayoutCreateInfo	layoutInfo	=
    952 		{
    953 			VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
    954 			DE_NULL,
    955 			(VkDescriptorSetLayoutCreateFlags)0u,
    956 			DE_LENGTH_OF_ARRAY(bindings),
    957 			bindings,
    958 		};
    959 
    960 		m_extraResourcesLayout = createDescriptorSetLayout(vkd, device, &layoutInfo);
    961 	}
    962 
    963 	{
    964 		const VkDescriptorPoolSize			poolSizes[]	=
    965 		{
    966 			{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,	1u	},
    967 		};
    968 		const VkDescriptorPoolCreateInfo	poolInfo	=
    969 		{
    970 			VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
    971 			DE_NULL,
    972 			(VkDescriptorPoolCreateFlags)VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
    973 			1u,		// maxSets
    974 			DE_LENGTH_OF_ARRAY(poolSizes),
    975 			poolSizes,
    976 		};
    977 
    978 		m_extraResourcesPool = createDescriptorPool(vkd, device, &poolInfo);
    979 	}
    980 
    981 	{
    982 		const VkDescriptorSetAllocateInfo	allocInfo	=
    983 		{
    984 			VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
    985 			DE_NULL,
    986 			*m_extraResourcesPool,
    987 			1u,
    988 			&m_extraResourcesLayout.get(),
    989 		};
    990 
    991 		m_extraResourcesSet = allocateDescriptorSet(vkd, device, &allocInfo);
    992 	}
    993 
    994 	{
    995 		const VkDescriptorImageInfo		imageInfo			=
    996 		{
    997 			*m_sampler,
    998 			*m_imView,
    999 			VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
   1000 		};
   1001 		const VkWriteDescriptorSet		descriptorWrite		=
   1002 		{
   1003 			VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
   1004 			DE_NULL,
   1005 			*m_extraResourcesSet,
   1006 			0u,		// dstBinding
   1007 			0u,		// dstArrayElement
   1008 			1u,
   1009 			VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
   1010 			&imageInfo,
   1011 			(const VkDescriptorBufferInfo*)DE_NULL,
   1012 			(const VkBufferView*)DE_NULL,
   1013 		};
   1014 
   1015 		vkd.updateDescriptorSets(device, 1u, &descriptorWrite, 0u, DE_NULL);
   1016 	}
   1017 
   1018 	m_executor = de::MovePtr<ShaderExecutor>(createExecutor(m_context, m_shaderType, m_shaderSpec, *m_extraResourcesLayout));
   1019 }
   1020 
   1021 VkFormatFeatureFlags getRequiredFormatFeatures (const SamplerParameters& samplerParams)
   1022 {
   1023 	VkFormatFeatureFlags	features	= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
   1024 
   1025 	if (samplerParams.minFilter	 == VK_FILTER_LINEAR ||
   1026 		samplerParams.magFilter	 == VK_FILTER_LINEAR ||
   1027 		samplerParams.mipmapFilter == VK_SAMPLER_MIPMAP_MODE_LINEAR)
   1028 	{
   1029 		features |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
   1030 	}
   1031 
   1032 	return features;
   1033 }
   1034 
   1035 bool TextureFilteringTestInstance::isSupported (void)
   1036 {
   1037 	const VkImageCreateFlags		imCreateFlags		= (m_imParams.dim == IMG_DIM_CUBE) ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0;
   1038 	const VkFormatFeatureFlags		reqImFeatures		= getRequiredFormatFeatures(m_samplerParams);
   1039 
   1040 	const VkImageFormatProperties	imFormatProperties	= getPhysicalDeviceImageFormatProperties(m_context.getInstanceInterface(),
   1041 																								 m_context.getPhysicalDevice(),
   1042 																								 m_imParams.format,
   1043 																								 mapImageType(m_imParams.dim),
   1044 																								 VK_IMAGE_TILING_OPTIMAL,
   1045 																								 VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
   1046 																								 imCreateFlags);
   1047 	const VkFormatProperties		formatProperties	= getPhysicalDeviceFormatProperties(m_context.getInstanceInterface(),
   1048 																							m_context.getPhysicalDevice(),
   1049 																							m_imParams.format);
   1050 
   1051 	// \todo [2016-06-23 collinbaker] Check image parameters against imFormatProperties
   1052 	DE_UNREF(imFormatProperties);
   1053 
   1054 	return (formatProperties.optimalTilingFeatures & reqImFeatures) == reqImFeatures;
   1055 }
   1056 
   1057 class TextureFilteringTestCase : public TestCase
   1058 {
   1059 public:
   1060 	TextureFilteringTestCase (tcu::TestContext&	testCtx,
   1061 							  const char*		name,
   1062 							  const char*		description)
   1063 		: TestCase(testCtx, name, description)
   1064 	{
   1065 	}
   1066 
   1067 	void initSpec (void);
   1068 
   1069 	virtual void initPrograms (vk::SourceCollections& programCollection) const
   1070 	{
   1071 		generateSources(m_testCaseData.shaderType, m_shaderSpec, programCollection);
   1072 	}
   1073 
   1074 	virtual de::MovePtr<DataGenerator> createGenerator (void) const = 0;
   1075 
   1076 	virtual TestInstance* createInstance (Context& ctx) const
   1077 	{
   1078 		return new TextureFilteringTestInstance(ctx, m_testCaseData, m_shaderSpec, createGenerator());
   1079 	}
   1080 
   1081 protected:
   1082 	de::MovePtr<ShaderExecutor> m_executor;
   1083 	TestCaseData				m_testCaseData;
   1084 	ShaderSpec					m_shaderSpec;
   1085 };
   1086 
   1087 void TextureFilteringTestCase::initSpec (void)
   1088 {
   1089 	m_shaderSpec.source = genLookupCode(m_testCaseData.imParams,
   1090 										m_testCaseData.samplerParams,
   1091 										m_testCaseData.sampleLookupSettings);
   1092 	m_shaderSpec.source += "\nsampledCoord = coord;";
   1093 
   1094 	m_shaderSpec.outputs.push_back(Symbol("result", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
   1095 	m_shaderSpec.outputs.push_back(Symbol("sampledCoord", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
   1096 	m_shaderSpec.inputs .push_back(Symbol("coord", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
   1097 	m_shaderSpec.inputs .push_back(Symbol("layer", glu::VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP)));
   1098 	m_shaderSpec.inputs .push_back(Symbol("dRef", glu::VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP)));
   1099 	m_shaderSpec.inputs .push_back(Symbol("dPdx", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
   1100 	m_shaderSpec.inputs .push_back(Symbol("dPdy", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
   1101 	m_shaderSpec.inputs .push_back(Symbol("lod", glu::VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP)));
   1102 
   1103 	m_shaderSpec.globalDeclarations = "layout(set=" + de::toString((int)EXTRA_RESOURCES_DESCRIPTOR_SET_INDEX) + ", binding=0) uniform highp ";
   1104 	m_shaderSpec.globalDeclarations += genSamplerDeclaration(m_testCaseData.imParams,
   1105 														   m_testCaseData.samplerParams);
   1106 	m_shaderSpec.globalDeclarations += " testSampler;";
   1107 }
   1108 
   1109 class Texture2DGradientTestCase : public TextureFilteringTestCase
   1110 {
   1111 public:
   1112 	Texture2DGradientTestCase (TestContext&			testCtx,
   1113 							   const char*			name,
   1114 							   const char*			desc,
   1115 							   TextureFormat		format,
   1116 							   IVec3				dimensions,
   1117 							   VkFilter				magFilter,
   1118 							   VkFilter				minFilter,
   1119 							   VkSamplerMipmapMode	mipmapFilter,
   1120 							   VkSamplerAddressMode	wrappingMode,
   1121 							   bool					useDerivatives)
   1122 
   1123 		: TextureFilteringTestCase	(testCtx, name, desc)
   1124 		, m_format					(format)
   1125 		, m_dimensions				(dimensions)
   1126 		, m_magFilter				(magFilter)
   1127 		, m_minFilter				(minFilter)
   1128 		, m_mipmapFilter			(mipmapFilter)
   1129 		, m_wrappingMode			(wrappingMode)
   1130 		, m_useDerivatives			(useDerivatives)
   1131 	{
   1132 		m_testCaseData = genTestCaseData();
   1133 		initSpec();
   1134 	}
   1135 
   1136 protected:
   1137 	class Generator;
   1138 
   1139 	virtual de::MovePtr<DataGenerator> createGenerator (void) const;
   1140 
   1141 	TestCaseData genTestCaseData()
   1142 	{
   1143 		// Generate grid
   1144 
   1145 		const SampleLookupSettings sampleLookupSettings =
   1146 		{
   1147 			m_useDerivatives ? LOOKUP_LOD_MODE_DERIVATIVES : LOOKUP_LOD_MODE_LOD, // lookupLodMode
   1148 			false, // hasLodBias
   1149 			false, // isProjective
   1150 		};
   1151 
   1152 		const SamplerParameters samplerParameters =
   1153 		{
   1154 			m_magFilter,
   1155 			m_minFilter,
   1156 			m_mipmapFilter,
   1157 			m_wrappingMode,
   1158 			m_wrappingMode,
   1159 			m_wrappingMode,
   1160 			VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE,
   1161 			0.0f,
   1162 			-1.0f,
   1163 			50.0f,
   1164 			false,
   1165 			false
   1166 		};
   1167 
   1168 		const deUint8 numLevels = (deUint8) (1 + deLog2Floor32(de::max(m_dimensions[0],
   1169 																	   m_dimensions[1])));
   1170 
   1171 		const ImageViewParameters imParameters =
   1172 		{
   1173 			IMG_DIM_2D,
   1174 			mapTextureFormat(m_format),
   1175 			m_dimensions,
   1176 			numLevels,
   1177 			false,
   1178 			1,
   1179 		};
   1180 
   1181 		const TestCaseData data =
   1182 		{
   1183 			std::vector<ConstPixelBufferAccess>(),
   1184 			imParameters,
   1185 			samplerParameters,
   1186 			sampleLookupSettings,
   1187 			glu::SHADERTYPE_FRAGMENT
   1188 		};
   1189 
   1190 		return data;
   1191 	}
   1192 
   1193 private:
   1194 	const TextureFormat			m_format;
   1195 	const IVec3					m_dimensions;
   1196 	const VkFilter				m_magFilter;
   1197 	const VkFilter				m_minFilter;
   1198 	const VkSamplerMipmapMode	m_mipmapFilter;
   1199 	const VkSamplerAddressMode	m_wrappingMode;
   1200 	const bool					m_useDerivatives;
   1201 };
   1202 
   1203 class Texture2DGradientTestCase::Generator : public DataGenerator
   1204 {
   1205 public:
   1206 	Generator (const Texture2DGradientTestCase* testCase) : m_testCase(testCase) {}
   1207 
   1208 	virtual ~Generator (void)
   1209 	{
   1210 		delete m_tex.release();
   1211 	}
   1212 
   1213 	virtual bool generate (void)
   1214 	{
   1215 		m_tex = de::MovePtr<Texture2D>(new Texture2D(m_testCase->m_format,
   1216 													 m_testCase->m_dimensions[0],
   1217 													 m_testCase->m_dimensions[1]));
   1218 
   1219 		const deUint8 numLevels = (deUint8) (1 + deLog2Floor32(de::max(m_testCase->m_dimensions[0],
   1220 																	   m_testCase->m_dimensions[1])));
   1221 
   1222 		const TextureFormatInfo fmtInfo = getTextureFormatInfo(m_testCase->m_format);
   1223 
   1224 		const Vec4 cBias  = fmtInfo.valueMin;
   1225 		const Vec4 cScale = fmtInfo.valueMax - fmtInfo.valueMin;
   1226 
   1227 		for (deUint8 levelNdx = 0; levelNdx < numLevels; ++levelNdx)
   1228 		{
   1229 			const Vec4 gMin = Vec4(0.0f, 0.0f, 0.0f, 1.0f) * cScale + cBias;
   1230 			const Vec4 gMax = Vec4(1.0f, 1.0f, 1.0f, 0.0f) * cScale + cBias;
   1231 
   1232 			m_tex->allocLevel(levelNdx);
   1233 			fillWithComponentGradients(m_tex->getLevel(levelNdx), gMin, gMax);
   1234 		}
   1235 
   1236 		return true;
   1237 	}
   1238 
   1239 	virtual std::vector<ConstPixelBufferAccess> getPba (void) const
   1240 	{
   1241 		std::vector<ConstPixelBufferAccess> pba;
   1242 
   1243 		const deUint8 numLevels = (deUint8) m_tex->getNumLevels();
   1244 
   1245 		for (deUint8 levelNdx = 0; levelNdx < numLevels; ++levelNdx)
   1246 		{
   1247 			pba.push_back(m_tex->getLevel(levelNdx));
   1248 		}
   1249 
   1250 		return pba;
   1251 	}
   1252 
   1253 	virtual std::vector<SampleArguments> getSampleArgs (void) const
   1254 	{
   1255 		std::vector<SampleArguments> args;
   1256 
   1257 		if (m_testCase->m_useDerivatives)
   1258 		{
   1259 			struct
   1260 			{
   1261 				Vec4 dPdx;
   1262 				Vec4 dPdy;
   1263 			}
   1264 			derivativePairs[] =
   1265 			{
   1266 				{Vec4(0.0f, 0.0f, 0.0f, 0.0f), Vec4(0.0f, 0.0f, 0.0f, 0.0f)},
   1267 				{Vec4(1.0f, 1.0f, 1.0f, 0.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f)},
   1268 				{Vec4(0.0f, 0.0f, 0.0f, 0.0f), Vec4(1.0f, 1.0f, 1.0f, 0.0f)},
   1269 				{Vec4(1.0f, 1.0f, 1.0f, 0.0f), Vec4(0.0f, 0.0f, 0.0f, 0.0f)},
   1270 				{Vec4(2.0f, 2.0f, 2.0f, 0.0f), Vec4(2.0f, 2.0f, 2.0f, 0.0f)}
   1271 			};
   1272 
   1273 			for (deInt32 i = 0; i < 2 * m_testCase->m_dimensions[0] + 1; ++i)
   1274 			{
   1275 				for (deInt32 j = 0; j < 2 * m_testCase->m_dimensions[1] + 1; ++j)
   1276 				{
   1277 				    for (deUint32 derivNdx = 0; derivNdx < DE_LENGTH_OF_ARRAY(derivativePairs); ++derivNdx)
   1278 					{
   1279 						SampleArguments cur = SampleArguments();
   1280 						cur.coord = Vec4((float)i / (float)(2 * m_testCase->m_dimensions[0]),
   1281 										 (float)j / (float)(2 * m_testCase->m_dimensions[1]),
   1282 										 0.0f, 0.0f);
   1283 						cur.dPdx = derivativePairs[derivNdx].dPdx;
   1284 						cur.dPdy = derivativePairs[derivNdx].dPdy;
   1285 
   1286 						args.push_back(cur);
   1287 					}
   1288 				}
   1289 			}
   1290 		}
   1291 		else
   1292 		{
   1293 			const float lodList[] = {-1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0};
   1294 
   1295 			for (deInt32 i = 0; i < 2 * m_testCase->m_dimensions[0] + 1; ++i)
   1296 			{
   1297 				for (deInt32 j = 0; j < 2 * m_testCase->m_dimensions[1] + 1; ++j)
   1298 				{
   1299 					for (deUint32 lodNdx = 0; lodNdx < DE_LENGTH_OF_ARRAY(lodList); ++lodNdx)
   1300 					{
   1301 						SampleArguments cur = SampleArguments();
   1302 						cur.coord = Vec4((float)i / (float)(2 * m_testCase->m_dimensions[0]),
   1303 										 (float)j / (float)(2 * m_testCase->m_dimensions[1]),
   1304 										 0.0f, 0.0f);
   1305 						cur.lod = lodList[lodNdx];
   1306 
   1307 						args.push_back(cur);
   1308 					}
   1309 				}
   1310 			}
   1311 		}
   1312 
   1313 		return args;
   1314 	}
   1315 
   1316 private:
   1317 	const Texture2DGradientTestCase*	m_testCase;
   1318 	de::MovePtr<Texture2D>				m_tex;
   1319 };
   1320 
   1321 de::MovePtr<DataGenerator> Texture2DGradientTestCase::createGenerator (void) const
   1322 {
   1323 	return de::MovePtr<DataGenerator>(new Generator(this));
   1324 }
   1325 
   1326 TestCaseGroup* create2DFormatTests (TestContext& testCtx)
   1327 {
   1328 	de::MovePtr<TestCaseGroup> tests(
   1329 		new TestCaseGroup(testCtx, "formats", "Various image formats"));
   1330 
   1331     const VkFormat formats[] =
   1332 	{
   1333 	    VK_FORMAT_B4G4R4A4_UNORM_PACK16,
   1334 		VK_FORMAT_R5G6B5_UNORM_PACK16,
   1335 		VK_FORMAT_A1R5G5B5_UNORM_PACK16,
   1336 		VK_FORMAT_R8_UNORM,
   1337 		VK_FORMAT_R8_SNORM,
   1338 		VK_FORMAT_R8G8_UNORM,
   1339 		VK_FORMAT_R8G8_SNORM,
   1340 		VK_FORMAT_R8G8B8A8_UNORM,
   1341 		VK_FORMAT_R8G8B8A8_SNORM,
   1342 //		VK_FORMAT_R8G8B8A8_SRGB,
   1343 		VK_FORMAT_B8G8R8A8_UNORM,
   1344 //		VK_FORMAT_B8G8R8A8_SRGB,
   1345 		VK_FORMAT_A8B8G8R8_UNORM_PACK32,
   1346 		VK_FORMAT_A8B8G8R8_SNORM_PACK32,
   1347 //		VK_FORMAT_A8B8G8R8_SRGB_PACK32,
   1348 		VK_FORMAT_A2B10G10R10_UNORM_PACK32,
   1349 		VK_FORMAT_R16_SFLOAT,
   1350 		VK_FORMAT_R16G16_SFLOAT,
   1351 		VK_FORMAT_R16G16B16A16_SFLOAT,
   1352 		VK_FORMAT_R32_SFLOAT,
   1353 		VK_FORMAT_R32G32_SFLOAT,
   1354 		VK_FORMAT_R32G32B32A32_SFLOAT,
   1355 //		VK_FORMAT_B10G11R11_UFLOAT_PACK32,
   1356 //		VK_FORMAT_E5B9G9R9_UFLOAT_PACK32
   1357 	};
   1358 
   1359 	const IVec3 size(32, 32, 1);
   1360 
   1361 	for (deUint32 formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); ++formatNdx)
   1362 	{
   1363 		const std::string prefix = de::toLower(std::string(getFormatName(formats[formatNdx])).substr(10));
   1364 
   1365 		Texture2DGradientTestCase* testCaseNearest =
   1366 			new Texture2DGradientTestCase(
   1367 				testCtx,
   1368 			    (prefix + "_nearest").c_str(),
   1369 				"...",
   1370 				mapVkFormat(formats[formatNdx]),
   1371 				size,
   1372 				VK_FILTER_NEAREST,
   1373 				VK_FILTER_NEAREST,
   1374 				VK_SAMPLER_MIPMAP_MODE_NEAREST,
   1375 				VK_SAMPLER_ADDRESS_MODE_REPEAT,
   1376 				false);
   1377 
   1378 		tests->addChild(testCaseNearest);
   1379 
   1380 	    Texture2DGradientTestCase* testCaseLinear =
   1381 			new Texture2DGradientTestCase(
   1382 				testCtx,
   1383 			    (prefix + "_linear").c_str(),
   1384 				"...",
   1385 				mapVkFormat(formats[formatNdx]),
   1386 				size,
   1387 				VK_FILTER_LINEAR,
   1388 				VK_FILTER_LINEAR,
   1389 				VK_SAMPLER_MIPMAP_MODE_LINEAR,
   1390 				VK_SAMPLER_ADDRESS_MODE_REPEAT,
   1391 				false);
   1392 
   1393 		tests->addChild(testCaseLinear);
   1394 	}
   1395 
   1396 	return tests.release();
   1397 }
   1398 
   1399 TestCaseGroup* create2DDerivTests (TestContext& testCtx)
   1400 {
   1401 	de::MovePtr<TestCaseGroup> tests(
   1402 		new TestCaseGroup(testCtx, "derivatives", "Explicit derivative tests"));
   1403 
   1404 	const VkFormat				format		 = VK_FORMAT_R8G8B8A8_UNORM;
   1405 	const VkSamplerAddressMode	wrappingMode = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
   1406 	const IVec3					size		 = IVec3(16, 16, 1);
   1407 
   1408 	const VkFilter filters[2] =
   1409 	{
   1410 		VK_FILTER_NEAREST,
   1411 		VK_FILTER_LINEAR
   1412 	};
   1413 
   1414 	const VkSamplerMipmapMode mipmapFilters[2] =
   1415 	{
   1416 		VK_SAMPLER_MIPMAP_MODE_NEAREST,
   1417 		VK_SAMPLER_MIPMAP_MODE_LINEAR,
   1418 	};
   1419 
   1420 	for (int magFilterNdx = 0; magFilterNdx < DE_LENGTH_OF_ARRAY(filters); ++magFilterNdx)
   1421 	{
   1422 		for (int minFilterNdx = 0; minFilterNdx < DE_LENGTH_OF_ARRAY(filters); ++minFilterNdx)
   1423 		{
   1424 			for (int mipmapFilterNdx = 0; mipmapFilterNdx < DE_LENGTH_OF_ARRAY(mipmapFilters); ++mipmapFilterNdx)
   1425 			{
   1426 				std::ostringstream caseName;
   1427 
   1428 				switch (filters[magFilterNdx])
   1429 				{
   1430 					case VK_FILTER_NEAREST:
   1431 						caseName << "nearest";
   1432 						break;
   1433 
   1434 					case VK_FILTER_LINEAR:
   1435 						caseName << "linear";
   1436 						break;
   1437 
   1438 					default:
   1439 						break;
   1440 				}
   1441 
   1442 				switch (filters[minFilterNdx])
   1443 				{
   1444 					case VK_FILTER_NEAREST:
   1445 						caseName << "_nearest";
   1446 						break;
   1447 
   1448 					case VK_FILTER_LINEAR:
   1449 						caseName << "_linear";
   1450 						break;
   1451 
   1452 					default:
   1453 						break;
   1454 				}
   1455 
   1456 				caseName << "_mipmap";
   1457 
   1458 				switch (mipmapFilters[mipmapFilterNdx])
   1459 				{
   1460 					case VK_SAMPLER_MIPMAP_MODE_NEAREST:
   1461 						caseName << "_nearest";
   1462 						break;
   1463 
   1464 					case VK_SAMPLER_MIPMAP_MODE_LINEAR:
   1465 						caseName << "_linear";
   1466 						break;
   1467 
   1468 					default:
   1469 						break;
   1470 				}
   1471 
   1472 				Texture2DGradientTestCase* testCase =
   1473 					new Texture2DGradientTestCase(
   1474 						testCtx,
   1475 						caseName.str().c_str(),
   1476 						"...",
   1477 						mapVkFormat(format),
   1478 						size,
   1479 						filters[magFilterNdx],
   1480 						filters[minFilterNdx],
   1481 						mipmapFilters[mipmapFilterNdx],
   1482 						wrappingMode,
   1483 						true);
   1484 
   1485 				tests->addChild(testCase);
   1486 			}
   1487 		}
   1488 	}
   1489 
   1490 	return tests.release();
   1491 }
   1492 
   1493 TestCaseGroup* create2DSizeTests (TestContext& testCtx)
   1494 {
   1495 	de::MovePtr<TestCaseGroup> tests(
   1496 		new TestCaseGroup(testCtx, "sizes", "Various size and filtering combinations"));
   1497 
   1498 	const VkFilter filters[2] =
   1499 	{
   1500 		VK_FILTER_NEAREST,
   1501 		VK_FILTER_LINEAR
   1502 	};
   1503 
   1504 	const VkSamplerMipmapMode mipmapFilters[2] =
   1505 	{
   1506 		VK_SAMPLER_MIPMAP_MODE_NEAREST,
   1507 		VK_SAMPLER_MIPMAP_MODE_LINEAR
   1508 	};
   1509 
   1510 	const VkSamplerAddressMode wrappingModes[2] =
   1511 	{
   1512 		VK_SAMPLER_ADDRESS_MODE_REPEAT,
   1513 		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE
   1514 	};
   1515 
   1516 	const IVec3 sizes[] =
   1517 	{
   1518 		IVec3(2, 2, 1),
   1519 		IVec3(2, 3, 1),
   1520 		IVec3(3, 7, 1),
   1521 		IVec3(4, 8, 1),
   1522 		IVec3(31, 55, 1),
   1523 		IVec3(32, 32, 1),
   1524 		IVec3(32, 64, 1),
   1525 		IVec3(57, 35, 1),
   1526 		IVec3(128, 128, 1)
   1527 	};
   1528 
   1529 
   1530 	for (deUint32 sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes); ++sizeNdx)
   1531 	{
   1532 		for (deUint32 magFilterNdx = 0; magFilterNdx < 2; ++magFilterNdx)
   1533 		{
   1534 			for (deUint32 minFilterNdx = 0; minFilterNdx < 2; ++minFilterNdx)
   1535 			{
   1536 				for (deUint32 mipmapFilterNdx = 0; mipmapFilterNdx < 2; ++mipmapFilterNdx)
   1537 				{
   1538 					for (deUint32 wrappingModeNdx = 0; wrappingModeNdx < 2; ++wrappingModeNdx)
   1539 					{
   1540 						std::ostringstream caseName;
   1541 
   1542 						caseName << sizes[sizeNdx][0] << "x" << sizes[sizeNdx][1];
   1543 
   1544 						switch (filters[magFilterNdx])
   1545 						{
   1546 							case VK_FILTER_NEAREST:
   1547 								caseName << "_nearest";
   1548 								break;
   1549 
   1550 							case VK_FILTER_LINEAR:
   1551 								caseName << "_linear";
   1552 								break;
   1553 
   1554 							default:
   1555 								break;
   1556 						}
   1557 
   1558 						switch (filters[minFilterNdx])
   1559 						{
   1560 							case VK_FILTER_NEAREST:
   1561 								caseName << "_nearest";
   1562 								break;
   1563 
   1564 							case VK_FILTER_LINEAR:
   1565 								caseName << "_linear";
   1566 								break;
   1567 
   1568 							default:
   1569 								break;
   1570 						}
   1571 
   1572 						switch (mipmapFilters[mipmapFilterNdx])
   1573 						{
   1574 							case VK_SAMPLER_MIPMAP_MODE_NEAREST:
   1575 								caseName << "_mipmap_nearest";
   1576 								break;
   1577 
   1578 							case VK_SAMPLER_MIPMAP_MODE_LINEAR:
   1579 								caseName << "_mipmap_linear";
   1580 								break;
   1581 
   1582 							default:
   1583 								break;
   1584 						}
   1585 
   1586 						switch (wrappingModes[wrappingModeNdx])
   1587 						{
   1588 							case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE:
   1589 								caseName << "_clamp";
   1590 								break;
   1591 
   1592 							case VK_SAMPLER_ADDRESS_MODE_REPEAT:
   1593 								caseName << "_repeat";
   1594 								break;
   1595 
   1596 							default:
   1597 								break;
   1598 						}
   1599 
   1600 						Texture2DGradientTestCase* testCase =
   1601 							new Texture2DGradientTestCase(
   1602 								testCtx,
   1603 								caseName.str().c_str(),
   1604 								"...",
   1605 								mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM),
   1606 								sizes[sizeNdx],
   1607 								filters[magFilterNdx],
   1608 								filters[minFilterNdx],
   1609 								mipmapFilters[mipmapFilterNdx],
   1610 								wrappingModes[wrappingModeNdx],
   1611 								false);
   1612 
   1613 						tests->addChild(testCase);
   1614 					}
   1615 				}
   1616 			}
   1617 		}
   1618 	}
   1619 
   1620 	return tests.release();
   1621 }
   1622 
   1623 TestCaseGroup* create2DTests (TestContext& testCtx)
   1624 {
   1625 	de::MovePtr<TestCaseGroup> tests(
   1626 		new TestCaseGroup(testCtx, "2d", "2D Image filtering tests"));
   1627 
   1628 	tests->addChild(create2DSizeTests(testCtx));
   1629 	tests->addChild(create2DFormatTests(testCtx));
   1630 	tests->addChild(create2DDerivTests(testCtx));
   1631 
   1632 	return tests.release();
   1633 }
   1634 
   1635 } // anonymous
   1636 
   1637 TestCaseGroup* createExplicitLodTests (TestContext& testCtx)
   1638 {
   1639 	de::MovePtr<TestCaseGroup> tests(
   1640 		new TestCaseGroup(testCtx, "explicit_lod", "Texture filtering with explicit LOD"));
   1641 
   1642 	tests->addChild(create2DTests(testCtx));
   1643 
   1644 	return tests.release();
   1645 }
   1646 
   1647 } // texture
   1648 } // vkt
   1649