• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2020 The Khronos Group Inc.
6  * Copyright (c) 2020 Google Inc.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Texture conversion tests.
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktTextureConversionTests.hpp"
26 #include "vktAmberTestCase.hpp"
27 #include "vktTestGroupUtil.hpp"
28 #include "vktTextureTestUtil.hpp"
29 #include "vkImageUtil.hpp"
30 #include "tcuTexture.hpp"
31 #include "tcuTextureUtil.hpp"
32 #include "tcuVectorUtil.hpp"
33 #include "deSharedPtr.hpp"
34 
35 #include <memory>
36 
37 namespace vkt
38 {
39 namespace texture
40 {
41 
42 using namespace vk;
43 
44 namespace
45 {
46 
47 using namespace texture::util;
48 using namespace glu::TextureTestUtil;
49 
50 class SnormLinearClampInstance : public TestInstance
51 {
52 public:
53 	struct Params
54 	{
55 		VkFormat	format;
56 		int			width;
57 		int			height;
58 	};
59 							SnormLinearClampInstance	(vkt::Context&					context,
60 														 de::SharedPtr<Params>			params);
61 
62 	virtual tcu::TestStatus	iterate						(void) override;
63 
64 protected:
65 	bool					verifyPixels				(const tcu::PixelBufferAccess&	rendered,
66 														 const tcu::PixelBufferAccess&	reference,
67 														 const ReferenceParams&			samplerParams,
68 														 const std::vector<float>&		texCoords)		const;
69 
70 	static int				lim							(const tcu::TextureFormat&		format,
71 														 int							channelIdx);
72 
73 private:
74 	const de::SharedPtr<Params>	m_params;
75 	const tcu::TextureFormat	m_inFormat;
76 	const VkFormat				m_outFormat;
77 	TestTexture2DSp				m_hwTexture;
78 	tcu::Texture2D				m_swTexture;
79 	TextureRenderer				m_renderer;
80 
81 	const tcu::IVec4			m_a;
82 	const tcu::IVec4			m_b;
83 	const tcu::IVec4			m_c;
84 	const tcu::IVec4			m_d;
85 
86 public:
87 	static const int			textureWidth	= 7;
88 	static const int			textureHeight	= 7;
89 };
90 
SnormLinearClampInstance(vkt::Context & context,de::SharedPtr<Params> params)91 SnormLinearClampInstance::SnormLinearClampInstance (vkt::Context& context, de::SharedPtr<Params> params)
92 	: TestInstance	(context)
93 	, m_params		(params)
94 	, m_inFormat	(mapVkFormat(m_params->format))
95 	, m_outFormat	(VK_FORMAT_R32G32B32A32_SFLOAT)
96 	, m_hwTexture	(TestTexture2DSp(new pipeline::TestTexture2D(m_inFormat, textureWidth, textureHeight)))
97 	, m_swTexture	(m_inFormat, textureWidth, textureHeight, 1)
98 	, m_renderer	(context, VK_SAMPLE_COUNT_1_BIT, m_params->width, m_params->height, 1u, makeComponentMappingRGBA(), VK_IMAGE_TYPE_2D, VK_IMAGE_VIEW_TYPE_2D, m_outFormat)
99 	, m_a			(lim(m_inFormat, 0),	lim(m_inFormat, 1)+2,	lim(m_inFormat, 2),		lim(m_inFormat, 3)+2)
100 	, m_b			(lim(m_inFormat, 0)+2,	lim(m_inFormat, 1),		lim(m_inFormat, 2)+2,	lim(m_inFormat, 3)	)
101 	, m_c			(lim(m_inFormat, 0)+1,	lim(m_inFormat, 1)+1,	lim(m_inFormat, 2)+1,	lim(m_inFormat, 3)+1)
102 	, m_d			(lim(m_inFormat, 0),	lim(m_inFormat, 1),		lim(m_inFormat, 2),		lim(m_inFormat, 3)	)
103 {
104 	tcu::IVec4 data[textureWidth * textureHeight] =
105 	{
106 		m_a, m_b, m_c, m_d, m_c, m_b, m_a,
107 		m_b, m_a, m_c, m_d, m_c, m_a, m_b,
108 		m_c, m_c, m_c, m_d, m_c, m_c, m_c,
109 		m_d, m_d, m_d, m_c, m_d, m_d, m_d,
110 		m_c, m_c, m_c, m_d, m_c, m_c, m_c,
111 		m_b, m_a, m_c, m_d, m_c, m_a, m_b,
112 		m_a, m_b, m_c, m_d, m_c, m_b, m_a,
113 	};
114 
115 	m_swTexture.allocLevel(0);
116 
117 	const tcu::PixelBufferAccess& swAccess	= m_swTexture.getLevel(0);
118 	const tcu::PixelBufferAccess& hwAccess	= m_hwTexture->getLevel(0, 0);
119 
120 	for (int y = 0; y < textureHeight; ++y)
121 	{
122 		for (int x = 0; x < textureWidth; ++x)
123 		{
124 			swAccess.setPixel(data[y*textureWidth+x], x, y);
125 			hwAccess.setPixel(data[y*textureWidth+x], x, y);
126 		}
127 	}
128 
129 	m_renderer.add2DTexture(m_hwTexture, VK_IMAGE_ASPECT_COLOR_BIT, TextureBinding::ImageBackingMode::IMAGE_BACKING_MODE_REGULAR);
130 }
131 
lim(const tcu::TextureFormat & format,int channelIdx)132 int SnormLinearClampInstance::lim (const tcu::TextureFormat& format, int channelIdx)
133 {
134 	auto   channelBits(getTextureFormatBitDepth(format));
135 	return channelBits[channelIdx] ? (-deIntMaxValue32(channelBits[channelIdx])) : (-1);
136 }
137 
verifyPixels(const tcu::PixelBufferAccess & rendered,const tcu::PixelBufferAccess & reference,const ReferenceParams & samplerParams,const std::vector<float> & texCoords) const138 bool SnormLinearClampInstance::verifyPixels	(const tcu::PixelBufferAccess& rendered, const tcu::PixelBufferAccess& reference, const ReferenceParams& samplerParams, const std::vector<float>& texCoords) const
139 {
140 	tcu::LodPrecision				lodPrec;
141 	tcu::LookupPrecision			lookupPrec;
142 
143 	const int						nuc				(getNumUsedChannels(m_inFormat.order));
144 	const int						width			(m_renderer.getRenderWidth());
145 	const int						height			(m_renderer.getRenderHeight());
146 
147 	std::unique_ptr<deUint8[]>		errorMaskData	(new deUint8[width * height * 4 * 4]);
148 	tcu::PixelBufferAccess			errorMask		(mapVkFormat(m_outFormat), width, height, 1, errorMaskData.get());
149 
150 
151 	lodPrec.derivateBits			= 18;
152 	lodPrec.lodBits					= 5;
153 
154 	lookupPrec.uvwBits				= tcu::IVec3(5,5,0);
155 	lookupPrec.coordBits			= tcu::IVec3(20,20,0);
156 	lookupPrec.colorMask			= tcu::BVec4(nuc >= 1, nuc >= 2, nuc >=3, nuc >= 4);
157 	lookupPrec.colorThreshold		= tcu::Vec4(0.9f/float(-lim(m_inFormat, 0)),
158 												0.9f/float(-lim(m_inFormat, 1)),
159 												0.9f/float(-lim(m_inFormat, 2)),
160 												0.9f/float(-lim(m_inFormat, 3)));
161 
162 	const int numFailedPixels		= glu::TextureTestUtil::computeTextureLookupDiff(rendered, reference, errorMask,
163 																					 m_swTexture, texCoords.data(), samplerParams,
164 																					 lookupPrec, lodPrec, /*watchDog*/nullptr);
165 	if (numFailedPixels)
166 	{
167 		const int	numTotalPixels	= width * height;
168 		auto&		log				= m_context.getTestContext().getLog();
169 		const auto	formatName		= de::toLower(std::string(getFormatName(m_params->format)).substr(10));
170 
171 		log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
172 		log << tcu::TestLog::Message << "       " << float(numFailedPixels * 100)/float(numTotalPixels) << "% failed from " << numTotalPixels << " compared pixel count." << tcu::TestLog::EndMessage;
173 		log << tcu::TestLog::Message << "       ColorThreshold: " << lookupPrec.colorThreshold << ", ColorMask: " << lookupPrec.colorMask << tcu::TestLog::EndMessage;
174 
175 		log << tcu::TestLog::ImageSet("VerifyResult", "Verification result");
176 		{
177 			log << tcu::TestLog::Image("Res_"+formatName, "Rendered image", rendered);
178 			log << tcu::TestLog::Image("Ref_"+formatName, "Reference image", reference);
179 			log << tcu::TestLog::Image("Err_"+formatName, "Error mask image", errorMask);
180 		}
181 		log << tcu::TestLog::EndImageSet;
182 	}
183 
184 	int numOutOfRangePixels			= 0;
185 	for (int y = 0; y < height; ++y)
186 	{
187 		for (int x = 0; x < width; ++x)
188 		{
189 			const auto px = rendered.getPixel(x, y);
190 			if (tcu::boolAny(tcu::lessThan(px, tcu::Vec4(-1.0f))) || tcu::boolAny(tcu::greaterThan(px, tcu::Vec4(+1.0f))))
191 				++numOutOfRangePixels;
192 		}
193 	}
194 
195 	if (numOutOfRangePixels)
196 	{
197 		auto&		log					= m_context.getTestContext().getLog();
198 		log << tcu::TestLog::Message << "ERROR: Found " << numOutOfRangePixels << " out of range [-1.0f, +1.0f]." << tcu::TestLog::EndMessage;
199 	}
200 
201 	return (numFailedPixels == 0 && numOutOfRangePixels == 0);
202 }
203 
iterate(void)204 tcu::TestStatus SnormLinearClampInstance::iterate (void)
205 {
206 	std::vector<float>				texCoords		(8);
207 	ReferenceParams					samplerParams	(TEXTURETYPE_2D);
208 	tcu::TextureFormat				resultFormat	(mapVkFormat(m_outFormat));
209 
210 	// Setup renderers.
211 	const int						width			(m_renderer.getRenderWidth());
212 	const int						height			(m_renderer.getRenderHeight());
213 	std::unique_ptr<deUint8[]>		renderedData	(new deUint8[width * height * 4 * 4]);
214 	std::unique_ptr<deUint8[]>		referenceData	(new deUint8[width * height * 4 * 4]);
215 	tcu::PixelBufferAccess			rendered		(resultFormat, width, height, 1, renderedData.get());
216 	tcu::PixelBufferAccess			reference		(resultFormat, width, height, 1, referenceData.get());
217 
218 	// Setup sampler params.
219 	samplerParams.sampler			= util::createSampler(tcu::Sampler::WrapMode::REPEAT_GL, tcu::Sampler::WrapMode::REPEAT_GL,
220 														  tcu::Sampler::FilterMode::LINEAR, tcu::Sampler::FilterMode::LINEAR, true);
221 	samplerParams.samplerType		= SAMPLERTYPE_FLOAT;
222 	samplerParams.lodMode			= LODMODE_EXACT;
223 	samplerParams.colorScale		= tcu::Vec4(1.0f);
224 	samplerParams.colorBias			= tcu::Vec4(0.0f);
225 
226 	// Compute texture coordinates.
227 	computeQuadTexCoord2D(texCoords, tcu::Vec2(0.0f), tcu::Vec2(1.0f));
228 
229 	// Peform online rendering with Vulkan.
230 	m_renderer.renderQuad(rendered, 0, texCoords.data(), samplerParams);
231 
232 	// Perform offline rendering with software renderer.
233 	sampleTexture(reference, m_swTexture, texCoords.data(), samplerParams);
234 
235 	return verifyPixels(rendered, reference, samplerParams, texCoords)
236 			? tcu::TestStatus::pass("")
237 			: tcu::TestStatus::fail("Pixels verification failed");
238 }
239 
240 class SnormLinearClampTestCase : public TestCase
241 {
242 public:
243 	using ParamsSp = de::SharedPtr<SnormLinearClampInstance::Params>;
244 
SnormLinearClampTestCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,ParamsSp params)245 						SnormLinearClampTestCase	(tcu::TestContext&	testCtx,
246 													 const std::string&	name,
247 													 const std::string&	description,
248 													 ParamsSp			params)
249 		: TestCase	(testCtx, name, description)
250 		, m_params	(params)
251 	{
252 	}
253 
createInstance(vkt::Context & context) const254 	vkt::TestInstance*	createInstance				(vkt::Context&		context) const override
255 	{
256 		return new SnormLinearClampInstance(context, m_params);
257 	}
258 
checkSupport(vkt::Context & context) const259 	virtual void		checkSupport				(vkt::Context&		context) const override
260 	{
261 		VkFormatProperties		formatProperties;
262 
263 		context.getInstanceInterface().getPhysicalDeviceFormatProperties(
264 				context.getPhysicalDevice(),
265 				m_params->format,
266 				&formatProperties);
267 
268 		if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT))
269 			TCU_THROW(NotSupportedError, "Linear filtering for this image format is not supported");
270 	}
271 
initPrograms(SourceCollections & programCollection) const272 	virtual void		initPrograms				(SourceCollections&	programCollection) const override
273 	{
274 		initializePrograms(programCollection, glu::Precision::PRECISION_HIGHP, std::vector<Program>({PROGRAM_2D_FLOAT}), DE_NULL, glu::Precision::PRECISION_HIGHP);
275 	}
276 
277 private:
278 	ParamsSp	m_params;
279 };
280 
populateUfloatNegativeValuesTests(tcu::TestCaseGroup * group)281 void populateUfloatNegativeValuesTests (tcu::TestCaseGroup* group)
282 {
283 	tcu::TestContext&	testCtx = group->getTestContext();
284 	VkImageUsageFlags	usage	= VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
285 
286 	VkImageCreateInfo	info	=
287 	{
288 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	// VkStructureType          sType
289 		DE_NULL,								// const void*              pNext
290 		0,										// VkImageCreateFlags       flags
291 		VK_IMAGE_TYPE_2D,						// VkImageType              imageType
292 		VK_FORMAT_B10G11R11_UFLOAT_PACK32,		// VkFormat                 format
293 		{50u, 50u, 1u},							// VkExtent3D               extent
294 		1u,										// uint32_t                 mipLevels
295 		1u,										// uint32_t                 arrayLayers
296 		VK_SAMPLE_COUNT_1_BIT,					// VkSampleCountFlagBits    samples
297 		VK_IMAGE_TILING_OPTIMAL,				// VkImageTiling            tiling
298 		usage,									// VkImageUsageFlags        usage
299 		VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode            sharingMode
300 		0u,										// uint32_t                 queueFamilyIndexCount
301 		DE_NULL,								// const uint32_t*          pQueueFamilyIndices
302 		VK_IMAGE_LAYOUT_UNDEFINED				// VkImageLayout            initialLayout
303 	};
304 
305 	group->addChild(cts_amber::createAmberTestCase(testCtx, "b10g11r11", "", "texture/conversion/ufloat_negative_values", "b10g11r11-ufloat-pack32.amber",
306 					std::vector<std::string>(), std::vector<VkImageCreateInfo>(1, info)));
307 }
308 
populateSnormClampTests(tcu::TestCaseGroup * group)309 void populateSnormClampTests (tcu::TestCaseGroup* group)
310 {
311 	tcu::TestContext&	testCtx	= group->getTestContext();
312 	VkImageUsageFlags	usage	= VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
313 
314 	VkImageCreateInfo	info	=
315 	{
316 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	// VkStructureType          sType
317 		DE_NULL,								// const void*              pNext
318 		0,										// VkImageCreateFlags       flags
319 		VK_IMAGE_TYPE_1D,						// VkImageType              imageType
320 		VK_FORMAT_UNDEFINED,					// VkFormat                 format
321 		{1u, 1u, 1u},							// VkExtent3D               extent
322 		1u,										// uint32_t                 mipLevels
323 		1u,										// uint32_t                 arrayLayers
324 		VK_SAMPLE_COUNT_1_BIT,					// VkSampleCountFlagBits    samples
325 		VK_IMAGE_TILING_OPTIMAL,				// VkImageTiling            tiling
326 		usage,									// VkImageUsageFlags        usage
327 		VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode            sharingMode
328 		0u,										// uint32_t                 queueFamilyIndexCount
329 		DE_NULL,								// const uint32_t*          pQueueFamilyIndices
330 		VK_IMAGE_LAYOUT_UNDEFINED				// VkImageLayout            initialLayout
331 	};
332 
333 	struct TestParams
334 	{
335 		std::string testName;
336 		std::string amberFile;
337 		VkFormat	format;
338 	} params[] =
339 	{
340 		{ "a2b10g10r10_snorm_pack32",	"a2b10g10r10-snorm-pack32.amber",	VK_FORMAT_A2B10G10R10_SNORM_PACK32	},
341 		{ "a2r10g10b10_snorm_pack32",	"a2r10g10b10-snorm-pack32.amber",	VK_FORMAT_A2R10G10B10_SNORM_PACK32	},
342 		{ "a8b8g8r8_snorm_pack32",		"a8b8g8r8-snorm-pack32.amber",		VK_FORMAT_A8B8G8R8_SNORM_PACK32		},
343 		{ "b8g8r8a8_snorm",				"b8g8r8a8-snorm.amber",				VK_FORMAT_B8G8R8A8_SNORM			},
344 		{ "b8g8r8_snorm",				"b8g8r8-snorm.amber",				VK_FORMAT_B8G8R8_SNORM				},
345 		{ "r16g16b16a16_snorm",			"r16g16b16a16-snorm.amber",			VK_FORMAT_R16G16B16A16_SNORM		},
346 		{ "r16g16b16_snorm",			"r16g16b16-snorm.amber",			VK_FORMAT_R16G16B16_SNORM			},
347 		{ "r16g16_snorm",				"r16g16-snorm.amber",				VK_FORMAT_R16G16_SNORM				},
348 		{ "r16_snorm",					"r16-snorm.amber",					VK_FORMAT_R16_SNORM					},
349 		{ "r8g8b8a8_snorm",				"r8g8b8a8-snorm.amber",				VK_FORMAT_R8G8B8A8_SNORM			},
350 		{ "r8g8b8_snorm",				"r8g8b8-snorm.amber",				VK_FORMAT_R8G8B8_SNORM				},
351 		{ "r8g8_snorm",					"r8g8-snorm.amber",					VK_FORMAT_R8G8_SNORM				},
352 		{ "r8_snorm",					"r8-snorm.amber",					VK_FORMAT_R8_SNORM					},
353 	};
354 
355 	for (const auto& param : params)
356 	{
357 		info.format = param.format;
358 		group->addChild(cts_amber::createAmberTestCase(testCtx, param.testName.c_str(), "", "texture/conversion/snorm_clamp", param.amberFile.c_str(),
359 						std::vector<std::string>(), std::vector<VkImageCreateInfo>(1, info)));
360 	}
361 }
362 
populateSnormLinearClampTests(tcu::TestCaseGroup * group)363 void populateSnormLinearClampTests (tcu::TestCaseGroup* group)
364 {
365 	struct TestParams
366 	{
367 		std::string testName;
368 		VkFormat	format;
369 	}
370 	testParams[] =
371 	{
372 		{ "a2b10g10r10_snorm_pack32",	VK_FORMAT_A2B10G10R10_SNORM_PACK32	},
373 		{ "a2r10g10b10_snorm_pack32",	VK_FORMAT_A2R10G10B10_SNORM_PACK32	},
374 		{ "a8b8g8r8_snorm_pack32",		VK_FORMAT_A8B8G8R8_SNORM_PACK32		},
375 		{ "b8g8r8a8_snorm",				VK_FORMAT_B8G8R8A8_SNORM			},
376 		{ "b8g8r8_snorm",				VK_FORMAT_B8G8R8_SNORM				},
377 		{ "r16g16b16a16_snorm",			VK_FORMAT_R16G16B16A16_SNORM		},
378 		{ "r16g16b16_snorm",			VK_FORMAT_R16G16B16_SNORM			},
379 		{ "r16g16_snorm",				VK_FORMAT_R16G16_SNORM				},
380 		{ "r16_snorm",					VK_FORMAT_R16_SNORM					},
381 		{ "r8g8b8a8_snorm",				VK_FORMAT_R8G8B8A8_SNORM			},
382 		{ "r8g8b8_snorm",				VK_FORMAT_R8G8B8_SNORM				},
383 		{ "r8g8_snorm",					VK_FORMAT_R8G8_SNORM				},
384 		{ "r8_snorm",					VK_FORMAT_R8_SNORM					},
385 	};
386 
387 	tcu::TestContext&	testCtx				= group->getTestContext();
388 	int					sizeMultipler		= 20;
389 
390 	for (const auto& testParam : testParams)
391 	{
392 		const int		tw					= SnormLinearClampInstance::textureWidth * sizeMultipler;
393 		const int		th					= SnormLinearClampInstance::textureHeight * sizeMultipler;
394 
395 		de::SharedPtr<SnormLinearClampInstance::Params> params(new SnormLinearClampInstance::Params{testParam.format, tw, th});
396 		group->addChild(new SnormLinearClampTestCase(testCtx, testParam.testName, {}, params));
397 
398 		sizeMultipler += 2;
399 	}
400 }
401 
populateTextureConversionTests(tcu::TestCaseGroup * group)402 void populateTextureConversionTests (tcu::TestCaseGroup* group)
403 {
404 	tcu::TestContext& testCtx = group->getTestContext();
405 
406 	group->addChild(createTestGroup(testCtx, "ufloat_negative_values", "Tests for converting negative floats to unsigned floats", populateUfloatNegativeValuesTests));
407 	group->addChild(createTestGroup(testCtx, "snorm_clamp", "Tests for SNORM corner cases when smallest negative number gets clamped to -1", populateSnormClampTests));
408 	group->addChild(createTestGroup(testCtx, "snorm_clamp_linear", "Tests for SNORM corner cases when negative number gets clamped to -1 after applying linear filtering", populateSnormLinearClampTests));
409 }
410 
411 } // anonymous namespace
412 
createTextureConversionTests(tcu::TestContext & testCtx)413 tcu::TestCaseGroup* createTextureConversionTests (tcu::TestContext& testCtx)
414 {
415 	return createTestGroup(testCtx, "conversion", "Texture conversion tests.", populateTextureConversionTests);
416 }
417 
418 } // texture
419 } // vkt
420