1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2023 The Khronos Group Inc.
6 * Copyright (c) 2023 Valve Corporation.
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 Test for VK_EXT_depth_bias_control.
23 *//*--------------------------------------------------------------------*/
24
25#include "vktRasterizationDepthBiasControlTests.hpp"
26#include "vktTestCase.hpp"
27
28#include "vkImageUtil.hpp"
29#include "vkObjUtil.hpp"
30#include "vkCmdUtil.hpp"
31#include "vkBarrierUtil.hpp"
32
33#include "tcuTextureUtil.hpp"
34#include "tcuImageCompare.hpp"
35
36#include "deUniquePtr.hpp"
37
38#include <sstream>
39#include <vector>
40#include <string>
41#include <cstring>
42
43namespace vkt
44{
45namespace rasterization
46{
47
48namespace
49{
50
51using namespace vk;
52
53using MaybeRepr = tcu::Maybe<VkDepthBiasRepresentationInfoEXT>;
54
55VkDepthBiasRepresentationInfoEXT makeDepthBiasRepresentationInfo (const VkDepthBiasRepresentationEXT repr, const bool exact)
56{
57	VkDepthBiasRepresentationInfoEXT info	= initVulkanStructure();
58	info.depthBiasRepresentation			= repr;
59	info.depthBiasExact						= (exact ? VK_TRUE : VK_FALSE);
60	return info;
61}
62
63std::string getFormatNameShort (const VkFormat format)
64{
65	static const size_t	prefixLen	= std::strlen("VK_FORMAT_");
66	const auto			fullName	= getFormatName(format);
67	const auto			shortName	= de::toLower(std::string(fullName).substr(prefixLen));
68	return shortName;
69}
70
71inline tcu::IVec3			getExtent		(void) { return tcu::IVec3(1, 1, 1); }
72inline VkImageUsageFlags	getColorUsage	(void) { return (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); }
73inline VkImageUsageFlags	getDepthUsage	(void) { return (VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); }
74
75VkImageCreateInfo getImageCreateInfo (const VkFormat format, const VkExtent3D& extent, const VkImageUsageFlags usage)
76{
77	const VkImageCreateInfo imageCreateInfo
78	{
79		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	//	VkStructureType			sType;
80		nullptr,								//	const void*				pNext;
81		0u,										//	VkImageCreateFlags		flags;
82		VK_IMAGE_TYPE_2D,						//	VkImageType				imageType;
83		format,									//	VkFormat				format;
84		extent,									//	VkExtent3D				extent;
85		1u,										//	uint32_t				mipLevels;
86		1u,										//	uint32_t				arrayLayers;
87		VK_SAMPLE_COUNT_1_BIT,					//	VkSampleCountFlagBits	samples;
88		VK_IMAGE_TILING_OPTIMAL,				//	VkImageTiling			tiling;
89		usage,									//	VkImageUsageFlags		usage;
90		VK_SHARING_MODE_EXCLUSIVE,				//	VkSharingMode			sharingMode;
91		0u,										//	uint32_t				queueFamilyIndexCount;
92		nullptr,								//	const uint32_t*			pQueueFamilyIndices;
93		VK_IMAGE_LAYOUT_UNDEFINED,				//	VkImageLayout			initialLayout;
94	};
95
96	return imageCreateInfo;
97}
98
99using MinResolvDiff = std::pair<double, double>; // Min and Max values.
100
101double calcPowerOf2 (int exponent)
102{
103	if (exponent >= 0)
104		return static_cast<double>(1u << exponent);
105	return (1.0 / static_cast<double>(1u << (-exponent)));
106}
107
108tcu::TextureChannelClass getChannelClass (const tcu::TextureFormat& format)
109{
110	const auto generalClass = getTextureChannelClass(format.type);
111	// Fix for VK_FORMAT_X8_D24_UNORM_PACK32
112	return ((generalClass == tcu::TEXTURECHANNELCLASS_LAST) ? tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT : generalClass);
113}
114
115// Returns a couple of numbers with the minimum and maximum values R (minimum resolvable difference) can have according to the spec.
116// As explained there, this depends on the depth attachment format, the depth bias representation parameters and sometimes the
117// geometry itself.
118MinResolvDiff calcMinResolvableDiff (const tcu::TextureFormat& format, const VkDepthBiasRepresentationEXT repr, bool exact, float sampleDepth)
119{
120	MinResolvDiff	r				(0.0, 0.0);
121	const auto		channelClass	= getChannelClass(format);
122
123	switch (repr)
124	{
125	case VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORMAT_EXT:
126		if (channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
127		{
128			// Up to r = 2x2^(-n) where n is bit width.
129			const auto		bitDepth	= getTextureFormatBitDepth(format);
130			const double	minR		= calcPowerOf2(-bitDepth[0]);
131
132			r.first		= minR;
133			r.second	= (exact ? 1.0 : 2.0) * minR;
134		}
135		else if (channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT)
136		{
137			// r = 2^(e-n): e is max exponent in z values, n is mantissa bits.
138			const tcu::Float32	value		(sampleDepth);
139			const int			exponent	= value.exponent() - tcu::Float32::MANTISSA_BITS; // (e-n)
140			const double		minR		= calcPowerOf2(exponent);
141
142			r.first		= minR;
143			r.second	= minR;
144		}
145		else
146			DE_ASSERT(false);
147		break;
148	case VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORCE_UNORM_EXT:
149		{
150			// Up to r = 2x2^(-n), where n is the bit width for fixed-point formats or the number of mantissa bits plus one for
151			// floating-point formats.
152			int n = 0;
153
154			if (channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)
155				n = getTextureFormatBitDepth(format)[0];
156			else if (channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT)
157				n = tcu::Float32::MANTISSA_BITS + 1;
158			else
159				DE_ASSERT(false);
160
161			DE_ASSERT(n > 0); // Make sure the bitwidth is positive.
162			const double minR = calcPowerOf2(-n);
163
164			r.first		= minR;
165			r.second	= (exact ? 1.0 : 2.0) * minR;
166		}
167		break;
168	case VK_DEPTH_BIAS_REPRESENTATION_FLOAT_EXT:
169		// r is always 1.
170		r.first		= 1.0;
171		r.second	= 1.0;
172		break;
173	default:
174		DE_ASSERT(false);
175		break;
176	}
177
178	return r;
179}
180
181// Calculates error threshold when representing values in the given format. This is equivalent to calculating the minimum resolvable
182// difference R according to the format, with exact precision.
183double getDepthErrorThreshold (const tcu::TextureFormat& format, const float sampleDepth)
184{
185	const auto r = calcMinResolvableDiff(format, VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORMAT_EXT, true, sampleDepth);
186	return r.first;
187}
188
189// Which depth bias factor will be used in the tests: focus on depthBiasSlopeFactor or depthBiasConstantFactor.
190enum class UsedFactor	{ SLOPE = 0, CONSTANT = 1 };
191
192// How are we going to set the depth bias parameters: statically or dynamically.
193enum class SetMechanism	{ STATIC = 0, DYNAMIC_1 = 1 /*vkCmdSetDepthBias*/, DYNAMIC_2 = 2 /*vkCmdSetDepthBias2*/};
194
195std::string getMechanismName (const SetMechanism m)
196{
197	switch (m)
198	{
199	case SetMechanism::STATIC:		return "Static";
200	case SetMechanism::DYNAMIC_1:	return "vkCmdSetDepthBias";
201	case SetMechanism::DYNAMIC_2:	return "vkCmdSetDepthBias2";
202	default:						break;
203	}
204
205	DE_ASSERT(false);
206	return "";
207}
208
209struct TestParams
210{
211	const VkFormat		attachmentFormat;	// Depth attachment format.
212	const MaybeRepr		reprInfo;			// Representation info. We omit it for some cases.
213	const SetMechanism	setMechanism;
214	const float			targetBias;			// The bias we aim to get, before clamping. Based on this and R, we can calculate factors.
215	const UsedFactor	usedFactor;
216	const float			constantDepth;		// When using UsedFactor::CONSTANT.
217	const float			depthBiasClamp;
218	const bool			secondaryCmdBuffer;	// Use secondary command buffers or not.
219
220	void log (tcu::TestLog& testLog) const
221	{
222		testLog << tcu::TestLog::Message << "Depth format: " << attachmentFormat << tcu::TestLog::EndMessage;
223
224		if (!reprInfo)
225			testLog << tcu::TestLog::Message << "No VkDepthBiasRepresentationInfoEXT extension structure" << tcu::TestLog::EndMessage;
226		else
227			testLog << tcu::TestLog::Message << *reprInfo << tcu::TestLog::EndMessage;
228
229		testLog
230			<< tcu::TestLog::Message << "Set mechanism: " << getMechanismName(setMechanism) << tcu::TestLog::EndMessage
231			<< tcu::TestLog::Message << "Target bias: " << targetBias << tcu::TestLog::EndMessage
232			<< tcu::TestLog::Message << "Used factor: " << ((usedFactor == UsedFactor::SLOPE) ? "depthBiasSlopeFactor" : "depthBiasConstantFactor") << tcu::TestLog::EndMessage
233			;
234
235		if (usedFactor == UsedFactor::SLOPE)
236			testLog << tcu::TestLog::Message << "Maximum depth slope: " << 1.0f << tcu::TestLog::EndMessage;
237		else
238			testLog << tcu::TestLog::Message << "Constant depth: " << constantDepth << tcu::TestLog::EndMessage;
239
240		testLog << tcu::TestLog::Message << "Depth bias clamp: " << depthBiasClamp << tcu::TestLog::EndMessage;
241	}
242};
243
244class DepthBiasControlInstance : public vkt::TestInstance
245{
246public:
247						DepthBiasControlInstance	(Context& context, const TestParams& params)
248							: vkt::TestInstance	(context)
249							, m_params			(params)
250							{}
251	virtual				~DepthBiasControlInstance	(void) {}
252
253	tcu::TestStatus		iterate						(void) override;
254
255protected:
256	const TestParams	m_params;
257};
258
259class DepthBiasControlCase : public vkt::TestCase
260{
261public:
262	static tcu::Vec4 kOutColor;
263
264					DepthBiasControlCase		(tcu::TestContext& testCtx, const std::string& name, const TestParams& params)
265						: vkt::TestCase	(testCtx, name)
266						, m_params		(params)
267						{}
268	virtual			~DepthBiasControlCase		(void) {}
269
270	void			initPrograms				(vk::SourceCollections& programCollection) const override;
271	TestInstance*	createInstance				(Context& context) const override;
272	void			checkSupport				(Context& context) const override;
273
274protected:
275	const TestParams m_params;
276};
277
278tcu::Vec4 DepthBiasControlCase::kOutColor (0.0f, 0.0f, 1.0f, 1.0f);
279
280void DepthBiasControlCase::checkSupport (Context &context) const
281{
282	context.requireDeviceFunctionality("VK_EXT_depth_bias_control");
283
284	if (m_params.reprInfo)
285	{
286		const auto& reprInfo	= m_params.reprInfo.get();
287		const auto& dbcFeatures	= context.getDepthBiasControlFeaturesEXT();
288
289		if (reprInfo.depthBiasExact && !dbcFeatures.depthBiasExact)
290			TCU_THROW(NotSupportedError, "depthBiasExact not supported");
291
292		if (reprInfo.depthBiasRepresentation == VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORCE_UNORM_EXT
293			&& !dbcFeatures.leastRepresentableValueForceUnormRepresentation)
294		{
295			TCU_THROW(NotSupportedError, "leastRepresentableValueForceUnormRepresentation not supported");
296		}
297
298		if (reprInfo.depthBiasRepresentation == VK_DEPTH_BIAS_REPRESENTATION_FLOAT_EXT && !dbcFeatures.floatRepresentation)
299			TCU_THROW(NotSupportedError, "floatRepresentation not supported");
300	}
301
302	// Check format support.
303	const auto&	vki				= context.getInstanceInterface();
304	const auto	physDev			= context.getPhysicalDevice();
305
306	const auto	imageExtent		= makeExtent3D(getExtent());
307	const auto	imageUsage		= getDepthUsage();
308	const auto	imageCreateInfo	= getImageCreateInfo(m_params.attachmentFormat, imageExtent, imageUsage);
309
310	VkImageFormatProperties formatProperties;
311	const auto formatSupport = vki.getPhysicalDeviceImageFormatProperties(physDev, m_params.attachmentFormat, imageCreateInfo.imageType, imageCreateInfo.tiling, imageUsage, imageCreateInfo.flags, &formatProperties);
312	if (formatSupport == VK_ERROR_FORMAT_NOT_SUPPORTED)
313		TCU_THROW(NotSupportedError, getFormatNameShort(m_params.attachmentFormat) + " not supported");
314}
315
316TestInstance* DepthBiasControlCase::createInstance (Context& context) const
317{
318	return new DepthBiasControlInstance(context, m_params);
319}
320
321void DepthBiasControlCase::initPrograms (vk::SourceCollections &programCollection) const
322{
323	std::ostringstream vert;
324	vert
325		<< "#version 460\n"
326		<< "layout (location=0) in vec4 inPos;\n"
327		<< "void main (void) {\n"
328		<< "    gl_Position = inPos;\n"
329		<< "}\n"
330		;
331	programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
332
333	std::ostringstream frag;
334	frag
335		<< "#version 460\n"
336		<< "layout (location=0) out vec4 outColor;\n"
337		<< "void main (void) {\n"
338		<< "    outColor = vec4" << kOutColor << ";\n"
339		<< "}\n"
340		;
341	programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
342}
343
344tcu::TestStatus DepthBiasControlInstance::iterate (void)
345{
346	const auto			ctx					= m_context.getContextCommonData();
347	const tcu::IVec3	fbExtent			(1, 1, 1);
348	const auto			vkExtent			= makeExtent3D(fbExtent);
349	const auto			colorFormat			= VK_FORMAT_R8G8B8A8_UNORM;
350	const auto			colorUsage			= getColorUsage();
351	const auto			depthFormat			= m_params.attachmentFormat;
352	const auto			depthUsage			= getDepthUsage();
353	const auto			bindPoint			= VK_PIPELINE_BIND_POINT_GRAPHICS;
354	const auto			colorSRR			= makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
355	const auto			depthSRR			= makeImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 1u, 0u, 1u);
356	const auto			colorSRL			= makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
357	const auto			depthSRL			= makeImageSubresourceLayers(VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 0u, 1u);
358	const auto			tcuDepthFormat		= getDepthCopyFormat(depthFormat);
359	const auto			tcuColorFormat		= mapVkFormat(colorFormat);
360	const bool			setStatically		= (m_params.setMechanism == SetMechanism::STATIC);
361	auto&				log					= m_context.getTestContext().getLog();
362
363	const auto			colorCreateInfo		= getImageCreateInfo(colorFormat, vkExtent, colorUsage);
364	const auto			depthCreateInfo		= getImageCreateInfo(depthFormat, vkExtent, depthUsage);
365
366	// Color buffer.
367	ImageWithBuffer colorBuffer(ctx.vkd, ctx.device, ctx.allocator, vkExtent, colorFormat, colorUsage, colorCreateInfo.imageType, colorSRR,
368		colorCreateInfo.arrayLayers, colorCreateInfo.samples, colorCreateInfo.tiling, colorCreateInfo.mipLevels, colorCreateInfo.sharingMode);
369
370	// Depth buffer.
371	ImageWithBuffer depthBuffer(ctx.vkd, ctx.device, ctx.allocator, vkExtent, depthFormat, depthUsage, depthCreateInfo.imageType, depthSRR,
372		depthCreateInfo.arrayLayers, depthCreateInfo.samples, depthCreateInfo.tiling, depthCreateInfo.mipLevels, depthCreateInfo.sharingMode);
373
374	// Vertices and vertex buffer.
375	//
376	// Generate two triangles as a triangle strip covering the whole framebuffer (4 vertices).
377	// +--+
378	// | /|
379	// |/ |
380	// +--+
381	//
382	// WHEN USING THE DEPTH SLOPE FACTOR:
383	// If the framebuffer is 1x1, the delta-X and delta-Y accross the whole framebuffer is 1.
384	// If we make the left-side vertices have a depth of 1.0 and the other 2 have 0.0, delta-Z is 1.
385	// Using both alternative formulas for calculating M, M is 1. This means depthSlopeFactor applies directly.
386	// The depth at the sampling point would be 0.5.
387	//
388	// WHEN USING THE CONSTANT FACTOR:
389	// Generate geometry with a chosen constant depth, so M is zero and depthSlopeFactor never applies.
390	// We will make depthSlopeFactor 0 in any case.
391	// The constant depth value allows us to control the depth value exponent, which affects some calculations.
392	const std::vector<tcu::Vec4> vertices
393	{
394		tcu::Vec4(-1.0f, -1.0f, ((m_params.usedFactor == UsedFactor::CONSTANT) ? m_params.constantDepth : 0.0f), 1.0f),
395		tcu::Vec4(-1.0f,  1.0f, ((m_params.usedFactor == UsedFactor::CONSTANT) ? m_params.constantDepth : 0.0f), 1.0f),
396		tcu::Vec4( 1.0f, -1.0f, ((m_params.usedFactor == UsedFactor::CONSTANT) ? m_params.constantDepth : 1.0f), 1.0f),
397		tcu::Vec4( 1.0f,  1.0f, ((m_params.usedFactor == UsedFactor::CONSTANT) ? m_params.constantDepth : 1.0f), 1.0f),
398	};
399	const float sampleDepth = ((m_params.usedFactor == UsedFactor::CONSTANT) ? m_params.constantDepth : 0.5f);
400
401	const auto			vertexBufferSize	= static_cast<VkDeviceSize>(de::dataSize(vertices));
402	const auto			vertexBufferInfo	= makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
403	BufferWithMemory	vertexBuffer		(ctx.vkd, ctx.device, ctx.allocator, vertexBufferInfo, MemoryRequirement::HostVisible);
404	auto&				vertexAlloc			= vertexBuffer.getAllocation();
405	const auto			vertexBufferOffset	= static_cast<VkDeviceSize>(0);
406
407	deMemcpy(vertexAlloc.getHostPtr(), de::dataOrNull(vertices), de::dataSize(vertices));
408	flushAlloc(ctx.vkd, ctx.device, vertexAlloc);
409
410	// Render pass with depth attachment.
411	const auto renderPass = makeRenderPass(ctx.vkd, ctx.device, colorFormat, depthFormat);
412
413	// Framebuffer.
414	const std::vector<VkImageView> imageViews
415	{
416		colorBuffer.getImageView(),
417		depthBuffer.getImageView(),
418	};
419
420	const auto framebuffer = makeFramebuffer(ctx.vkd, ctx.device, renderPass.get(),
421											 de::sizeU32(imageViews), de::dataOrNull(imageViews),
422											 vkExtent.width, vkExtent.height);
423
424	// Pipeline.
425	const auto&	binaries		= m_context.getBinaryCollection();
426	const auto	vertModule		= createShaderModule(ctx.vkd, ctx.device, binaries.get("vert"));
427	const auto	fragModule		= createShaderModule(ctx.vkd, ctx.device, binaries.get("frag"));
428	const auto	pipelineLayout	= makePipelineLayout(ctx.vkd, ctx.device);
429
430	// Viewports and scissors.
431	const std::vector<VkViewport>	viewports	(1u, makeViewport(fbExtent));
432	const std::vector<VkRect2D>		scissors	(1u, makeRect2D(fbExtent));
433
434	// Calculate depth bias parameters.
435	const auto representation	= (m_params.reprInfo ? m_params.reprInfo->depthBiasRepresentation : VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORMAT_EXT);
436	const bool exactRepr		= (m_params.reprInfo ? m_params.reprInfo->depthBiasExact : false);
437	const auto rValue			= calcMinResolvableDiff(tcuDepthFormat, representation, exactRepr, sampleDepth);
438
439	// Calculate factors based on the target bias and the minimum resolvable difference.
440	const float depthBiasConstantFactor	= ((m_params.usedFactor == UsedFactor::CONSTANT) ? static_cast<float>(static_cast<double>(m_params.targetBias) / rValue.first) : 0.0f);
441	const float depthBiasSlopeFactor	= ((m_params.usedFactor == UsedFactor::SLOPE) ? m_params.targetBias : 0.0f); // Note M is 1.
442	const float depthBiasClamp			= m_params.depthBiasClamp;
443	{
444		// Log some interesting test details, including computed factors.
445		m_params.log(log);
446		log
447			<< tcu::TestLog::Message << "Rmin:                    " << rValue.first << tcu::TestLog::EndMessage
448			<< tcu::TestLog::Message << "Rmax:                    " << rValue.second << tcu::TestLog::EndMessage
449			<< tcu::TestLog::Message << "depthBiasConstantFactor: " << depthBiasConstantFactor << tcu::TestLog::EndMessage
450			<< tcu::TestLog::Message << "depthBiasSlopeFactor:    " << depthBiasSlopeFactor << tcu::TestLog::EndMessage
451			<< tcu::TestLog::Message << "depthBiasClamp:          " << depthBiasClamp << tcu::TestLog::EndMessage
452			;
453	}
454
455	const void* rasterizationPnext = ((setStatically && m_params.reprInfo) ? &m_params.reprInfo.get() : nullptr);
456
457	const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo =
458	{
459		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,	//	VkStructureType							sType;
460		rasterizationPnext,											//	const void*								pNext;
461		0u,															//	VkPipelineRasterizationStateCreateFlags	flags;
462		VK_FALSE,													//	VkBool32								depthClampEnable;
463		VK_FALSE,													//	VkBool32								rasterizerDiscardEnable;
464		VK_POLYGON_MODE_FILL,										//	VkPolygonMode							polygonMode;
465		VK_CULL_MODE_BACK_BIT,										//	VkCullModeFlags							cullMode;
466		VK_FRONT_FACE_COUNTER_CLOCKWISE,							//	VkFrontFace								frontFace;
467		VK_TRUE,													//	VkBool32								depthBiasEnable;
468		(setStatically ? depthBiasConstantFactor : 0.0f),			//	float									depthBiasConstantFactor;
469		(setStatically ? depthBiasClamp : 0.0f),					//	float									depthBiasClamp;
470		(setStatically ? depthBiasSlopeFactor : 0.0f),				//	float									depthBiasSlopeFactor;
471		1.0f,														//	float									lineWidth;
472	};
473
474	const auto stencilOp = makeStencilOpState(VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_ALWAYS, 0xFFu, 0xFFu, 0xFFu);
475
476	const VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo =
477	{
478		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,	//	VkStructureType							sType;
479		nullptr,													//	const void*								pNext;
480		0u,															//	VkPipelineDepthStencilStateCreateFlags	flags;
481		VK_TRUE,													//	VkBool32								depthTestEnable;
482		VK_TRUE,													//	VkBool32								depthWriteEnable;
483		VK_COMPARE_OP_LESS_OR_EQUAL,								//	VkCompareOp								depthCompareOp;
484		VK_FALSE,													//	VkBool32								depthBoundsTestEnable;
485		VK_FALSE,													//	VkBool32								stencilTestEnable;
486		stencilOp,													//	VkStencilOpState						front;
487		stencilOp,													//	VkStencilOpState						back;
488		0.0f,														//	float									minDepthBounds;
489		1.0f,														//	float									maxDepthBounds;
490	};
491
492	std::vector<VkDynamicState> dynamicStates;
493	if (!setStatically)
494		dynamicStates.push_back(VK_DYNAMIC_STATE_DEPTH_BIAS);
495
496	const VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo =
497	{
498		VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,	//	VkStructureType						sType;
499		nullptr,												//	const void*							pNext;
500		0u,														//	VkPipelineDynamicStateCreateFlags	flags;
501		de::sizeU32(dynamicStates),								//	uint32_t							dynamicStateCount;
502		de::dataOrNull(dynamicStates),							//	const VkDynamicState*				pDynamicStates;
503	};
504
505	const auto pipeline = makeGraphicsPipeline(
506		ctx.vkd, ctx.device, pipelineLayout.get(),
507		vertModule.get(), VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE, fragModule.get(),
508		renderPass.get(), viewports, scissors, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 0u, 0u,
509		nullptr, &rasterizationStateCreateInfo, nullptr, &depthStencilStateCreateInfo, nullptr, &dynamicStateCreateInfo);
510
511	// Command buffers.
512	CommandPoolWithBuffer cmd(ctx.vkd, ctx.device, ctx.qfIndex);
513	const auto primaryCmdBuffer = cmd.cmdBuffer.get();
514
515	// Optional secondary command buffer
516	const auto secondaryCmdBufferPtr	= (m_params.secondaryCmdBuffer
517										? allocateCommandBuffer(ctx.vkd, ctx.device, cmd.cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_SECONDARY)
518										: Move<VkCommandBuffer>());
519	const auto secondaryCmdBuffer		= (m_params.secondaryCmdBuffer ? secondaryCmdBufferPtr.get() : VK_NULL_HANDLE);
520	const auto subpassContents			= (m_params.secondaryCmdBuffer ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS : VK_SUBPASS_CONTENTS_INLINE);
521
522	// For render pass contents.
523	const auto rpCmdBuffer = (m_params.secondaryCmdBuffer ? secondaryCmdBuffer : primaryCmdBuffer);
524
525	const std::vector<VkClearValue> clearValues
526	{
527		makeClearValueColor(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f)),
528		makeClearValueDepthStencil(1.0f, 0u),
529	};
530
531	beginCommandBuffer(ctx.vkd, primaryCmdBuffer);
532	if (m_params.secondaryCmdBuffer)
533		beginSecondaryCommandBuffer(ctx.vkd, secondaryCmdBuffer, renderPass.get(), framebuffer.get());
534	beginRenderPass(ctx.vkd, primaryCmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0u), de::sizeU32(clearValues), de::dataOrNull(clearValues), subpassContents);
535
536	// Render pass contents.
537	ctx.vkd.cmdBindVertexBuffers(rpCmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
538	ctx.vkd.cmdBindPipeline(rpCmdBuffer, bindPoint, pipeline.get());
539	if (!setStatically)
540	{
541		if (m_params.setMechanism == SetMechanism::DYNAMIC_1)
542		{
543			DE_ASSERT(!m_params.reprInfo);
544			ctx.vkd.cmdSetDepthBias(rpCmdBuffer, depthBiasConstantFactor, depthBiasClamp, depthBiasSlopeFactor);
545		}
546		else if (m_params.setMechanism == SetMechanism::DYNAMIC_2)
547		{
548			const void* biasInfoPnext = (m_params.reprInfo ? &m_params.reprInfo.get() : nullptr);
549
550			const VkDepthBiasInfoEXT depthBiasInfo =
551			{
552				VK_STRUCTURE_TYPE_DEPTH_BIAS_INFO_EXT,	//	VkStructureType	sType;
553				biasInfoPnext,							//	const void*		pNext;
554				depthBiasConstantFactor,				//	float			depthBiasConstantFactor;
555				depthBiasClamp,							//	float			depthBiasClamp;
556				depthBiasSlopeFactor,					//	float			depthBiasSlopeFactor;
557			};
558			ctx.vkd.cmdSetDepthBias2EXT(rpCmdBuffer, &depthBiasInfo);
559		}
560		else
561			DE_ASSERT(false);
562	}
563	ctx.vkd.cmdDraw(rpCmdBuffer, de::sizeU32(vertices), 1u, 0u, 0u);
564
565	if (m_params.secondaryCmdBuffer)
566	{
567		endCommandBuffer(ctx.vkd, secondaryCmdBuffer);
568		ctx.vkd.cmdExecuteCommands(primaryCmdBuffer, 1u, &secondaryCmdBuffer);
569	}
570	endRenderPass(ctx.vkd, primaryCmdBuffer);
571
572	// Copy color and depth buffers to their verification buffers.
573	{
574		const std::vector<VkImageMemoryBarrier> preTransferBarriers
575		{
576			makeImageMemoryBarrier(
577				VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
578				VK_ACCESS_TRANSFER_READ_BIT,
579				VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
580				VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
581				depthBuffer.getImage(), depthSRR),
582
583			makeImageMemoryBarrier(
584				VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
585				VK_ACCESS_TRANSFER_READ_BIT,
586				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
587				VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
588				colorBuffer.getImage(), colorSRR),
589		};
590
591		const auto preTransferStages = (VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
592		cmdPipelineImageMemoryBarrier(ctx.vkd, primaryCmdBuffer, preTransferStages, VK_PIPELINE_STAGE_TRANSFER_BIT, de::dataOrNull(preTransferBarriers), de::sizeU32(preTransferBarriers));
593
594		const auto depthRegion = makeBufferImageCopy(vkExtent, depthSRL);
595		const auto colorRegion = makeBufferImageCopy(vkExtent, colorSRL);
596
597		ctx.vkd.cmdCopyImageToBuffer(primaryCmdBuffer, depthBuffer.getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, depthBuffer.getBuffer(), 1u, &depthRegion);
598		ctx.vkd.cmdCopyImageToBuffer(primaryCmdBuffer, colorBuffer.getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorBuffer.getBuffer(), 1u, &colorRegion);
599
600		const auto transfer2Host = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
601		cmdPipelineMemoryBarrier(ctx.vkd, primaryCmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, &transfer2Host);
602	}
603
604	endCommandBuffer(ctx.vkd, primaryCmdBuffer);
605	submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, primaryCmdBuffer);
606
607	// Invalidate allocations and verify contents.
608	invalidateAlloc(ctx.vkd, ctx.device, depthBuffer.getBufferAllocation());
609	invalidateAlloc(ctx.vkd, ctx.device, colorBuffer.getBufferAllocation());
610
611	// Depth reference.
612	tcu::TextureLevel		depthReferenceLevel		(tcuDepthFormat, fbExtent.x(), fbExtent.y());
613	tcu::PixelBufferAccess	depthReferenceAccess	(depthReferenceLevel.getAccess());
614	const bool				noClamp					= (m_params.depthBiasClamp == 0.0f);
615	const float				clampedBias				= std::min(m_params.targetBias, (noClamp ? m_params.targetBias : m_params.depthBiasClamp));
616	const float				expectedDepth			= sampleDepth + clampedBias; // Must match vertex depth + actual bias.
617	tcu::clearDepth(depthReferenceAccess, expectedDepth);
618
619	// We calculated depth bias constant factors based on the most precise minimum resolvable diff, but the actual resolvable diff
620	// may be bigger in some cases. We take that into account when calculating the error threshold for depth values, and we add the
621	// format precision on top.
622	const double			constantFactorD			= static_cast<double>(depthBiasConstantFactor);
623	const double			constantBiasMin			= constantFactorD * rValue.first;
624	const double			constantBiasMax			= constantFactorD * rValue.second;
625	const double			constantBiasErrorThres	= constantBiasMax - constantBiasMin;
626	const float				depthThreshold			= static_cast<float>(constantBiasErrorThres + getDepthErrorThreshold(tcuDepthFormat, expectedDepth));
627	{
628		log
629			<< tcu::TestLog::Message << "Constant Bias Min:             " << constantBiasMin << tcu::TestLog::EndMessage
630			<< tcu::TestLog::Message << "Constant Bias Max:             " << constantBiasMax << tcu::TestLog::EndMessage
631			<< tcu::TestLog::Message << "Constant Bias Error Threshold: " << constantBiasErrorThres << tcu::TestLog::EndMessage
632			;
633	}
634
635	// Color reference.
636	const tcu::Vec4&	expectedColor	= DepthBiasControlCase::kOutColor;
637	const tcu::Vec4		colorThreshold	(0.0f, 0.0f, 0.0f, 0.0f); // Expect exact result in color.
638
639	// Result pixel buffer accesses.
640	const tcu::ConstPixelBufferAccess depthResultAccess (tcuDepthFormat, fbExtent, depthBuffer.getBufferAllocation().getHostPtr());
641	const tcu::ConstPixelBufferAccess colorResultAccess (tcuColorFormat, fbExtent, colorBuffer.getBufferAllocation().getHostPtr());
642
643	bool fail = false;
644
645	if (!tcu::dsThresholdCompare(log, "DepthResult", "", depthReferenceAccess, depthResultAccess, depthThreshold, tcu::COMPARE_LOG_ON_ERROR))
646	{
647		log << tcu::TestLog::Message << "Depth buffer failed: expected " << expectedDepth << " (threshold " << depthThreshold
648			<< ") and found " << depthResultAccess.getPixDepth(0, 0) << tcu::TestLog::EndMessage;
649		fail = true;
650	}
651
652	if (!tcu::floatThresholdCompare(log, "ColorResult", "", expectedColor, colorResultAccess, colorThreshold, tcu::COMPARE_LOG_ON_ERROR))
653	{
654		log << tcu::TestLog::Message << "Color buffer failed: expected " << expectedColor << " (threshold " << colorThreshold
655			<< ") and found " << depthResultAccess.getPixel(0, 0) << tcu::TestLog::EndMessage;
656		fail = true;
657	}
658
659	if (fail)
660		return tcu::TestStatus::fail("Failed -- check log for details");
661	return tcu::TestStatus::pass("Pass");
662}
663
664} // anonymous namespace
665
666tcu::TestCaseGroup* createDepthBiasControlTests (tcu::TestContext& testCtx)
667{
668	using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
669
670	const std::vector<VkFormat> attachmentFormats
671	{
672		VK_FORMAT_D16_UNORM,
673		VK_FORMAT_X8_D24_UNORM_PACK32,
674		VK_FORMAT_D32_SFLOAT,
675		VK_FORMAT_D16_UNORM_S8_UINT,
676		VK_FORMAT_D24_UNORM_S8_UINT,
677		VK_FORMAT_D32_SFLOAT_S8_UINT,
678	};
679
680	const struct
681	{
682		const UsedFactor	usedFactor;
683		const char*			name;
684	} usedFactorCases[] =
685	{
686		{ UsedFactor::SLOPE,	"slope"		},
687		{ UsedFactor::CONSTANT,	"constant"	},
688	};
689
690	const struct
691	{
692		const MaybeRepr	reprInfo;
693		const char*		name;
694	} reprInfoCases[] =
695	{
696		{ tcu::Nothing,																										"no_repr_info"			},
697		{ makeDepthBiasRepresentationInfo(VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORMAT_EXT, false),		"format_inexact"			},
698		{ makeDepthBiasRepresentationInfo(VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORMAT_EXT, true),			"format_exact"		},
699		{ makeDepthBiasRepresentationInfo(VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORCE_UNORM_EXT, false),	"force_unorm_inexact"		},
700		{ makeDepthBiasRepresentationInfo(VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORCE_UNORM_EXT, true),	"force_unorm_exact"	},
701		{ makeDepthBiasRepresentationInfo(VK_DEPTH_BIAS_REPRESENTATION_FLOAT_EXT, false),									"float_inexact"			},
702		{ makeDepthBiasRepresentationInfo(VK_DEPTH_BIAS_REPRESENTATION_FLOAT_EXT, true),									"float_exact"			},
703	};
704
705	struct ConstantDepthCase
706	{
707		const float constantDepth;
708		const char* name;
709	};
710	using ConstantDepthCaseVec = std::vector<ConstantDepthCase>;
711
712	const ConstantDepthCaseVec constantDepthSlopeCases // For these subcases, the constant depth is not used.
713	{
714		{ 0.0f,				"slope_depth_1_0"				},
715	};
716	const ConstantDepthCaseVec constantDepthConstantCases
717	{
718		{ 0.25f,			"constant_depth_0_25"			},
719		{ 0.3125f,			"constant_depth_0_3125"			},
720		{ 0.489742279053f,	"constant_depth_close_to_0_5"	},
721		{ 0.625f,			"constant_depth_0_625"			},
722		{ 0.125f,			"constant_depth_0_125"			},
723	};
724
725	const struct
726	{
727		const float targetBias;
728		const char* name;
729	} targetBiasCases[] =
730	{
731		{ 0.0625f,	"target_bias_0_0625"	},
732		{ 0.125f,	"target_bias_0_125"		},
733		{ 0.25f,	"target_bias_0_25"		},
734	};
735
736	const struct
737	{
738		const SetMechanism		setMechanism;
739		const char*				name;
740	} setMechanismCases[] =
741	{
742		{ SetMechanism::STATIC,		"static"			},
743		{ SetMechanism::DYNAMIC_1,	"dynamic_set_1"		},
744		{ SetMechanism::DYNAMIC_2,	"dynamic_set_2"		},
745	};
746
747	enum class ClampCase { ZERO = 0, LARGE = 1, SMALL = 2 };
748	const struct
749	{
750		const ClampCase		clampCase;
751		const char*			suffix;
752	} clampValueCases[] =
753	{
754		{	ClampCase::ZERO,		"_no_clamp"				},
755		{	ClampCase::LARGE,		"_no_effective_clamp"	},
756		{	ClampCase::SMALL,		"_clamp_to_half"		},
757	};
758
759	const struct
760	{
761		const bool	secondaryCmdBuffer;
762		const char*	suffix;
763	} secondaryCmdBufferCases[] =
764	{
765		{ false,	""						},
766		{ true,		"_secondary_cmd_buffer"	},
767	};
768
769	GroupPtr dbcGroup (new tcu::TestCaseGroup(testCtx, "depth_bias_control"));
770
771	for (const auto& format : attachmentFormats)
772	{
773		const auto formatName = getFormatNameShort(format);
774
775		GroupPtr formatGroup (new tcu::TestCaseGroup(testCtx, formatName.c_str()));
776
777		for (const auto& reprInfoCase : reprInfoCases)
778		{
779			GroupPtr reprInfoGroup (new tcu::TestCaseGroup(testCtx, reprInfoCase.name));
780
781			for (const auto& usedFactorCase : usedFactorCases)
782			{
783				GroupPtr usedFactorGroup (new tcu::TestCaseGroup(testCtx, usedFactorCase.name));
784
785				const bool constantFactor = (usedFactorCase.usedFactor == UsedFactor::CONSTANT);
786				const ConstantDepthCaseVec& constantDepthCases = (constantFactor ? constantDepthConstantCases : constantDepthSlopeCases);
787
788				for (const auto& constantDepthCase : constantDepthCases)
789				{
790					GroupPtr constantDepthGroup (new tcu::TestCaseGroup(testCtx, constantDepthCase.name));
791
792					for (const auto& targetBiasCase : targetBiasCases)
793					{
794						GroupPtr targetBiasGroup (new tcu::TestCaseGroup(testCtx, targetBiasCase.name));
795
796						for (const auto& setMechanismCase : setMechanismCases)
797						{
798							// We cannot use the representation info with vkCmdSetDepthBias.
799							if (setMechanismCase.setMechanism == SetMechanism::DYNAMIC_1 && static_cast<bool>(reprInfoCase.reprInfo))
800								continue;
801
802							for (const auto& clampValueCase : clampValueCases)
803							{
804								float depthBiasClamp = 0.0f;
805								switch (clampValueCase.clampCase)
806								{
807								case ClampCase::ZERO:			depthBiasClamp = 0.0f;									break;
808								case ClampCase::LARGE:			depthBiasClamp = targetBiasCase.targetBias * 2.0f;		break;
809								case ClampCase::SMALL:			depthBiasClamp = targetBiasCase.targetBias * 0.5f;		break;
810								default:						DE_ASSERT(false);										break;
811								}
812
813								for (const auto& secondaryCmdBufferCase : secondaryCmdBufferCases)
814								{
815									// Some selected combinations will use secondary command buffers. Avoid applying this to all
816									// combinations to keep the number of cases low.
817									if (secondaryCmdBufferCase.secondaryCmdBuffer)
818									{
819										if (usedFactorCase.usedFactor != UsedFactor::CONSTANT)
820											continue;
821
822										if (setMechanismCase.setMechanism == SetMechanism::DYNAMIC_1)
823											continue;
824
825										if (clampValueCase.clampCase != ClampCase::ZERO)
826											continue;
827
828										if (!static_cast<bool>(reprInfoCase.reprInfo))
829											continue;
830									}
831
832									const TestParams params
833									{
834										format,
835										reprInfoCase.reprInfo,
836										setMechanismCase.setMechanism,
837										targetBiasCase.targetBias,
838										usedFactorCase.usedFactor,
839										constantDepthCase.constantDepth,
840										depthBiasClamp,
841										secondaryCmdBufferCase.secondaryCmdBuffer,
842									};
843									const std::string testName = std::string(setMechanismCase.name) + clampValueCase.suffix + secondaryCmdBufferCase.suffix;
844									targetBiasGroup->addChild(new DepthBiasControlCase(testCtx, testName, params));
845								}
846							}
847						}
848
849						constantDepthGroup->addChild(targetBiasGroup.release());
850					}
851
852					usedFactorGroup->addChild(constantDepthGroup.release());
853				}
854
855				reprInfoGroup->addChild(usedFactorGroup.release());
856			}
857
858			formatGroup->addChild(reprInfoGroup.release());
859		}
860
861		dbcGroup->addChild(formatGroup.release());
862	}
863
864	return dbcGroup.release();
865}
866
867} // rasterization
868} // vkt
869