1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2015 The Khronos Group Inc.
6 * Copyright (c) 2015 Intel Corporation
7 * Copyright (c) 2023 LunarG, Inc.
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 Tests - Base Class
25 *//*--------------------------------------------------------------------*/
26
27#include "vktDynamicStateBaseClass.hpp"
28
29#include "vkPrograms.hpp"
30#include "vkTypeUtil.hpp"
31#include "vkCmdUtil.hpp"
32#include "vkObjUtil.hpp"
33#include "vkBuilderUtil.hpp"
34#include "vkBarrierUtil.hpp"
35
36namespace vkt
37{
38namespace DynamicState
39{
40
41using namespace Draw;
42
43DynamicStateBaseClass::DynamicStateBaseClass (Context& context,
44											  vk::PipelineConstructionType pipelineConstructionType,
45											  const char* vertexShaderName,
46											  const char* fragmentShaderName,
47											  const char* meshShaderName)
48	: TestInstance					(context)
49	, m_pipelineConstructionType	(pipelineConstructionType)
50	, m_colorAttachmentFormat		(vk::VK_FORMAT_R8G8B8A8_UNORM)
51	, m_topology					(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
52	, m_vk							(context.getDeviceInterface())
53	, m_pipeline					(context.getInstanceInterface(), context.getDeviceInterface(), context.getPhysicalDevice(), context.getDevice(), context.getDeviceExtensions(), pipelineConstructionType)
54	, m_vertexShaderName			(vertexShaderName ? vertexShaderName : "")
55	, m_fragmentShaderName			(fragmentShaderName)
56	, m_meshShaderName				(meshShaderName ? meshShaderName : "")
57	, m_isMesh						(meshShaderName != nullptr)
58{
59	// We must provide either the mesh shader or the vertex shader.
60	DE_ASSERT(static_cast<bool>(vertexShaderName) != static_cast<bool>(meshShaderName));
61}
62
63void DynamicStateBaseClass::initialize (void)
64{
65	const vk::VkDevice						device				= m_context.getDevice();
66	const deUint32							queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
67	const auto								vertDescType		= (m_isMesh ? vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER : vk::VK_DESCRIPTOR_TYPE_MAX_ENUM);
68	std::vector<vk::VkPushConstantRange>	pcRanges;
69
70	// The mesh shading pipeline will contain a set with vertex data.
71#ifndef CTS_USES_VULKANSC
72	if (m_isMesh)
73	{
74		vk::DescriptorSetLayoutBuilder	setLayoutBuilder;
75		vk::DescriptorPoolBuilder		poolBuilder;
76
77		setLayoutBuilder.addSingleBinding(vertDescType, vk::VK_SHADER_STAGE_MESH_BIT_EXT);
78		m_meshSetLayout = setLayoutBuilder.build(m_vk, device);
79
80		poolBuilder.addType(vertDescType);
81		m_descriptorPool = poolBuilder.build(m_vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
82
83		m_descriptorSet = vk::makeDescriptorSet(m_vk, device, m_descriptorPool.get(), m_meshSetLayout.get());
84		pcRanges.push_back(vk::makePushConstantRange(vk::VK_SHADER_STAGE_MESH_BIT_EXT, 0u, static_cast<uint32_t>(sizeof(uint32_t))));
85	}
86#endif // CTS_USES_VULKANSC
87
88	std::vector<vk::VkDescriptorSetLayout> rawSetLayouts;
89
90	if (m_meshSetLayout)
91		rawSetLayouts.push_back(m_meshSetLayout.get());
92
93	if (m_otherSetLayout)
94		rawSetLayouts.push_back(m_otherSetLayout.get());
95
96	m_pipelineLayout = vk::PipelineLayoutWrapper(m_pipelineConstructionType, m_vk, device, de::sizeU32(rawSetLayouts), de::dataOrNull(rawSetLayouts), de::sizeU32(pcRanges), de::dataOrNull(pcRanges));
97
98	const vk::VkExtent3D targetImageExtent = { WIDTH, HEIGHT, 1 };
99	const ImageCreateInfo targetImageCreateInfo(vk::VK_IMAGE_TYPE_2D, m_colorAttachmentFormat, targetImageExtent, 1, 1, vk::VK_SAMPLE_COUNT_1_BIT,
100												vk::VK_IMAGE_TILING_OPTIMAL, vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT | vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT);
101
102	m_colorTargetImage = Image::createAndAlloc(m_vk, device, targetImageCreateInfo, m_context.getDefaultAllocator(), m_context.getUniversalQueueFamilyIndex());
103
104	const ImageViewCreateInfo colorTargetViewInfo(m_colorTargetImage->object(), vk::VK_IMAGE_VIEW_TYPE_2D, m_colorAttachmentFormat);
105	m_colorTargetView = vk::createImageView(m_vk, device, &colorTargetViewInfo);
106
107	const vk::VkVertexInputBindingDescription vertexInputBindingDescription =
108	{
109		0,
110		(deUint32)sizeof(tcu::Vec4) * 2,
111		vk::VK_VERTEX_INPUT_RATE_VERTEX,
112	};
113
114	const vk::VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] =
115	{
116		{
117			0u,
118			0u,
119			vk::VK_FORMAT_R32G32B32A32_SFLOAT,
120			0u
121		},
122		{
123			1u,
124			0u,
125			vk::VK_FORMAT_R32G32B32A32_SFLOAT,
126			(deUint32)(sizeof(float)* 4),
127		}
128	};
129
130	m_vertexInputState = PipelineCreateInfo::VertexInputState(
131		1,
132		&vertexInputBindingDescription,
133		2,
134		vertexInputAttributeDescriptions);
135
136	const vk::VkDeviceSize			dataSize	= de::dataSize(m_data);
137	const vk::VkBufferUsageFlags	bufferUsage	= (m_isMesh ? vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT : vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
138	m_vertexBuffer = Buffer::createAndAlloc(m_vk, device, BufferCreateInfo(dataSize, bufferUsage),
139											m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
140
141	deUint8* ptr = reinterpret_cast<unsigned char *>(m_vertexBuffer->getBoundMemory().getHostPtr());
142	deMemcpy(ptr, &m_data[0], (size_t)dataSize);
143
144	vk::flushAlloc(m_vk, device, m_vertexBuffer->getBoundMemory());
145
146	// Update descriptor set for mesh shaders.
147	if (m_isMesh)
148	{
149		vk::DescriptorSetUpdateBuilder	updateBuilder;
150		const auto						location		= vk::DescriptorSetUpdateBuilder::Location::binding(0u);
151		const auto						bufferInfo		= vk::makeDescriptorBufferInfo(m_vertexBuffer->object(), 0ull, dataSize);
152
153		updateBuilder.writeSingle(m_descriptorSet.get(), location, vertDescType, &bufferInfo);
154		updateBuilder.update(m_vk, device);
155	}
156
157	const CmdPoolCreateInfo cmdPoolCreateInfo(queueFamilyIndex);
158	m_cmdPool = vk::createCommandPool(m_vk, device, &cmdPoolCreateInfo);
159
160	const vk::VkCommandBufferAllocateInfo cmdBufferAllocateInfo =
161	{
162		vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,	// VkStructureType			sType;
163		DE_NULL,											// const void*				pNext;
164		*m_cmdPool,											// VkCommandPool			commandPool;
165		vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY,				// VkCommandBufferLevel		level;
166		1u,													// deUint32					bufferCount;
167	};
168	m_cmdBuffer = vk::allocateCommandBuffer(m_vk, device, &cmdBufferAllocateInfo);
169
170	initRenderPass(device);
171	initFramebuffer(device);
172	initPipeline(device);
173}
174
175
176void DynamicStateBaseClass::initRenderPass (const vk::VkDevice device)
177{
178	RenderPassCreateInfo renderPassCreateInfo;
179	renderPassCreateInfo.addAttachment(AttachmentDescription(m_colorAttachmentFormat,
180		vk::VK_SAMPLE_COUNT_1_BIT,
181		vk::VK_ATTACHMENT_LOAD_OP_LOAD,
182		vk::VK_ATTACHMENT_STORE_OP_STORE,
183		vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
184		vk::VK_ATTACHMENT_STORE_OP_STORE,
185		vk::VK_IMAGE_LAYOUT_GENERAL,
186		vk::VK_IMAGE_LAYOUT_GENERAL));
187
188	const vk::VkAttachmentReference colorAttachmentReference =
189	{
190		0,
191		vk::VK_IMAGE_LAYOUT_GENERAL
192	};
193
194	renderPassCreateInfo.addSubpass(SubpassDescription(
195		vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
196		0,
197		0,
198		DE_NULL,
199		1,
200		&colorAttachmentReference,
201		DE_NULL,
202		AttachmentReference(),
203		0,
204		DE_NULL
205	)
206	);
207
208	m_renderPass = vk::RenderPassWrapper(m_pipelineConstructionType, m_vk, device, &renderPassCreateInfo);
209}
210
211void DynamicStateBaseClass::initFramebuffer (const vk::VkDevice device)
212{
213	std::vector<vk::VkImageView> colorAttachments(1);
214	colorAttachments[0] = *m_colorTargetView;
215
216	const FramebufferCreateInfo framebufferCreateInfo(*m_renderPass, colorAttachments, WIDTH, HEIGHT, 1);
217
218	m_renderPass.createFramebuffer(m_vk, device, &framebufferCreateInfo, m_colorTargetImage->object());
219}
220
221void DynamicStateBaseClass::initPipeline (const vk::VkDevice device)
222{
223	const PipelineCreateInfo::ColorBlendState				colorBlendState(1, &m_attachmentState);
224	const PipelineCreateInfo::RasterizerState				rasterizerState;
225	const PipelineCreateInfo::DepthStencilState             depthStencilState;
226	const PipelineCreateInfo::DynamicState					dynamicState;
227	const PipelineCreateInfo::MultiSampleState				multisampleState;
228
229	const auto&							binaries	= m_context.getBinaryCollection();
230	const vk::ShaderWrapper				ms			(m_isMesh ? vk::ShaderWrapper(m_vk, device, binaries.get(m_meshShaderName), 0) : vk::ShaderWrapper());
231	const vk::ShaderWrapper				vs			(m_isMesh ? vk::ShaderWrapper() : vk::ShaderWrapper(m_vk, device, binaries.get(m_vertexShaderName), 0));
232	const vk::ShaderWrapper				fs			(vk::ShaderWrapper(m_vk, device, binaries.get(m_fragmentShaderName), 0));
233	std::vector<vk::VkViewport>			viewports	{ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } };
234	std::vector<vk::VkRect2D>			scissors	{ { { 0u, 0u }, { 0u, 0u } }};
235
236	m_pipeline.setDefaultTopology(m_topology)
237			  .setDynamicState(static_cast<const vk::VkPipelineDynamicStateCreateInfo*>(&dynamicState));
238
239#ifndef CTS_USES_VULKANSC
240	if (m_isMesh)
241	{
242		m_pipeline
243			  .setupPreRasterizationMeshShaderState(viewports,
244													scissors,
245													m_pipelineLayout,
246													*m_renderPass,
247													0u,
248													vk::ShaderWrapper(),
249													ms,
250													static_cast<const vk::VkPipelineRasterizationStateCreateInfo*>(&rasterizerState));
251	}
252	else
253#endif // CTS_USES_VULKANSC
254	{
255		m_pipeline
256			  .setupVertexInputState(&m_vertexInputState)
257			  .setupPreRasterizationShaderState(viewports,
258												scissors,
259												m_pipelineLayout,
260												*m_renderPass,
261												0u,
262												vs,
263												static_cast<const vk::VkPipelineRasterizationStateCreateInfo*>(&rasterizerState));
264	}
265
266	m_pipeline.setupFragmentShaderState(m_pipelineLayout, *m_renderPass, 0u, fs, static_cast<const vk::VkPipelineDepthStencilStateCreateInfo*>(&depthStencilState), &multisampleState)
267			  .setupFragmentOutputState(*m_renderPass, 0u, static_cast<const vk::VkPipelineColorBlendStateCreateInfo*>(&colorBlendState), &multisampleState)
268			  .setMonolithicPipelineLayout(m_pipelineLayout)
269			  .buildPipeline();
270}
271
272tcu::TestStatus DynamicStateBaseClass::iterate (void)
273{
274	DE_ASSERT(false);
275	return tcu::TestStatus::fail("Implement iterate() method!");
276}
277
278void DynamicStateBaseClass::beginRenderPass (void)
279{
280	const vk::VkClearColorValue clearColor = { { 0.0f, 0.0f, 0.0f, 1.0f } };
281	beginRenderPassWithClearColor(clearColor);
282}
283
284void DynamicStateBaseClass::beginRenderPassWithClearColor(const vk::VkClearColorValue& clearColor, const bool skipBeginCmdBuffer, const bool previousTransfer)
285{
286	if (!skipBeginCmdBuffer)
287	{
288		beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
289	}
290
291	if (previousTransfer)
292	{
293		const auto transfer2Transfer = vk::makeMemoryBarrier(vk::VK_ACCESS_TRANSFER_WRITE_BIT, (vk::VK_ACCESS_TRANSFER_WRITE_BIT | vk::VK_ACCESS_TRANSFER_READ_BIT));
294		vk::cmdPipelineMemoryBarrier(m_vk, *m_cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, &transfer2Transfer);
295	}
296	else
297	{
298		initialTransitionColor2DImage(m_vk, *m_cmdBuffer, m_colorTargetImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
299									  vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT);
300	}
301
302	const ImageSubresourceRange subresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT);
303	m_vk.cmdClearColorImage(*m_cmdBuffer, m_colorTargetImage->object(),
304		vk::VK_IMAGE_LAYOUT_GENERAL, &clearColor, 1, &subresourceRange);
305
306	const vk::VkMemoryBarrier memBarrier =
307	{
308		vk::VK_STRUCTURE_TYPE_MEMORY_BARRIER,
309		DE_NULL,
310		vk::VK_ACCESS_TRANSFER_WRITE_BIT,
311		vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
312	};
313
314	m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
315		vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
316		0, 1, &memBarrier, 0, DE_NULL, 0, DE_NULL);
317
318	m_renderPass.begin(m_vk, *m_cmdBuffer, vk::makeRect2D(0, 0, WIDTH, HEIGHT));
319}
320
321void DynamicStateBaseClass::setDynamicViewportState (const deUint32 width, const deUint32 height)
322{
323	vk::VkViewport viewport = vk::makeViewport(tcu::UVec2(width, height));
324	vk::VkRect2D scissor = vk::makeRect2D(tcu::UVec2(width, height));
325	if (vk::isConstructionTypeShaderObject(m_pipelineConstructionType))
326	{
327#ifndef CTS_USES_VULKANSC
328		m_vk.cmdSetViewportWithCount(*m_cmdBuffer, 1, &viewport);
329		m_vk.cmdSetScissorWithCount(*m_cmdBuffer, 1, &scissor);
330#else
331		m_vk.cmdSetViewportWithCountEXT(*m_cmdBuffer, 1, &viewport);
332		m_vk.cmdSetScissorWithCountEXT(*m_cmdBuffer, 1, &scissor);
333#endif
334	}
335	else
336	{
337		m_vk.cmdSetViewport(*m_cmdBuffer, 0, 1, &viewport);
338		m_vk.cmdSetScissor(*m_cmdBuffer, 0, 1, &scissor);
339	}
340}
341
342void DynamicStateBaseClass::setDynamicViewportState (deUint32 viewportCount, const vk::VkViewport* pViewports, const vk::VkRect2D* pScissors)
343{
344	if (vk::isConstructionTypeShaderObject(m_pipelineConstructionType))
345	{
346#ifndef CTS_USES_VULKANSC
347		m_vk.cmdSetViewportWithCount(*m_cmdBuffer, viewportCount, pViewports);
348		m_vk.cmdSetScissorWithCount(*m_cmdBuffer, viewportCount, pScissors);
349#else
350		m_vk.cmdSetViewportWithCountEXT(*m_cmdBuffer, viewportCount, pViewports);
351		m_vk.cmdSetScissorWithCountEXT(*m_cmdBuffer, viewportCount, pScissors);
352#endif
353	}
354	else
355	{
356		m_vk.cmdSetViewport(*m_cmdBuffer, 0, viewportCount, pViewports);
357		m_vk.cmdSetScissor(*m_cmdBuffer, 0, viewportCount, pScissors);
358	}
359}
360
361void DynamicStateBaseClass::setDynamicRasterizationState (const float lineWidth,
362														 const float depthBiasConstantFactor,
363														 const float depthBiasClamp,
364														 const float depthBiasSlopeFactor)
365{
366	m_vk.cmdSetLineWidth(*m_cmdBuffer, lineWidth);
367	m_vk.cmdSetDepthBias(*m_cmdBuffer, depthBiasConstantFactor, depthBiasClamp, depthBiasSlopeFactor);
368}
369
370void DynamicStateBaseClass::setDynamicBlendState (const float const1, const float const2, const float const3, const float const4)
371{
372	float blendConstantsants[4] = { const1, const2, const3, const4 };
373	m_vk.cmdSetBlendConstants(*m_cmdBuffer, blendConstantsants);
374}
375
376void DynamicStateBaseClass::setDynamicDepthStencilState (const float	minDepthBounds,
377														 const float	maxDepthBounds,
378														 const deUint32 stencilFrontCompareMask,
379														 const deUint32 stencilFrontWriteMask,
380														 const deUint32 stencilFrontReference,
381														 const deUint32 stencilBackCompareMask,
382														 const deUint32 stencilBackWriteMask,
383														 const deUint32 stencilBackReference)
384{
385	m_vk.cmdSetDepthBounds(*m_cmdBuffer, minDepthBounds, maxDepthBounds);
386	m_vk.cmdSetStencilCompareMask(*m_cmdBuffer, vk::VK_STENCIL_FACE_FRONT_BIT, stencilFrontCompareMask);
387	m_vk.cmdSetStencilWriteMask(*m_cmdBuffer, vk::VK_STENCIL_FACE_FRONT_BIT, stencilFrontWriteMask);
388	m_vk.cmdSetStencilReference(*m_cmdBuffer, vk::VK_STENCIL_FACE_FRONT_BIT, stencilFrontReference);
389	m_vk.cmdSetStencilCompareMask(*m_cmdBuffer, vk::VK_STENCIL_FACE_BACK_BIT, stencilBackCompareMask);
390	m_vk.cmdSetStencilWriteMask(*m_cmdBuffer, vk::VK_STENCIL_FACE_BACK_BIT, stencilBackWriteMask);
391	m_vk.cmdSetStencilReference(*m_cmdBuffer, vk::VK_STENCIL_FACE_BACK_BIT, stencilBackReference);
392}
393
394#ifndef CTS_USES_VULKANSC
395void DynamicStateBaseClass::pushVertexOffset (const uint32_t				vertexOffset,
396											  const vk::VkPipelineLayout	pipelineLayout,
397											  const vk::VkShaderStageFlags	stageFlags)
398{
399	m_vk.cmdPushConstants(*m_cmdBuffer, pipelineLayout, stageFlags, 0u, static_cast<uint32_t>(sizeof(uint32_t)), &vertexOffset);
400}
401#endif // CTS_USES_VULKANSC
402
403} // DynamicState
404} // vkt
405