• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 The Khronos Group Inc.
6  * Copyright (c) 2017 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 Inverted depth ranges tests.
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktDrawInvertedDepthRangesTests.hpp"
26 #include "vktDrawCreateInfoUtil.hpp"
27 #include "vktDrawImageObjectUtil.hpp"
28 #include "vktDrawBufferObjectUtil.hpp"
29 #include "vktTestGroupUtil.hpp"
30 #include "vktTestCaseUtil.hpp"
31 
32 #include "vkPrograms.hpp"
33 #include "vkTypeUtil.hpp"
34 #include "vkImageUtil.hpp"
35 #include "vkCmdUtil.hpp"
36 
37 #include "tcuVector.hpp"
38 #include "tcuTextureUtil.hpp"
39 #include "tcuImageCompare.hpp"
40 #include "tcuTestLog.hpp"
41 
42 #include "deSharedPtr.hpp"
43 
44 #include <utility>
45 #include <array>
46 #include <vector>
47 #include <iterator>
48 
49 namespace vkt
50 {
51 namespace Draw
52 {
53 namespace
54 {
55 using namespace vk;
56 using tcu::Vec4;
57 using de::SharedPtr;
58 using de::MovePtr;
59 
60 struct TestParams
61 {
62 	float		minDepth;
63 	float		maxDepth;
64 	VkBool32	depthClampEnable;
65 	VkBool32	depthBiasEnable;
66 	float		depthBiasClamp;
67 	VkBool32	useDynamicRendering;
68 };
69 
70 constexpr deUint32			kImageDim		= 256u;
71 const VkExtent3D			kImageExtent	= makeExtent3D(kImageDim, kImageDim, 1u);
72 const Vec4					kClearColor		(0.0f, 0.0f, 0.0f, 1.0f);
73 constexpr float				kClearDepth		= 1.0f;
74 constexpr int				kClearStencil	= 0;
75 constexpr int				kMaskedStencil	= 1;
76 constexpr float				kDepthEpsilon	= 0.00025f;	// Used to decide if a calculated depth passes the depth test.
77 constexpr float				kDepthThreshold	= 0.0025f;	// Used when checking depth buffer values. Less than depth delta in each pixel (~= 1.4/205).
78 constexpr float				kMargin			= 0.2f;		// Space between triangle and image border. See kVertices.
79 constexpr float				kDiagonalMargin	= 0.00125f; // Makes sure the image diagonal falls inside the triangle. See kVertices.
80 const Vec4					kVertexColor	(0.0f, 0.5f, 0.5f, 1.0f); // Note: the first component will vary.
81 
82 // Maximum depth slope is constant for triangle and the value here is true only for triangle used it this tests.
83 constexpr float				kMaxDepthSlope = 1.4f / 205;
84 
85 const std::array<Vec4, 3u>	kVertices		=
86 {{
87 	Vec4(-1.0f + kMargin,                   -1.0f + kMargin,                    -0.2f, 1.0f),	//  0-----2
88 	Vec4(-1.0f + kMargin,                    1.0f - kMargin + kDiagonalMargin,   0.0f, 1.0f),	//   |  /
89 	Vec4( 1.0f - kMargin + kDiagonalMargin, -1.0f + kMargin,                     1.2f, 1.0f),	//  1|/
90 }};
91 
92 
93 class InvertedDepthRangesTestInstance : public TestInstance
94 {
95 public:
96 	enum class ReferenceImageType
97 	{
98 		COLOR = 0,
99 		DEPTH,
100 	};
101 
102 	using ColorAndDepth = std::pair<tcu::ConstPixelBufferAccess, tcu::ConstPixelBufferAccess>;
103 
104 												InvertedDepthRangesTestInstance	(Context& context, const TestParams& params);
105 	tcu::TestStatus								iterate							(void);
106 	ColorAndDepth								draw							(const VkViewport viewport);
107 	MovePtr<tcu::TextureLevel>					generateReferenceImage			(ReferenceImageType refType) const;
108 
109 private:
110 	const TestParams				m_params;
111 	const VkFormat					m_colorAttachmentFormat;
112 	const VkFormat					m_depthAttachmentFormat;
113 	SharedPtr<Image>				m_colorTargetImage;
114 	Move<VkImageView>				m_colorTargetView;
115 	SharedPtr<Image>				m_depthTargetImage;
116 	Move<VkImageView>				m_depthTargetView;
117 	SharedPtr<Buffer>				m_vertexBuffer;
118 	Move<VkRenderPass>				m_renderPass;
119 	Move<VkFramebuffer>				m_framebuffer;
120 	Move<VkPipelineLayout>			m_pipelineLayout;
121 	Move<VkPipeline>				m_pipeline;
122 };
123 
InvertedDepthRangesTestInstance(Context & context,const TestParams & params)124 InvertedDepthRangesTestInstance::InvertedDepthRangesTestInstance (Context& context, const TestParams& params)
125 	: TestInstance				(context)
126 	, m_params					(params)
127 	, m_colorAttachmentFormat	(VK_FORMAT_R8G8B8A8_UNORM)
128 	, m_depthAttachmentFormat	(VK_FORMAT_D16_UNORM)
129 {
130 	const DeviceInterface&	vk		= m_context.getDeviceInterface();
131 	const VkDevice			device	= m_context.getDevice();
132 	auto&					alloc	= m_context.getDefaultAllocator();
133 	auto					qIndex	= m_context.getUniversalQueueFamilyIndex();
134 
135 	// Vertex data
136 	{
137 		const auto dataSize = static_cast<VkDeviceSize>(kVertices.size() * sizeof(decltype(kVertices)::value_type));
138 		m_vertexBuffer = Buffer::createAndAlloc(vk, device, BufferCreateInfo(dataSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
139 												alloc, MemoryRequirement::HostVisible);
140 
141 		deMemcpy(m_vertexBuffer->getBoundMemory().getHostPtr(), kVertices.data(), static_cast<size_t>(dataSize));
142 		flushMappedMemoryRange(vk, device, m_vertexBuffer->getBoundMemory().getMemory(), m_vertexBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
143 	}
144 
145 	const VkImageUsageFlags	targetImageUsageFlags	= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
146 	const VkImageUsageFlags depthTargeUsageFlags	= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
147 
148 	const ImageCreateInfo	targetImageCreateInfo(
149 		VK_IMAGE_TYPE_2D,						// imageType,
150 		m_colorAttachmentFormat,				// format,
151 		kImageExtent,							// extent,
152 		1u,										// mipLevels,
153 		1u,										// arrayLayers,
154 		VK_SAMPLE_COUNT_1_BIT,					// samples,
155 		VK_IMAGE_TILING_OPTIMAL,				// tiling,
156 		targetImageUsageFlags);					// usage,
157 
158 	m_colorTargetImage = Image::createAndAlloc(vk, device, targetImageCreateInfo, alloc, qIndex);
159 
160 	const ImageCreateInfo	depthTargetImageCreateInfo(
161 		VK_IMAGE_TYPE_2D,						// imageType,
162 		m_depthAttachmentFormat,				// format,
163 		kImageExtent,							// extent,
164 		1u,										// mipLevels,
165 		1u,										// arrayLayers,
166 		VK_SAMPLE_COUNT_1_BIT,					// samples,
167 		VK_IMAGE_TILING_OPTIMAL,				// tiling,
168 		depthTargeUsageFlags);					// usage,
169 
170 	m_depthTargetImage = Image::createAndAlloc(vk, device, depthTargetImageCreateInfo, alloc, qIndex);
171 
172 	const ImageViewCreateInfo colorTargetViewInfo(m_colorTargetImage->object(), VK_IMAGE_VIEW_TYPE_2D, m_colorAttachmentFormat);
173 	m_colorTargetView = createImageView(vk, device, &colorTargetViewInfo);
174 
175 	const ImageViewCreateInfo depthTargetViewInfo(m_depthTargetImage->object(), VK_IMAGE_VIEW_TYPE_2D, m_depthAttachmentFormat);
176 	m_depthTargetView = createImageView(vk, device, &depthTargetViewInfo);
177 
178 	// Render pass and framebuffer
179 	if (!m_params.useDynamicRendering)
180 	{
181 		RenderPassCreateInfo	renderPassCreateInfo;
182 		renderPassCreateInfo.addAttachment(AttachmentDescription(
183 			m_colorAttachmentFormat,				// format
184 			VK_SAMPLE_COUNT_1_BIT,					// samples
185 			VK_ATTACHMENT_LOAD_OP_LOAD,				// loadOp
186 			VK_ATTACHMENT_STORE_OP_STORE,			// storeOp
187 			VK_ATTACHMENT_LOAD_OP_DONT_CARE,		// stencilLoadOp
188 			VK_ATTACHMENT_STORE_OP_DONT_CARE,		// stencilStoreOp
189 			VK_IMAGE_LAYOUT_GENERAL,				// initialLayout
190 			VK_IMAGE_LAYOUT_GENERAL));				// finalLayout
191 
192 		renderPassCreateInfo.addAttachment(AttachmentDescription(
193 			m_depthAttachmentFormat,				// format
194 			VK_SAMPLE_COUNT_1_BIT,					// samples
195 			VK_ATTACHMENT_LOAD_OP_LOAD,				// loadOp
196 			VK_ATTACHMENT_STORE_OP_STORE,			// storeOp
197 			VK_ATTACHMENT_LOAD_OP_DONT_CARE,		// stencilLoadOp
198 			VK_ATTACHMENT_STORE_OP_DONT_CARE,		// stencilStoreOp
199 			VK_IMAGE_LAYOUT_GENERAL,				// initialLayout
200 			VK_IMAGE_LAYOUT_GENERAL));				// finalLayout
201 
202 		const VkAttachmentReference colorAttachmentReference =
203 		{
204 			0u,
205 			VK_IMAGE_LAYOUT_GENERAL
206 		};
207 
208 		const VkAttachmentReference depthAttachmentReference =
209 		{
210 			1u,
211 			VK_IMAGE_LAYOUT_GENERAL
212 		};
213 
214 		renderPassCreateInfo.addSubpass(SubpassDescription(
215 			VK_PIPELINE_BIND_POINT_GRAPHICS,		// pipelineBindPoint
216 			(VkSubpassDescriptionFlags)0,			// flags
217 			0u,										// inputAttachmentCount
218 			DE_NULL,								// inputAttachments
219 			1u,										// colorAttachmentCount
220 			&colorAttachmentReference,				// colorAttachments
221 			DE_NULL,								// resolveAttachments
222 			depthAttachmentReference,				// depthStencilAttachment
223 			0u,										// preserveAttachmentCount
224 			DE_NULL));								// preserveAttachments
225 
226 		m_renderPass = createRenderPass(vk, device, &renderPassCreateInfo);
227 
228 		std::vector<VkImageView> fbAttachments
229 		{
230 			*m_colorTargetView,
231 			*m_depthTargetView
232 		};
233 
234 		const FramebufferCreateInfo	framebufferCreateInfo(*m_renderPass, fbAttachments, kImageExtent.width, kImageExtent.height, 1u);
235 		m_framebuffer = createFramebuffer(vk, device, &framebufferCreateInfo);
236 	}
237 
238 	// Vertex input
239 
240 	const VkVertexInputBindingDescription		vertexInputBindingDescription =
241 	{
242 		0u,										// uint32_t             binding;
243 		sizeof(Vec4),							// uint32_t             stride;
244 		VK_VERTEX_INPUT_RATE_VERTEX,			// VkVertexInputRate    inputRate;
245 	};
246 
247 	const VkVertexInputAttributeDescription		vertexInputAttributeDescription =
248 	{
249 		0u,										// uint32_t    location;
250 		0u,										// uint32_t    binding;
251 		VK_FORMAT_R32G32B32A32_SFLOAT,			// VkFormat    format;
252 		0u										// uint32_t    offset;
253 	};
254 
255 	const PipelineCreateInfo::VertexInputState	vertexInputState = PipelineCreateInfo::VertexInputState(1, &vertexInputBindingDescription,
256 																										1, &vertexInputAttributeDescription);
257 
258 	// Graphics pipeline
259 
260 	const auto scissor = makeRect2D(kImageExtent);
261 
262 	std::vector<VkDynamicState>		dynamicStates;
263 	dynamicStates.push_back(VK_DYNAMIC_STATE_VIEWPORT);
264 
265 	const Unique<VkShaderModule>	vertexModule	(createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0));
266 	const Unique<VkShaderModule>	fragmentModule	(createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0));
267 
268 	const PipelineLayoutCreateInfo	pipelineLayoutCreateInfo;
269 	m_pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
270 
271 	const PipelineCreateInfo::ColorBlendState::Attachment colorBlendAttachmentState;
272 
273 	PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, (VkPipelineCreateFlags)0);
274 	pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vertexModule,   "main", VK_SHADER_STAGE_VERTEX_BIT));
275 	pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fragmentModule, "main", VK_SHADER_STAGE_FRAGMENT_BIT));
276 	pipelineCreateInfo.addState (PipelineCreateInfo::VertexInputState	(vertexInputState));
277 	pipelineCreateInfo.addState (PipelineCreateInfo::InputAssemblerState(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
278 	pipelineCreateInfo.addState (PipelineCreateInfo::ColorBlendState	(1, &colorBlendAttachmentState));
279 	pipelineCreateInfo.addState (PipelineCreateInfo::ViewportState		(1, std::vector<VkViewport>(), std::vector<VkRect2D>(1, scissor)));
280 	pipelineCreateInfo.addState (PipelineCreateInfo::DepthStencilState	(true, true));
281 	pipelineCreateInfo.addState (PipelineCreateInfo::RasterizerState	(
282 		m_params.depthClampEnable,										// depthClampEnable
283 		VK_FALSE,														// rasterizerDiscardEnable
284 		VK_POLYGON_MODE_FILL,											// polygonMode
285 		VK_CULL_MODE_NONE,												// cullMode
286 		VK_FRONT_FACE_CLOCKWISE,										// frontFace
287 		m_params.depthBiasEnable,										// depthBiasEnable
288 		0.0f,															// depthBiasConstantFactor
289 		m_params.depthBiasEnable ? m_params.depthBiasClamp : 0.0f,		// depthBiasClamp
290 		m_params.depthBiasEnable ? 1.0f : 0.0f,							// depthBiasSlopeFactor
291 		1.0f));															// lineWidth
292 	pipelineCreateInfo.addState (PipelineCreateInfo::MultiSampleState	());
293 	pipelineCreateInfo.addState (PipelineCreateInfo::DynamicState		(dynamicStates));
294 
295 	VkPipelineRenderingCreateInfoKHR renderingCreateInfo
296 	{
297 		VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
298 		DE_NULL,
299 		0u,
300 		1u,
301 		&m_colorAttachmentFormat,
302 		m_depthAttachmentFormat,
303 		m_depthAttachmentFormat
304 	};
305 
306 	if (m_params.useDynamicRendering)
307 		pipelineCreateInfo.pNext = &renderingCreateInfo;
308 
309 	m_pipeline = createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
310 }
311 
draw(const VkViewport viewport)312 InvertedDepthRangesTestInstance::ColorAndDepth InvertedDepthRangesTestInstance::draw (const VkViewport viewport)
313 {
314 	const DeviceInterface&		vk					= m_context.getDeviceInterface();
315 	const VkDevice				device				= m_context.getDevice();
316 	const VkQueue				queue				= m_context.getUniversalQueue();
317 	const deUint32				queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
318 	auto&						alloc				= m_context.getDefaultAllocator();
319 	const VkClearValue			clearColor			= makeClearValueColor(kClearColor);
320 	const VkClearValue			clearDepth			= makeClearValueDepthStencil(kClearDepth, 0u);
321 
322 	// Command buffer
323 
324 	const CmdPoolCreateInfo			cmdPoolCreateInfo	(queueFamilyIndex);
325 	const Unique<VkCommandPool>		cmdPool				(createCommandPool(vk, device, &cmdPoolCreateInfo));
326 	const Unique<VkCommandBuffer>	cmdBuffer			(allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
327 
328 	// Draw
329 
330 	beginCommandBuffer(vk, *cmdBuffer);
331 
332 	vk.cmdSetViewport(*cmdBuffer, 0u, 1u, &viewport);
333 
334 	{
335 		const ImageSubresourceRange		subresourceRange		(VK_IMAGE_ASPECT_COLOR_BIT);
336 		const ImageSubresourceRange		depthSubresourceRange	(VK_IMAGE_ASPECT_DEPTH_BIT);
337 
338 		initialTransitionColor2DImage(vk, *cmdBuffer, m_colorTargetImage->object(), VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
339 		initialTransitionDepth2DImage(vk, *cmdBuffer, m_depthTargetImage->object(), VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
340 		vk.cmdClearColorImage(*cmdBuffer, m_colorTargetImage->object(), VK_IMAGE_LAYOUT_GENERAL, &clearColor.color, 1, &subresourceRange);
341 		vk.cmdClearDepthStencilImage(*cmdBuffer, m_depthTargetImage->object(), VK_IMAGE_LAYOUT_GENERAL, &clearDepth.depthStencil, 1u, &depthSubresourceRange);
342 	}
343 	{
344 		const VkMemoryBarrier memBarrier =
345 		{
346 			VK_STRUCTURE_TYPE_MEMORY_BARRIER,												// VkStructureType    sType;
347 			DE_NULL,																		// const void*        pNext;
348 			VK_ACCESS_TRANSFER_WRITE_BIT,													// VkAccessFlags      srcAccessMask;
349 			VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT		// VkAccessFlags      dstAccessMask;
350 		};
351 
352 		const VkMemoryBarrier depthBarrier =
353 		{
354 			VK_STRUCTURE_TYPE_MEMORY_BARRIER,												// VkStructureType    sType;
355 			DE_NULL,																		// const void*        pNext;
356 			VK_ACCESS_TRANSFER_WRITE_BIT,													// VkAccessFlags      srcAccessMask;
357 			VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT		// VkAccessFlags      dstAccessMask;
358 		};
359 
360 		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 1, &memBarrier, 0, DE_NULL, 0, DE_NULL);
361 		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT), 0, 1, &depthBarrier, 0, DE_NULL, 0, DE_NULL);
362 	}
363 
364 	if (m_params.useDynamicRendering)
365 		beginRendering(vk, *cmdBuffer, *m_colorTargetView, *m_depthTargetView, false, makeRect2D(kImageExtent), clearColor, clearDepth);
366 	else
367 		beginRenderPass(vk, *cmdBuffer, *m_renderPass, *m_framebuffer, makeRect2D(kImageExtent));
368 
369 	{
370 		const VkDeviceSize	offset	= 0;
371 		const VkBuffer		buffer	= m_vertexBuffer->object();
372 
373 		vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &buffer, &offset);
374 	}
375 
376 	vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
377 	vk.cmdDraw(*cmdBuffer, 3, 1, 0, 0);
378 
379 	if (m_params.useDynamicRendering)
380 		endRendering(vk, *cmdBuffer);
381 	else
382 		endRenderPass(vk, *cmdBuffer);
383 
384 	endCommandBuffer(vk, *cmdBuffer);
385 
386 	// Submit
387 	submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
388 
389 	// Get result
390 	{
391 		const auto zeroOffset	= makeOffset3D(0, 0, 0);
392 		const auto iWidth		= static_cast<int>(kImageExtent.width);
393 		const auto iHeight		= static_cast<int>(kImageExtent.height);
394 		const auto colorPixels	= m_colorTargetImage->readSurface(queue, alloc, VK_IMAGE_LAYOUT_GENERAL, zeroOffset, iWidth, iHeight, VK_IMAGE_ASPECT_COLOR_BIT);
395 		const auto depthPixels	= m_depthTargetImage->readSurface(queue, alloc, VK_IMAGE_LAYOUT_GENERAL, zeroOffset, iWidth, iHeight, VK_IMAGE_ASPECT_DEPTH_BIT);
396 
397 		return ColorAndDepth(colorPixels, depthPixels);
398 	}
399 }
400 
generateReferenceImage(ReferenceImageType refType) const401 MovePtr<tcu::TextureLevel> InvertedDepthRangesTestInstance::generateReferenceImage (ReferenceImageType refType) const
402 {
403 	const auto						iWidth			= static_cast<int>(kImageExtent.width);
404 	const auto						iHeight			= static_cast<int>(kImageExtent.height);
405 	const bool						color			= (refType == ReferenceImageType::COLOR);
406 	const auto						tcuFormat		= mapVkFormat(color ? m_colorAttachmentFormat : VK_FORMAT_D16_UNORM_S8_UINT);
407 	MovePtr<tcu::TextureLevel>		image			(new tcu::TextureLevel(tcuFormat, iWidth, iHeight));
408 	const tcu::PixelBufferAccess	access			(image->getAccess());
409 	const float						fImageDim		= static_cast<float>(kImageDim);
410 	const float						p1f				= fImageDim * kMargin / 2.0f;
411 	const float						p2f				= fImageDim * (2.0f - kMargin + kDiagonalMargin) / 2.0f;
412 	const float						triangleSide	= fImageDim * (2.0f - (2.0f*kMargin - kDiagonalMargin)) / 2.0f;
413 	const float						clampMin		= de::min(m_params.minDepth, m_params.maxDepth);
414 	const float						clampMax		= de::max(m_params.minDepth, m_params.maxDepth);
415 	std::array<float, 3>			depthValues;
416 	float							depthBias		= 0.0f;
417 
418 	// Depth value of each vertex in kVertices.
419 	DE_ASSERT(depthValues.size() == kVertices.size());
420 	std::transform(begin(kVertices), end(kVertices), begin(depthValues), [](const Vec4& coord) { return coord.z(); });
421 
422 	if (color)
423 		tcu::clear(access, kClearColor);
424 	else
425 	{
426 		tcu::clearDepth(access, kClearDepth);
427 		tcu::clearStencil(access, kClearStencil);
428 
429 		if (m_params.depthBiasEnable)
430 		{
431 			const float	depthBiasSlopeFactor	= 1.0f;
432 			const float	r						= 0.000030518f;		// minimum resolvable difference is an implementation-dependent parameter
433 			const float	depthBiasConstantFactor	= 0.0f;				// so we use factor 0.0 to not include it; same as in PipelineCreateInfo
434 
435 			// Equations taken from vkCmdSetDepthBias manual page
436 			depthBias = kMaxDepthSlope * depthBiasSlopeFactor + r * depthBiasConstantFactor;
437 
438 			// dbclamp(x) function depends on the sign of the depthBiasClamp
439 			if (m_params.depthBiasClamp < 0.0f)
440 				depthBias = de::max(depthBias, m_params.depthBiasClamp);
441 			else if (m_params.depthBiasClamp > 0.0f)
442 				depthBias = de::min(depthBias, m_params.depthBiasClamp);
443 
444 			if (m_params.maxDepth < m_params.minDepth)
445 				depthBias *= -1.0f;
446 		}
447 	}
448 
449 	for (int y = 0; y < iHeight; ++y)
450 	for (int x = 0; x < iWidth; ++x)
451 	{
452 		const float xcoord = static_cast<float>(x) + 0.5f;
453 		const float ycoord = static_cast<float>(y) + 0.5f;
454 
455 		if (xcoord < p1f || xcoord > p2f)
456 			continue;
457 
458 		if (ycoord < p1f || ycoord > p2f)
459 			continue;
460 
461 		if (ycoord > -xcoord + fImageDim)
462 			continue;
463 
464 		// Interpolate depth value taking the 3 triangle corners into account.
465 		const float b				= (ycoord - p1f) / triangleSide;
466 		const float c				= (xcoord - p1f) / triangleSide;
467 		const float a				= 1.0f - b - c;
468 		const float depth			= a * depthValues[0] + b * depthValues[1] + c * depthValues[2];
469 
470 		// Depth values are always limited to the range [0,1] by clamping after depth bias addition is performed
471 		const float depthClamped	= de::clamp(depth + depthBias, 0.0f, 1.0f);
472 		const float depthFinal		= depthClamped * m_params.maxDepth + (1.0f - depthClamped) * m_params.minDepth;
473 		const float storedDepth		= (m_params.depthClampEnable ? de::clamp(depthFinal, clampMin, clampMax) : depthFinal);
474 
475 		if (m_params.depthClampEnable || de::inRange(depth, -kDepthEpsilon, 1.0f + kDepthEpsilon))
476 		{
477 			if (color)
478 				access.setPixel(Vec4(depthFinal, kVertexColor.y(), kVertexColor.z(), kVertexColor.w()), x, y);
479 			else
480 			{
481 				if (!m_params.depthClampEnable &&
482 					(de::inRange(depth, -kDepthEpsilon, kDepthEpsilon) ||
483 					 de::inRange(depth, 1.0f - kDepthEpsilon, 1.0f + kDepthEpsilon)))
484 				{
485 					// We should avoid comparing this pixel due to possible rounding problems.
486 					// Pixels that should not be compared will be marked in the stencil aspect.
487 					access.setPixStencil(kMaskedStencil, x, y);
488 				}
489 				access.setPixDepth(storedDepth, x, y);
490 			}
491 		}
492 	}
493 
494 	return image;
495 }
496 
iterate(void)497 tcu::TestStatus InvertedDepthRangesTestInstance::iterate (void)
498 {
499 	// Set up the viewport and draw
500 
501 	const VkViewport viewport =
502 	{
503 		0.0f,										// float    x;
504 		0.0f,										// float    y;
505 		static_cast<float>(kImageExtent.width),		// float    width;
506 		static_cast<float>(kImageExtent.height),	// float    height;
507 		m_params.minDepth,							// float    minDepth;
508 		m_params.maxDepth,							// float    maxDepth;
509 	};
510 
511 	ColorAndDepth	results		= draw(viewport);
512 	auto&			resultImage	= results.first;
513 	auto&			resultDepth	= results.second;
514 
515 	// Verify results
516 	auto&	log				= m_context.getTestContext().getLog();
517 	auto	referenceImage	= generateReferenceImage(ReferenceImageType::COLOR);
518 	auto	referenceDepth	= generateReferenceImage(ReferenceImageType::DEPTH);
519 
520 	bool fail = false;
521 	// Color aspect.
522 	if (!tcu::fuzzyCompare(log, "Image compare", "Image compare", referenceImage->getAccess(), resultImage, 0.02f, tcu::COMPARE_LOG_RESULT))
523 		fail = true;
524 
525 	// Depth aspect.
526 	bool depthFail = false;
527 
528 	const auto refWidth			= referenceDepth->getWidth();
529 	const auto refHeight		= referenceDepth->getHeight();
530 	const auto refAccess		= referenceDepth->getAccess();
531 
532 	tcu::TextureLevel errorMask	(mapVkFormat(VK_FORMAT_R8G8B8_UNORM), refWidth, refHeight);
533 	auto errorAccess			= errorMask.getAccess();
534 	const tcu::Vec4 kGreen		(0.0f, 1.0f, 0.0f, 1.0f);
535 	const tcu::Vec4 kRed		(1.0f, 0.0f, 0.0f, 1.0f);
536 
537 	tcu::clear(errorAccess, kGreen);
538 
539 	for (int y = 0; y < refHeight; ++y)
540 	for (int x = 0; x < refWidth; ++x)
541 	{
542 		// Ignore pixels that could be too close to having or not having coverage.
543 		const auto stencil = refAccess.getPixStencil(x, y);
544 		if (stencil == kMaskedStencil)
545 			continue;
546 
547 		// Compare the rest using a known threshold.
548 		const auto refValue = refAccess.getPixDepth(x, y);
549 		const auto resValue = resultDepth.getPixDepth(x, y);
550 		if (!de::inRange(resValue, refValue - kDepthThreshold, refValue + kDepthThreshold))
551 		{
552 			depthFail = true;
553 			errorAccess.setPixel(kRed, x, y);
554 		}
555 	}
556 
557 	if (depthFail)
558 	{
559 		log << tcu::TestLog::Message << "Depth Image comparison failed" << tcu::TestLog::EndMessage;
560 		log	<< tcu::TestLog::Image("Result", "Result", resultDepth)
561 			<< tcu::TestLog::Image("Reference",	"Reference", refAccess)
562 			<< tcu::TestLog::Image("ErrorMask",	"Error mask", errorAccess);
563 	}
564 
565 	if (fail || depthFail)
566 		return tcu::TestStatus::fail("Result images are incorrect");
567 
568 	return tcu::TestStatus::pass("Pass");
569 }
570 
571 class InvertedDepthRangesTest : public TestCase
572 {
573 public:
InvertedDepthRangesTest(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const TestParams & params)574 	InvertedDepthRangesTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params)
575 		: TestCase	(testCtx, name, description)
576 		, m_params	(params)
577 	{
578 	}
579 
initPrograms(SourceCollections & programCollection) const580 	void initPrograms (SourceCollections& programCollection) const
581 	{
582 		// Vertex shader
583 		{
584 			std::ostringstream src;
585 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
586 				<< "\n"
587 				<< "layout(location = 0) in highp vec4 in_position;\n"
588 				<< "\n"
589 				<< "out gl_PerVertex {\n"
590 				<< "    highp vec4 gl_Position;\n"
591 				<< "};\n"
592 				<< "\n"
593 				<< "void main(void)\n"
594 				<< "{\n"
595 				<< "    gl_Position = in_position;\n"
596 				<< "}\n";
597 
598 			programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
599 		}
600 
601 		// Fragment shader
602 		{
603 			std::ostringstream src;
604 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
605 				<< "\n"
606 				<< "layout(location = 0) out highp vec4 out_color;\n"
607 				<< "\n"
608 				<< "void main(void)\n"
609 				<< "{\n"
610 				<< "    out_color = vec4(gl_FragCoord.z, " << kVertexColor.y() << ", " << kVertexColor.z() << ", " << kVertexColor.w() << ");\n"
611 				<< "}\n";
612 
613 			programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
614 		}
615 	}
616 
checkSupport(Context & context) const617 	virtual void checkSupport (Context& context) const
618 	{
619 		if (m_params.depthClampEnable)
620 			context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_DEPTH_CLAMP);
621 
622 		if (m_params.depthBiasEnable && m_params.depthBiasClamp != 0.0f)
623 			context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_DEPTH_BIAS_CLAMP);
624 
625 		if (m_params.minDepth > 1.0f || m_params.minDepth < 0.0f || m_params.maxDepth > 1.0f || m_params.maxDepth < 0.0f)
626 			context.requireDeviceFunctionality("VK_EXT_depth_range_unrestricted");
627 
628 		if (m_params.useDynamicRendering)
629 			context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
630 	}
631 
createInstance(Context & context) const632 	virtual TestInstance* createInstance (Context& context) const
633 	{
634 		return new InvertedDepthRangesTestInstance(context, m_params);
635 	}
636 
637 private:
638 	const TestParams	m_params;
639 };
640 
populateTestGroup(tcu::TestCaseGroup * testGroup,bool useDynamicRendering)641 void populateTestGroup (tcu::TestCaseGroup* testGroup, bool useDynamicRendering)
642 {
643 	const struct
644 	{
645 		std::string		name;
646 		VkBool32		depthClamp;
647 	} depthClamp[] =
648 	{
649 		{ "depthclamp",		VK_TRUE		},
650 		{ "nodepthclamp",	VK_FALSE	},
651 	};
652 
653 	const struct
654 	{
655 		std::string		name;
656 		float			delta;
657 		VkBool32		depthBiasEnable;
658 		float			depthBiasClamp;
659 	} depthParams[] =
660 	{
661 		{ "deltazero",					0.0f,		DE_FALSE,	 0.0f },
662 		{ "deltasmall",					0.3f,		DE_FALSE,	 0.0f },
663 		{ "deltaone",					1.0f,		DE_FALSE,	 0.0f },
664 
665 		// depthBiasClamp must be smaller then maximum depth slope to make a difference
666 		{ "deltaone_bias_clamp_neg",	1.0f,		DE_TRUE,	-0.003f },
667 		{ "deltasmall_bias_clamp_pos",	0.3f,		DE_TRUE,	 0.003f },
668 
669 		// Range > 1.0 requires VK_EXT_depth_range_unrestricted extension
670 		{ "depth_range_unrestricted",	2.7f,		DE_FALSE,	 0.0f },
671 	};
672 
673 	for (int ndxDepthClamp = 0; ndxDepthClamp < DE_LENGTH_OF_ARRAY(depthClamp); ++ndxDepthClamp)
674 	for (int ndxParams = 0; ndxParams < DE_LENGTH_OF_ARRAY(depthParams); ++ndxParams)
675 	{
676 		const auto& cDepthClamp		= depthClamp[ndxDepthClamp];
677 		const auto& cDepthParams	= depthParams[ndxParams];
678 		const float minDepth		= 0.5f + cDepthParams.delta / 2.0f;
679 		const float maxDepth		 = minDepth - cDepthParams.delta;
680 		DE_ASSERT(minDepth >= maxDepth);
681 
682 		const TestParams params =
683 		{
684 			minDepth,
685 			maxDepth,
686 			cDepthClamp.depthClamp,
687 			cDepthParams.depthBiasEnable,
688 			cDepthParams.depthBiasClamp,
689 			useDynamicRendering
690 		};
691 
692 		std::string name = cDepthClamp.name + "_" + cDepthParams.name;
693 		testGroup->addChild(new InvertedDepthRangesTest(testGroup->getTestContext(), name, "", params));
694 	}
695 }
696 
697 }	// anonymous
698 
createInvertedDepthRangesTests(tcu::TestContext & testCtx,bool useDynamicRendering)699 tcu::TestCaseGroup*	createInvertedDepthRangesTests (tcu::TestContext& testCtx, bool useDynamicRendering)
700 {
701 	return createTestGroup(testCtx, "inverted_depth_ranges", "Inverted depth ranges", populateTestGroup, useDynamicRendering);
702 }
703 
704 }	// Draw
705 }	// vkt
706