1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2018 The Khronos Group Inc.
6 * Copyright (c) 2018 Danylo Piliaiev <danylo.piliaiev@gmail.com>
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 Conditional Rendering Test Utils
23 *//*--------------------------------------------------------------------*/
24
25#include "vktConditionalRenderingTestUtil.hpp"
26#include "vktDrawCreateInfoUtil.hpp"
27#include "vkQueryUtil.hpp"
28#include "vkCmdUtil.hpp"
29#include "vkTypeUtil.hpp"
30
31namespace vkt
32{
33namespace conditional
34{
35
36void checkConditionalRenderingCapabilities (vkt::Context& context, const ConditionalData& data)
37{
38	context.requireDeviceFunctionality("VK_EXT_conditional_rendering");
39
40	const auto& conditionalRenderingFeatures = context.getConditionalRenderingFeaturesEXT();
41
42	if (conditionalRenderingFeatures.conditionalRendering == VK_FALSE)
43		TCU_FAIL("conditionalRendering feature not supported but VK_EXT_conditional_rendering present");
44
45	if (data.conditionInherited && !conditionalRenderingFeatures.inheritedConditionalRendering)
46		TCU_THROW(NotSupportedError, "Device does not support inherited conditional rendering");
47}
48
49de::SharedPtr<Draw::Buffer>	createConditionalRenderingBuffer (vkt::Context& context, const ConditionalData& data)
50{
51	const auto&	vk			= context.getDeviceInterface();
52	const auto	device		= context.getDevice();
53	const auto	queueIndex	= context.getUniversalQueueFamilyIndex();
54	const auto	queue		= context.getUniversalQueue();
55	auto&		alloc		= context.getDefaultAllocator();
56
57	// When padding the condition value, it will be surounded by two additional values with nonzero bytes in them.
58	// When choosing to apply an offset to the allocation, the offset will be four times the size of the condition variable.
59	const auto					bufferSize	= static_cast<vk::VkDeviceSize>(sizeof(data.conditionValue)) * (data.padConditionValue ? 3ull : 1ull);
60	const auto					dataOffset	= static_cast<vk::VkDeviceSize>(data.padConditionValue ? sizeof(data.conditionValue) : 0);
61	const auto					allocOffset	= static_cast<vk::VkDeviceSize>(sizeof(data.conditionValue) * (data.allocationOffset ? 4u : 0u));
62
63	// Create host-visible buffer. This may be the final buffer or only a staging buffer.
64	const auto					hostUsage	= ((data.memoryType == HOST) ? vk::VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT : vk::VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
65	de::SharedPtr<Draw::Buffer>	hostBuffer	= Draw::Buffer::createAndAlloc(vk, device,
66												Draw::BufferCreateInfo(bufferSize, hostUsage),
67												alloc,
68												vk::MemoryRequirement::HostVisible,
69												allocOffset);
70
71	// Copy data to host buffer.
72	deUint8* conditionBufferPtr = reinterpret_cast<deUint8*>(hostBuffer->getHostPtr());
73	deMemset(conditionBufferPtr, 1, static_cast<size_t>(bufferSize));
74	deMemcpy(conditionBufferPtr + dataOffset, &data.conditionValue, sizeof(data.conditionValue));
75	vk::flushAlloc(vk, context.getDevice(), hostBuffer->getBoundMemory());
76
77	// Return host buffer if appropriate.
78	if (data.memoryType == HOST)
79		return hostBuffer;
80
81	// Create and return device-local buffer otherwise, after copying host-visible buffer contents to it.
82	const auto					deviceLocalUsage	= (vk::VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT | vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT);
83	de::SharedPtr<Draw::Buffer>	deviceLocalBuffer	= Draw::Buffer::createAndAlloc(vk, device,
84														Draw::BufferCreateInfo(bufferSize, deviceLocalUsage),
85														alloc,
86														vk::MemoryRequirement::Local,
87														allocOffset);
88
89	const auto cmdPool		= vk::makeCommandPool(vk, device, queueIndex);
90	const auto cmdBuffer	= vk::allocateCommandBuffer (vk, device, cmdPool.get(), vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
91	const auto copyInfo		= vk::makeBufferCopy(0ull, 0ull, bufferSize);
92
93	vk::beginCommandBuffer(vk, *cmdBuffer);
94	vk.cmdCopyBuffer(*cmdBuffer, hostBuffer->object(), deviceLocalBuffer->object(), 1, &copyInfo);
95	vk::endCommandBuffer(vk, *cmdBuffer);
96	vk::submitCommandsAndWait(vk, device, queue, *cmdBuffer);
97
98	return deviceLocalBuffer;
99}
100
101void beginConditionalRendering (const vk::DeviceInterface& vk, vk::VkCommandBuffer cmdBuffer, Draw::Buffer& buffer, const ConditionalData& data)
102{
103	vk::VkConditionalRenderingBeginInfoEXT conditionalRenderingBeginInfo;
104	conditionalRenderingBeginInfo.sType		= vk::VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT;
105	conditionalRenderingBeginInfo.pNext		= nullptr;
106	conditionalRenderingBeginInfo.buffer	= buffer.object();
107	conditionalRenderingBeginInfo.offset	= static_cast<vk::VkDeviceSize>(data.padConditionValue ? sizeof(data.conditionValue) : 0u);
108	conditionalRenderingBeginInfo.flags		= data.conditionInverted ? vk::VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT : 0;
109
110	vk.cmdBeginConditionalRenderingEXT(cmdBuffer, &conditionalRenderingBeginInfo);
111}
112
113std::ostream& operator<< (std::ostream& str, ConditionalData const& c)
114{
115	const bool conditionEnabled = c.conditionInPrimaryCommandBuffer || c.conditionInSecondaryCommandBuffer;
116	str << (conditionEnabled ? "condition" : "no_condition");
117	str << (c.memoryType ? "_host_memory" : "_local_memory");
118
119
120	if (c.conditionInSecondaryCommandBuffer || !conditionEnabled)
121	{
122		str << "_secondary_buffer";
123	}
124
125	if (c.conditionInherited)
126	{
127		str << "_inherited";
128	}
129
130	str << "_" << (c.expectCommandExecution ? "expect_execution" : "expect_noop");
131
132	if (c.conditionInverted)
133	{
134		str << "_inverted";
135	}
136
137	if (c.padConditionValue)
138	{
139		str << "_padded";
140	}
141
142	if (c.clearInRenderPass)
143	{
144		str << "_rp_clear";
145	}
146
147	return str;
148}
149
150}   // conditional
151}	// vkt
152