• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2022 LunarG, Inc.
6  * Copyright (c) 2022 The Khronos Group Inc.
7  * Copyright (c) 2022 Google LLC
8  * Copyright (c) 2023 Nintendo
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  *//*!
23  * \file
24  * \brief Dynamic State Discard Tests
25  *//*--------------------------------------------------------------------*/
26 
27 #include "vktDynamicStateDiscardTests.hpp"
28 
29 #include "vktDynamicStateBaseClass.hpp"
30 #include "vktDynamicStateTestCaseUtil.hpp"
31 
32 #include "vkImageUtil.hpp"
33 #include "vkCmdUtil.hpp"
34 
35 #include "tcuImageCompare.hpp"
36 #include "tcuTextureUtil.hpp"
37 #include "tcuRGBA.hpp"
38 #include "vkQueryUtil.hpp"
39 #include "vkObjUtil.hpp"
40 #include "vkTypeUtil.hpp"
41 #include "vkBufferWithMemory.hpp"
42 
43 namespace vkt
44 {
45 namespace DynamicState
46 {
47 using namespace Draw;
48 using namespace vk;
49 
50 enum TestDynamicStateDiscard
51 {
52 	TEST_STENCIL,
53 	TEST_VIEWPORT,
54 	TEST_SCISSOR,
55 	TEST_DEPTH,
56 	TEST_BLEND_CONSTANTS,
57 	TEST_LINE_WIDTH,
58 };
59 
pickSupportedStencilFormat(const InstanceInterface & instanceInterface,const VkPhysicalDevice device)60 VkFormat pickSupportedStencilFormat	(const InstanceInterface&	instanceInterface,
61 									 const VkPhysicalDevice		device)
62 {
63 	static const VkFormat stencilFormats[] =
64 	{
65 		VK_FORMAT_S8_UINT,
66 		VK_FORMAT_D16_UNORM_S8_UINT,
67 		VK_FORMAT_D24_UNORM_S8_UINT,
68 		VK_FORMAT_D32_SFLOAT_S8_UINT,
69 	};
70 
71 	for (deUint32 i = 0; i < DE_LENGTH_OF_ARRAY(stencilFormats); ++i)
72 	{
73 		VkFormatProperties formatProps;
74 		instanceInterface.getPhysicalDeviceFormatProperties(device, stencilFormats[i], &formatProps);
75 
76 		if ((formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0)
77 		{
78 			return stencilFormats[i];
79 		}
80 	}
81 	TCU_FAIL("Cannot find supported stencil format");
82 }
83 
isFormatStencil(VkFormat format)84 bool isFormatStencil (VkFormat format)
85 {
86 	const auto textureFormat = vk::mapVkFormat(format);
87 	return (textureFormat.order == tcu::TextureFormat::DS || textureFormat.order == tcu::TextureFormat::S);
88 }
89 
90 class DiscardTestInstance : public DynamicStateBaseClass
91 {
92 public:
93 	DiscardTestInstance (Context& context, vk::PipelineConstructionType pipelineConstructionType, const char* vertexShaderName, const char* fragmentShaderName, vk::VkFormat depthStencilFormat);
94 
95 	virtual void								initRenderPass	(const vk::VkDevice		device);
96 	virtual void								initFramebuffer	(const vk::VkDevice		device);
97 	virtual void								initPipeline	(const vk::VkDevice		device);
98 
99 	void										beginRenderPass	(const vk::VkClearColorValue& clearColor);
100 
101 	virtual tcu::TestStatus						iterate			(void);
102 
103 protected:
104 
setDynamicState(void)105 	virtual void								setDynamicState	(void) {
106 		DE_ASSERT(false);
107 	}
verifyResults(void)108 	virtual tcu::TestStatus						verifyResults	(void) {
109 		DE_ASSERT(false);
110 		return tcu::TestStatus(QP_TEST_RESULT_PASS, "");
111 	}
112 	const vk::VkFormat					m_depthStencilAttachmentFormat;
113 
114 	de::SharedPtr<Draw::Image>			m_depthStencilImage;
115 	vk::Move<vk::VkImageView>			m_depthStencilView;
116 	std::vector<vk::VkDynamicState>		m_dynamicStates;
117 	VkBool32							m_depthBounds;
118 };
119 
DiscardTestInstance(Context & context,vk::PipelineConstructionType pipelineConstructionType,const char * vertexShaderName,const char * fragmentShaderName,vk::VkFormat depthStencilFormat)120 DiscardTestInstance::DiscardTestInstance(Context& context, vk::PipelineConstructionType pipelineConstructionType, const char* vertexShaderName, const char* fragmentShaderName, vk::VkFormat depthStencilFormat)
121 	: DynamicStateBaseClass(context, pipelineConstructionType, vertexShaderName, fragmentShaderName)
122 	, m_depthStencilAttachmentFormat(depthStencilFormat)
123 	, m_depthBounds(VK_FALSE)
124 {
125 	const vk::VkDevice				device					= m_context.getDevice();
126 
127 	const vk::VkExtent3D			stencilImageExtent		= { WIDTH, HEIGHT, 1 };
128 	const ImageCreateInfo			stencilImageCreateInfo	(vk::VK_IMAGE_TYPE_2D, m_depthStencilAttachmentFormat, stencilImageExtent, 1, 1, vk::VK_SAMPLE_COUNT_1_BIT, vk::VK_IMAGE_TILING_OPTIMAL, vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT | vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT);
129 
130 	m_depthStencilImage	= Image::createAndAlloc(m_vk, device, stencilImageCreateInfo, m_context.getDefaultAllocator(), m_context.getUniversalQueueFamilyIndex());
131 
132 	const ImageViewCreateInfo		stencilViewInfo(m_depthStencilImage->object(), vk::VK_IMAGE_VIEW_TYPE_2D, m_depthStencilAttachmentFormat);
133 	m_depthStencilView	= vk::createImageView(m_vk, device, &stencilViewInfo);
134 
135 	m_topology		= vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
136 
137 	m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
138 	m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
139 	m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
140 	m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
141 
142 	const vk::VkDescriptorSetLayoutBinding binding =
143 	{
144 		0u,
145 		vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
146 		1,
147 		vk::VK_SHADER_STAGE_FRAGMENT_BIT,
148 		DE_NULL
149 	};
150 
151 	DescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo(1, &binding);
152 	m_otherSetLayout = vk::createDescriptorSetLayout(m_vk, device, &descriptorSetLayoutCreateInfo);
153 }
154 
initRenderPass(const vk::VkDevice device)155 void DiscardTestInstance::initRenderPass (const vk::VkDevice device)
156 {
157 	RenderPassCreateInfo renderPassCreateInfo;
158 	renderPassCreateInfo.addAttachment(AttachmentDescription(m_colorAttachmentFormat,
159 		vk::VK_SAMPLE_COUNT_1_BIT,
160 		vk::VK_ATTACHMENT_LOAD_OP_LOAD,
161 		vk::VK_ATTACHMENT_STORE_OP_STORE,
162 		vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
163 		vk::VK_ATTACHMENT_STORE_OP_STORE,
164 		vk::VK_IMAGE_LAYOUT_GENERAL,
165 		vk::VK_IMAGE_LAYOUT_GENERAL));
166 	renderPassCreateInfo.addAttachment(AttachmentDescription(m_depthStencilAttachmentFormat,
167 		vk::VK_SAMPLE_COUNT_1_BIT,
168 		vk::VK_ATTACHMENT_LOAD_OP_LOAD,
169 		vk::VK_ATTACHMENT_STORE_OP_STORE,
170 		vk::VK_ATTACHMENT_LOAD_OP_LOAD,
171 		vk::VK_ATTACHMENT_STORE_OP_STORE,
172 		vk::VK_IMAGE_LAYOUT_GENERAL,
173 		vk::VK_IMAGE_LAYOUT_GENERAL));
174 
175 	const vk::VkAttachmentReference colorAttachmentReference =
176 	{
177 		0,
178 		vk::VK_IMAGE_LAYOUT_GENERAL
179 	};
180 
181 	const vk::VkAttachmentReference stencilAttachmentReference =
182 	{
183 		1,
184 		vk::VK_IMAGE_LAYOUT_GENERAL
185 	};
186 
187 	renderPassCreateInfo.addSubpass(SubpassDescription(
188 		vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
189 		0,
190 		0,
191 		DE_NULL,
192 		1,
193 		&colorAttachmentReference,
194 		DE_NULL,
195 		stencilAttachmentReference,
196 		0,
197 		DE_NULL
198 	)
199 	);
200 
201 	m_renderPass = vk::RenderPassWrapper(m_pipelineConstructionType, m_vk, device, &renderPassCreateInfo);
202 }
203 
initFramebuffer(const vk::VkDevice device)204 void DiscardTestInstance::initFramebuffer (const vk::VkDevice device)
205 {
206 	std::vector<vk::VkImageView> attachments(2);
207 	attachments[0] = *m_colorTargetView;
208 	attachments[1] = *m_depthStencilView;
209 
210 	const FramebufferCreateInfo framebufferCreateInfo(*m_renderPass, attachments, WIDTH, HEIGHT, 1);
211 
212 	m_renderPass.createFramebuffer(m_vk, device, &framebufferCreateInfo, {m_colorTargetImage->object(), m_depthStencilImage->object()});
213 }
214 
initPipeline(const vk::VkDevice device)215 void DiscardTestInstance::initPipeline(const vk::VkDevice device)
216 {
217 	const vk::ShaderWrapper									vs(vk::ShaderWrapper	(m_vk, device, m_context.getBinaryCollection().get(m_vertexShaderName), 0));
218 	const vk::ShaderWrapper									fs(vk::ShaderWrapper	(m_vk, device, m_context.getBinaryCollection().get(m_fragmentShaderName), 0));
219 	std::vector<vk::VkViewport>								viewports				{ { 0.0f, 0.0f, (float)WIDTH, (float)HEIGHT, 0.0f, 1.0f } };
220 	std::vector<vk::VkRect2D>								scissors				{ { { 0u, 0u }, { WIDTH, HEIGHT } } };
221 
222 	const PipelineCreateInfo::ColorBlendState::Attachment	attachmentState;
223 	const PipelineCreateInfo::ColorBlendState				colorBlendState(1u, static_cast<const vk::VkPipelineColorBlendAttachmentState*>(&attachmentState));
224 	const PipelineCreateInfo::RasterizerState				rasterizerState;
225 	PipelineCreateInfo::DepthStencilState					depthStencilState;
226 	const PipelineCreateInfo::DynamicState					dynamicState(m_dynamicStates);
227 
228 	depthStencilState.depthTestEnable		= VK_TRUE;
229 	depthStencilState.depthWriteEnable		= VK_TRUE;
230 	depthStencilState.depthCompareOp		= VK_COMPARE_OP_ALWAYS;
231 	depthStencilState.depthBoundsTestEnable = m_depthBounds;
232 	depthStencilState.minDepthBounds		= 0.0f;
233 	depthStencilState.maxDepthBounds		= 1.0f;
234 	depthStencilState.stencilTestEnable		= VK_TRUE;
235 	depthStencilState.front.failOp			= VK_STENCIL_OP_KEEP;
236 	depthStencilState.front.passOp			= VK_STENCIL_OP_REPLACE;
237 	depthStencilState.front.depthFailOp		= VK_STENCIL_OP_KEEP;
238 	depthStencilState.front.compareOp		= VK_COMPARE_OP_ALWAYS;
239 	depthStencilState.front.compareMask		= 0u;
240 	depthStencilState.front.writeMask		= 0u;
241 	depthStencilState.front.reference		= 0u;
242 	depthStencilState.back.failOp			= VK_STENCIL_OP_KEEP;
243 	depthStencilState.back.passOp			= VK_STENCIL_OP_REPLACE;
244 	depthStencilState.back.depthFailOp		= VK_STENCIL_OP_KEEP;
245 	depthStencilState.back.compareOp		= VK_COMPARE_OP_ALWAYS;
246 	depthStencilState.back.compareMask		= 0u;
247 	depthStencilState.back.writeMask		= 0u;
248 	depthStencilState.back.reference		= 0u;
249 
250 	m_pipeline.setDefaultTopology(m_topology)
251 		.setDynamicState(static_cast<const vk::VkPipelineDynamicStateCreateInfo*>(&dynamicState))
252 		.setDefaultMultisampleState()
253 		.setupVertexInputState(&m_vertexInputState)
254 		.setupPreRasterizationShaderState(viewports,
255 			scissors,
256 			m_pipelineLayout,
257 			*m_renderPass,
258 			0u,
259 			vs,
260 			static_cast<const vk::VkPipelineRasterizationStateCreateInfo*>(&rasterizerState))
261 		.setupFragmentShaderState(m_pipelineLayout, *m_renderPass, 0u, fs, static_cast<const vk::VkPipelineDepthStencilStateCreateInfo*>(&depthStencilState))
262 		.setupFragmentOutputState(*m_renderPass, 0u, static_cast<const vk::VkPipelineColorBlendStateCreateInfo*>(&colorBlendState))
263 		.setMonolithicPipelineLayout(m_pipelineLayout)
264 		.buildPipeline();
265 }
266 
beginRenderPass(const vk::VkClearColorValue & clearColor)267 void DiscardTestInstance::beginRenderPass (const vk::VkClearColorValue& clearColor)
268 {
269 	beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
270 
271 	initialTransitionColor2DImage(m_vk, *m_cmdBuffer, m_colorTargetImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
272 		vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT);
273 
274 	const ImageSubresourceRange subresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT);
275 	m_vk.cmdClearColorImage(*m_cmdBuffer, m_colorTargetImage->object(),
276 		vk::VK_IMAGE_LAYOUT_GENERAL, &clearColor, 1, &subresourceRange);
277 
278 	const vk::VkMemoryBarrier memBarrier =
279 	{
280 		vk::VK_STRUCTURE_TYPE_MEMORY_BARRIER,
281 		DE_NULL,
282 		vk::VK_ACCESS_TRANSFER_WRITE_BIT,
283 		vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
284 	};
285 
286 	m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
287 		vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
288 		0, 1, &memBarrier, 0, DE_NULL, 0, DE_NULL);
289 
290 	if (isFormatStencil(m_depthStencilAttachmentFormat)) {
291 		initialTransitionStencil2DImage(m_vk, *m_cmdBuffer, m_depthStencilImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL, vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT);
292 	}
293 	else
294 	{
295 		initialTransitionDepth2DImage(m_vk, *m_cmdBuffer, m_depthStencilImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL, vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT);
296 	}
297 
298 
299 	const vk::VkClearDepthStencilValue	depthStencilClearValue	= { 0.0f, 0 };
300 	const ImageSubresourceRange			subresourceRangeStencil = m_depthStencilAttachmentFormat == vk::VK_FORMAT_S8_UINT ? vk::VK_IMAGE_ASPECT_STENCIL_BIT : vk::VK_IMAGE_ASPECT_DEPTH_BIT;
301 	m_vk.cmdClearDepthStencilImage(*m_cmdBuffer, m_depthStencilImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL, &depthStencilClearValue, 1, &subresourceRangeStencil);
302 
303 	vk::VkMemoryBarrier dsMemBarrier;
304 	dsMemBarrier.sType = vk::VK_STRUCTURE_TYPE_MEMORY_BARRIER;
305 	dsMemBarrier.pNext = NULL;
306 	dsMemBarrier.srcAccessMask = vk::VK_ACCESS_TRANSFER_WRITE_BIT;
307 	dsMemBarrier.dstAccessMask = vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
308 
309 	m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | vk::VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | vk::VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, 0, 1, &dsMemBarrier, 0, NULL, 0, NULL);
310 
311 	m_renderPass.begin(m_vk, *m_cmdBuffer, vk::makeRect2D(0, 0, WIDTH, HEIGHT));
312 }
iterate(void)313 tcu::TestStatus DiscardTestInstance::iterate(void) {
314 	const vk::VkQueue					queue				= m_context.getUniversalQueue();
315 	const vk::VkDevice					device				= m_context.getDevice();
316 	Allocator&							allocator			= m_context.getDefaultAllocator();
317 
318 	const VkDescriptorPoolSize			poolSizes[] =
319 	{
320 		{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,	1u	},
321 	};
322 	const VkDescriptorPoolCreateInfo	poolInfo =
323 	{
324 		VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
325 		DE_NULL,
326 		vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
327 		1u,		// maxSets
328 		DE_LENGTH_OF_ARRAY(poolSizes),
329 		poolSizes,
330 	};
331 
332 	vk::Move<vk::VkDescriptorPool>		descriptorPool		= createDescriptorPool(m_vk, device, &poolInfo);
333 	vk::Move<vk::VkDescriptorSet>		descriptorSet		= makeDescriptorSet(m_vk, device, *descriptorPool, *m_otherSetLayout);
334 
335 	const vk::VkDeviceSize				size				= sizeof(int);
336 
337 	const BufferWithMemory				buffer				(m_vk, device, allocator, makeBufferCreateInfo(size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT), MemoryRequirement::HostVisible);
338 
339 	deUint32*							ptr					= (deUint32*)buffer.getAllocation().getHostPtr();
340 	deMemset(ptr, 0u, static_cast<std::size_t>(size));
341 
342 	{
343 		const vk::VkDescriptorBufferInfo	bufferInfo		= makeDescriptorBufferInfo(*buffer, 0, size);
344 		const vk::VkWriteDescriptorSet		descriptorWrite =
345 		{
346 			VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
347 			DE_NULL,
348 			*descriptorSet,
349 			0u,		// dstBinding
350 			0u,		// dstArrayElement
351 			1u,		// descriptorCount
352 			VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
353 			DE_NULL,
354 			&bufferInfo,
355 			DE_NULL,
356 		};
357 
358 		m_vk.updateDescriptorSets(device, 1, &descriptorWrite, 0u, DE_NULL);
359 	}
360 
361 	const vk::VkClearColorValue			clearColor			= { { 0.0f, 0.0f, 0.0f, 1.0f } };
362 	beginRenderPass(clearColor);
363 	m_vk.cmdBindDescriptorSets(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0, 1, &*descriptorSet, 0, nullptr);
364 	m_pipeline.bind(*m_cmdBuffer);
365 	const vk::VkDeviceSize vertexBufferOffset = 0;
366 	const vk::VkBuffer		vertexBuffer = m_vertexBuffer->object();
367 	m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
368 
369 	setDynamicState();
370 
371 	m_vk.cmdDraw(*m_cmdBuffer, 4, 1, 0, 0);
372 	m_renderPass.end(m_vk, *m_cmdBuffer);
373 	endCommandBuffer(m_vk, *m_cmdBuffer);
374 
375 	submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
376 
377 	return verifyResults();
378 }
379 
380 class StencilTestInstance : public DiscardTestInstance
381 {
382 public:
StencilTestInstance(Context & context,vk::PipelineConstructionType pipelineConstructionType,const char * vertexShaderName,const char * fragmentShaderName)383 	StencilTestInstance(Context& context, vk::PipelineConstructionType pipelineConstructionType, const char* vertexShaderName, const char* fragmentShaderName)
384 		: DiscardTestInstance(context, pipelineConstructionType, vertexShaderName, fragmentShaderName, pickSupportedStencilFormat(context.getInstanceInterface(), context.getPhysicalDevice()))
385 	{
386 		m_dynamicStates = { vk::VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, vk::VK_DYNAMIC_STATE_STENCIL_WRITE_MASK, vk::VK_DYNAMIC_STATE_STENCIL_REFERENCE };
387 		const auto features = context.getDeviceFeatures();
388 		m_depthBounds = features.depthBounds;
389 
390 		DynamicStateBaseClass::initialize();
391 	}
392 
setDynamicState(void)393 	virtual void setDynamicState(void) {
394 		uint32_t value = 0x80;
395 		m_vk.cmdSetStencilCompareMask(*m_cmdBuffer, vk::VK_STENCIL_FACE_FRONT_BIT, value);
396 		m_vk.cmdSetStencilWriteMask(*m_cmdBuffer, vk::VK_STENCIL_FACE_FRONT_BIT, value);
397 		m_vk.cmdSetStencilReference(*m_cmdBuffer, vk::VK_STENCIL_FACE_FRONT_BIT, value);
398 		m_vk.cmdSetStencilCompareMask(*m_cmdBuffer, vk::VK_STENCIL_FACE_BACK_BIT, value);
399 		m_vk.cmdSetStencilWriteMask(*m_cmdBuffer, vk::VK_STENCIL_FACE_BACK_BIT, value);
400 		m_vk.cmdSetStencilReference(*m_cmdBuffer, vk::VK_STENCIL_FACE_BACK_BIT, value);
401 	}
402 
verifyResults(void)403 	virtual tcu::TestStatus verifyResults(void) {
404 		const vk::VkQueue					queue			= m_context.getUniversalQueue();
405 		const vk::VkOffset3D				zeroOffset		= { 0, 0, 0 };
406 		tcu::ConstPixelBufferAccess			renderedFrame	= m_depthStencilImage->readSurface(queue, m_context.getDefaultAllocator(), vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_STENCIL_BIT);
407 		de::SharedPtr<tcu::TextureLevel>	stencilFrame;
408 
409 		if (tcu::isCombinedDepthStencilType(renderedFrame.getFormat().type))
410 		{
411 			stencilFrame = de::SharedPtr<tcu::TextureLevel>( new tcu::TextureLevel(tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT8), WIDTH, HEIGHT, 1u));
412 
413 			tcu::copy(stencilFrame->getAccess(), tcu::getEffectiveDepthStencilAccess(renderedFrame, tcu::Sampler::MODE_STENCIL));
414 			renderedFrame = stencilFrame->getAccess();
415 		}
416 
417 		for (int i = 0; i < WIDTH; ++i) {
418 			for (int j = 0; j < HEIGHT; ++j) {
419 				const tcu::Vec4 pixel = renderedFrame.getPixel(i, j);
420 				if (pixel[0] != 0.0f) {
421 					return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Image verification failed");
422 				}
423 			}
424 		}
425 		return tcu::TestStatus(QP_TEST_RESULT_PASS, "Image verification passed");
426 	}
427 };
428 
429 class ViewportTestInstance : public DiscardTestInstance
430 {
431 public:
ViewportTestInstance(Context & context,vk::PipelineConstructionType pipelineConstructionType,const char * vertexShaderName,const char * fragmentShaderName)432 	ViewportTestInstance(Context& context, vk::PipelineConstructionType pipelineConstructionType, const char* vertexShaderName, const char* fragmentShaderName)
433 		: DiscardTestInstance(context, pipelineConstructionType, vertexShaderName, fragmentShaderName, pickSupportedStencilFormat(context.getInstanceInterface(), context.getPhysicalDevice()))
434 	{
435 		m_dynamicStates = { vk::VK_DYNAMIC_STATE_VIEWPORT };
436 		DynamicStateBaseClass::initialize();
437 	}
438 
setDynamicState(void)439 	virtual void setDynamicState(void) {
440 		vk::VkViewport viewport = vk::makeViewport(tcu::UVec2(WIDTH, HEIGHT));
441 		if (vk::isConstructionTypeShaderObject(m_pipelineConstructionType))
442 		{
443 #ifndef CTS_USES_VULKANSC
444 			m_vk.cmdSetViewportWithCount(*m_cmdBuffer, 1, &viewport);
445 #else
446 			m_vk.cmdSetViewportWithCountEXT(*m_cmdBuffer, 1, &viewport);
447 #endif
448 		}
449 		else
450 		{
451 			m_vk.cmdSetViewport(*m_cmdBuffer, 0, 1, &viewport);
452 		}
453 	}
454 
verifyResults(void)455 	virtual tcu::TestStatus verifyResults(void) {
456 		const vk::VkQueue	queue = m_context.getUniversalQueue();
457 		tcu::Texture2D		referenceFrame(vk::mapVkFormat(m_depthStencilAttachmentFormat), WIDTH, HEIGHT);
458 		referenceFrame.allocLevel(0);
459 
460 		const vk::VkOffset3D				zeroOffset = { 0, 0, 0 };
461 		const tcu::ConstPixelBufferAccess	renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
462 			vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
463 
464 		for (int i = 0; i < WIDTH; ++i) {
465 			for (int j = 0; j < HEIGHT; ++j) {
466 				const tcu::Vec4 pixel = renderedFrame.getPixel(i, j);
467 				if (pixel != tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)) {
468 					return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Image verification failed");
469 				}
470 			}
471 		}
472 		return tcu::TestStatus(QP_TEST_RESULT_PASS, "Image verification passed");
473 	}
474 };
475 
476 class ScissorTestInstance : public DiscardTestInstance
477 {
478 public:
ScissorTestInstance(Context & context,vk::PipelineConstructionType pipelineConstructionType,const char * vertexShaderName,const char * fragmentShaderName)479 	ScissorTestInstance(Context& context, vk::PipelineConstructionType pipelineConstructionType, const char* vertexShaderName, const char* fragmentShaderName)
480 		: DiscardTestInstance(context, pipelineConstructionType, vertexShaderName, fragmentShaderName, pickSupportedStencilFormat(context.getInstanceInterface(), context.getPhysicalDevice()))
481 	{
482 		m_dynamicStates = { vk::VK_DYNAMIC_STATE_SCISSOR };
483 		DynamicStateBaseClass::initialize();
484 	}
485 
setDynamicState(void)486 	virtual void setDynamicState(void) {
487 		vk::VkRect2D scissor = vk::makeRect2D(tcu::UVec2(WIDTH, HEIGHT));
488 		m_vk.cmdSetScissor(*m_cmdBuffer, 0, 1, &scissor);
489 	}
490 
verifyResults(void)491 	virtual tcu::TestStatus verifyResults(void) {
492 		const vk::VkQueue	queue = m_context.getUniversalQueue();
493 		tcu::Texture2D		referenceFrame(vk::mapVkFormat(m_depthStencilAttachmentFormat), WIDTH, HEIGHT);
494 		referenceFrame.allocLevel(0);
495 
496 		const vk::VkOffset3D				zeroOffset = { 0, 0, 0 };
497 		const tcu::ConstPixelBufferAccess	renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
498 			vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
499 
500 		for (int i = 0; i < WIDTH; ++i) {
501 			for (int j = 0; j < HEIGHT; ++j) {
502 				const tcu::Vec4 pixel = renderedFrame.getPixel(i, j);
503 				if (pixel != tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)) {
504 					return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Image verification failed");
505 				}
506 			}
507 		}
508 		return tcu::TestStatus(QP_TEST_RESULT_PASS, "Image verification passed");
509 	}
510 };
511 
512 class DepthTestInstance : public DiscardTestInstance
513 {
514 public:
DepthTestInstance(Context & context,vk::PipelineConstructionType pipelineConstructionType,const char * vertexShaderName,const char * fragmentShaderName)515 	DepthTestInstance(Context& context, vk::PipelineConstructionType pipelineConstructionType, const char* vertexShaderName, const char* fragmentShaderName)
516 		: DiscardTestInstance(context, pipelineConstructionType, vertexShaderName, fragmentShaderName, vk::VK_FORMAT_D32_SFLOAT)
517 	{
518 		m_dynamicStates = { vk::VK_DYNAMIC_STATE_DEPTH_BIAS, vk::VK_DYNAMIC_STATE_DEPTH_BOUNDS };
519 		DynamicStateBaseClass::initialize();
520 	}
521 
setDynamicState(void)522 	virtual void setDynamicState(void) {
523 		m_vk.cmdSetDepthBounds(*m_cmdBuffer, 0.0f, 1.0f);
524 		m_vk.cmdSetDepthBias(*m_cmdBuffer, 1.0f, 1.0f, 1.0f);
525 	}
526 
verifyResults(void)527 	virtual tcu::TestStatus verifyResults(void) {
528 		const vk::VkQueue					queue			= m_context.getUniversalQueue();
529 		const vk::VkOffset3D				zeroOffset		= { 0, 0, 0 };
530 		const tcu::ConstPixelBufferAccess	renderedFrame	= m_depthStencilImage->readSurface(queue, m_context.getDefaultAllocator(), vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_DEPTH_BIT);
531 
532 		for (int i = 0; i < WIDTH; ++i) {
533 			for (int j = 0; j < HEIGHT; ++j) {
534 				const tcu::Vec4 pixel = renderedFrame.getPixel(i, j);
535 				if (pixel[0] != 0.0f) {
536 					return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Image verification failed");
537 				}
538 			}
539 		}
540 		return tcu::TestStatus(QP_TEST_RESULT_PASS, "Image verification passed");
541 	}
542 };
543 
544 class BlendTestInstance : public DiscardTestInstance
545 {
546 public:
BlendTestInstance(Context & context,vk::PipelineConstructionType pipelineConstructionType,const char * vertexShaderName,const char * fragmentShaderName)547 	BlendTestInstance(Context& context, vk::PipelineConstructionType pipelineConstructionType, const char* vertexShaderName, const char* fragmentShaderName)
548 		: DiscardTestInstance(context, pipelineConstructionType, vertexShaderName, fragmentShaderName, pickSupportedStencilFormat(context.getInstanceInterface(), context.getPhysicalDevice()))
549 	{
550 		m_dynamicStates = { vk::VK_DYNAMIC_STATE_BLEND_CONSTANTS };
551 		DynamicStateBaseClass::initialize();
552 	}
553 
setDynamicState(void)554 	virtual void setDynamicState(void) {
555 		float blendConstantsants[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
556 		m_vk.cmdSetBlendConstants(*m_cmdBuffer, blendConstantsants);
557 	}
558 
verifyResults(void)559 	virtual tcu::TestStatus verifyResults(void) {
560 		const vk::VkQueue	queue = m_context.getUniversalQueue();
561 		tcu::Texture2D		referenceFrame(vk::mapVkFormat(m_depthStencilAttachmentFormat), WIDTH, HEIGHT);
562 		referenceFrame.allocLevel(0);
563 
564 		const vk::VkOffset3D				zeroOffset = { 0, 0, 0 };
565 		const tcu::ConstPixelBufferAccess	renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
566 			vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
567 
568 		for (int i = 0; i < WIDTH; ++i) {
569 			for (int j = 0; j < HEIGHT; ++j) {
570 				const tcu::Vec4 pixel = renderedFrame.getPixel(i, j);
571 				if (pixel != tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)) {
572 					return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Image verification failed");
573 				}
574 			}
575 		}
576 		return tcu::TestStatus(QP_TEST_RESULT_PASS, "Image verification passed");
577 	}
578 };
579 
580 class LineTestInstance : public DiscardTestInstance
581 {
582 public:
LineTestInstance(Context & context,vk::PipelineConstructionType pipelineConstructionType,const char * vertexShaderName,const char * fragmentShaderName)583 	LineTestInstance(Context& context, vk::PipelineConstructionType pipelineConstructionType, const char* vertexShaderName, const char* fragmentShaderName)
584 		: DiscardTestInstance(context, pipelineConstructionType, vertexShaderName, fragmentShaderName, pickSupportedStencilFormat(context.getInstanceInterface(), context.getPhysicalDevice()))
585 	{
586 		m_dynamicStates = { vk::VK_DYNAMIC_STATE_LINE_WIDTH };
587 		DynamicStateBaseClass::initialize();
588 	}
589 
setDynamicState(void)590 	virtual void setDynamicState(void) {
591 		m_vk.cmdSetLineWidth(*m_cmdBuffer, 1.0f);
592 	}
593 
verifyResults(void)594 	virtual tcu::TestStatus verifyResults(void) {
595 		const vk::VkQueue	queue = m_context.getUniversalQueue();
596 		tcu::Texture2D		referenceFrame(vk::mapVkFormat(m_depthStencilAttachmentFormat), WIDTH, HEIGHT);
597 		referenceFrame.allocLevel(0);
598 
599 		const vk::VkOffset3D				zeroOffset = { 0, 0, 0 };
600 		const tcu::ConstPixelBufferAccess	renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
601 			vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
602 
603 		for (int i = 0; i < WIDTH; ++i) {
604 			for (int j = 0; j < HEIGHT; ++j) {
605 				const tcu::Vec4 pixel = renderedFrame.getPixel(i, j);
606 				if (pixel != tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)) {
607 					return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Image verification failed");
608 				}
609 			}
610 		}
611 		return tcu::TestStatus(QP_TEST_RESULT_PASS, "Image verification passed");
612 	}
613 };
614 
615 class DiscardTestCase : public vkt::TestCase
616 {
617 public:
DiscardTestCase(tcu::TestContext & context,const char * name,vk::PipelineConstructionType pipelineConstructionType,TestDynamicStateDiscard testCase)618 	DiscardTestCase (tcu::TestContext& context, const char* name, vk::PipelineConstructionType pipelineConstructionType, TestDynamicStateDiscard testCase)
619 		: TestCase	(context, name)
620 		, m_pipelineConstructionType(pipelineConstructionType)
621 		, m_testCase(testCase)
622 		, m_depthBounds(false)
623 	{
624 	}
625 
checkSupport(Context & context) const626 	virtual void	checkSupport(Context& context) const
627 	{
628 		checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), m_pipelineConstructionType);
629 	}
630 
createInstance(Context & context) const631 	TestInstance* createInstance(Context& context) const
632 	{
633 		switch (m_testCase) {
634 		case TEST_STENCIL:
635 			return new StencilTestInstance(context, m_pipelineConstructionType, "discard.vert", "discard.frag");
636 		case TEST_VIEWPORT:
637 			return new ViewportTestInstance(context, m_pipelineConstructionType, "discard.vert", "discard.frag");
638 		case TEST_SCISSOR:
639 			return new ScissorTestInstance(context, m_pipelineConstructionType, "discard.vert", "discard.frag");
640 		case TEST_DEPTH:
641 			return new DepthTestInstance(context, m_pipelineConstructionType, "discard.vert", "discard.frag");
642 		case TEST_BLEND_CONSTANTS:
643 			return new BlendTestInstance(context, m_pipelineConstructionType, "discard.vert", "discard.frag");
644 		case TEST_LINE_WIDTH:
645 			return new LineTestInstance(context, m_pipelineConstructionType, "discard.vert", "discard.frag");
646 		default:
647 			break;
648 		}
649 		DE_ASSERT(false);
650 		return nullptr;
651 	}
652 
initPrograms(vk::SourceCollections & programCollection) const653 	virtual void initPrograms(vk::SourceCollections& programCollection) const
654 	{
655 		std::ostringstream vert;
656 		vert
657 			<< "#version 450\n"
658 			<< "\n"
659 			<< "layout(location = 0) in vec4 in_position;"
660 			<< "layout(location = 1) in vec4 in_color;"
661 			<< "\n"
662 			<< "layout(location = 0) out vec4 out_color;"
663 			<< "out gl_PerVertex { vec4 gl_Position; };"
664 			<< "\n"
665 			<< "void main ()\n"
666 			<< "{\n"
667 			<< "	gl_Position = in_position;\n"
668 			<< "	out_color = in_color;\n"
669 			<< "}\n";
670 
671 		programCollection.glslSources.add("discard.vert") << glu::VertexSource(vert.str());
672 
673 		std::ostringstream frag;
674 		frag
675 			<< "#version 450\n"
676 			<< "\n"
677 			<< "layout (set=0, binding=0, std140) uniform InputBlock {\n"
678 			<< "	int discard_all;\n"
679 			<< "} unif;\n"
680 			<< "\n"
681 			<< "layout (location = 0) in vec4 in_color;"
682 			<< "\n"
683 			<< "layout (location = 0) out vec4 color;"
684 			<< "\n"
685 			<< "void main ()\n"
686 			<< "{\n"
687 			<< "	if (unif.discard_all == 0) {\n"
688 			<< "		discard;\n"
689 			<< "	}\n"
690 			<< "	color = in_color;\n"
691 			<< "}\n";
692 
693 		programCollection.glslSources.add("discard.frag") << glu::FragmentSource(frag.str());
694 	}
695 
696 protected:
697 	vk::PipelineConstructionType	m_pipelineConstructionType;
698 	TestDynamicStateDiscard			m_testCase;
699 	VkBool32						m_depthBounds;
700 };
701 
DynamicStateDiscardTests(tcu::TestContext & testCtx,vk::PipelineConstructionType pipelineConstructionType)702 DynamicStateDiscardTests::DynamicStateDiscardTests (tcu::TestContext& testCtx, vk::PipelineConstructionType pipelineConstructionType)
703 	: TestCaseGroup					(testCtx, "discard")
704 	, m_pipelineConstructionType	(pipelineConstructionType)
705 {
706 	/* Left blank on purpose */
707 }
708 
~DynamicStateDiscardTests()709 DynamicStateDiscardTests::~DynamicStateDiscardTests ()
710 {
711 }
712 
init(void)713 void DynamicStateDiscardTests::init (void)
714 {
715 	// Use dynamic stencil with discard
716 	addChild(new DiscardTestCase(m_testCtx, "stencil", m_pipelineConstructionType, TestDynamicStateDiscard::TEST_STENCIL));
717 	// Use dynamic viewport with discard
718 	addChild(new DiscardTestCase(m_testCtx, "viewport", m_pipelineConstructionType, TestDynamicStateDiscard::TEST_VIEWPORT));
719 	// Use dynamic scissor with discard
720 	addChild(new DiscardTestCase(m_testCtx, "scissor", m_pipelineConstructionType, TestDynamicStateDiscard::TEST_SCISSOR));
721 	// Use dynamic depth with discard
722 	addChild(new DiscardTestCase(m_testCtx, "depth", m_pipelineConstructionType, TestDynamicStateDiscard::TEST_DEPTH));
723 	// Use dynamic blend constants with discard
724 	addChild(new DiscardTestCase(m_testCtx, "blend", m_pipelineConstructionType, TestDynamicStateDiscard::TEST_BLEND_CONSTANTS));
725 	// Use dynamic line width with discard
726 	addChild(new DiscardTestCase(m_testCtx, "line", m_pipelineConstructionType, TestDynamicStateDiscard::TEST_LINE_WIDTH));
727 }
728 
729 } // DynamicState
730 } // vkt
731