1cb93a386Sopenharmony_ci// Copyright 2018 The SwiftShader Authors. All Rights Reserved.
2cb93a386Sopenharmony_ci//
3cb93a386Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License");
4cb93a386Sopenharmony_ci// you may not use this file except in compliance with the License.
5cb93a386Sopenharmony_ci// You may obtain a copy of the License at
6cb93a386Sopenharmony_ci//
7cb93a386Sopenharmony_ci//    http://www.apache.org/licenses/LICENSE-2.0
8cb93a386Sopenharmony_ci//
9cb93a386Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software
10cb93a386Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS,
11cb93a386Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12cb93a386Sopenharmony_ci// See the License for the specific language governing permissions and
13cb93a386Sopenharmony_ci// limitations under the License.
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_ci#include "VkQueryPool.hpp"
16cb93a386Sopenharmony_ci
17cb93a386Sopenharmony_ci#include <chrono>
18cb93a386Sopenharmony_ci#include <cstring>
19cb93a386Sopenharmony_ci#include <new>
20cb93a386Sopenharmony_ci
21cb93a386Sopenharmony_cinamespace vk {
22cb93a386Sopenharmony_ci
23cb93a386Sopenharmony_ciQuery::Query(VkQueryType type)
24cb93a386Sopenharmony_ci    : finished(marl::Event::Mode::Manual)
25cb93a386Sopenharmony_ci    , state(UNAVAILABLE)
26cb93a386Sopenharmony_ci    , type(type)
27cb93a386Sopenharmony_ci    , value(0)
28cb93a386Sopenharmony_ci{}
29cb93a386Sopenharmony_ci
30cb93a386Sopenharmony_civoid Query::reset()
31cb93a386Sopenharmony_ci{
32cb93a386Sopenharmony_ci	finished.clear();
33cb93a386Sopenharmony_ci	auto prevState = state.exchange(UNAVAILABLE);
34cb93a386Sopenharmony_ci	ASSERT(prevState != ACTIVE);
35cb93a386Sopenharmony_ci	value = 0;
36cb93a386Sopenharmony_ci}
37cb93a386Sopenharmony_ci
38cb93a386Sopenharmony_civoid Query::start()
39cb93a386Sopenharmony_ci{
40cb93a386Sopenharmony_ci	auto prevState = state.exchange(ACTIVE);
41cb93a386Sopenharmony_ci	ASSERT(prevState != FINISHED);  // Must be reset first
42cb93a386Sopenharmony_ci	wg.add();
43cb93a386Sopenharmony_ci}
44cb93a386Sopenharmony_ci
45cb93a386Sopenharmony_civoid Query::finish()
46cb93a386Sopenharmony_ci{
47cb93a386Sopenharmony_ci	if(wg.done())
48cb93a386Sopenharmony_ci	{
49cb93a386Sopenharmony_ci		auto prevState = state.exchange(FINISHED);
50cb93a386Sopenharmony_ci		ASSERT(prevState == ACTIVE);
51cb93a386Sopenharmony_ci		finished.signal();
52cb93a386Sopenharmony_ci	}
53cb93a386Sopenharmony_ci}
54cb93a386Sopenharmony_ci
55cb93a386Sopenharmony_ciQuery::Data Query::getData() const
56cb93a386Sopenharmony_ci{
57cb93a386Sopenharmony_ci	Data out;
58cb93a386Sopenharmony_ci	out.state = state;
59cb93a386Sopenharmony_ci	out.value = value;
60cb93a386Sopenharmony_ci	return out;
61cb93a386Sopenharmony_ci}
62cb93a386Sopenharmony_ci
63cb93a386Sopenharmony_ciVkQueryType Query::getType() const
64cb93a386Sopenharmony_ci{
65cb93a386Sopenharmony_ci	return type;
66cb93a386Sopenharmony_ci}
67cb93a386Sopenharmony_ci
68cb93a386Sopenharmony_civoid Query::wait()
69cb93a386Sopenharmony_ci{
70cb93a386Sopenharmony_ci	finished.wait();
71cb93a386Sopenharmony_ci}
72cb93a386Sopenharmony_ci
73cb93a386Sopenharmony_civoid Query::set(int64_t v)
74cb93a386Sopenharmony_ci{
75cb93a386Sopenharmony_ci	value = v;
76cb93a386Sopenharmony_ci}
77cb93a386Sopenharmony_ci
78cb93a386Sopenharmony_civoid Query::add(int64_t v)
79cb93a386Sopenharmony_ci{
80cb93a386Sopenharmony_ci	value += v;
81cb93a386Sopenharmony_ci}
82cb93a386Sopenharmony_ci
83cb93a386Sopenharmony_ciQueryPool::QueryPool(const VkQueryPoolCreateInfo *pCreateInfo, void *mem)
84cb93a386Sopenharmony_ci    : pool(reinterpret_cast<Query *>(mem))
85cb93a386Sopenharmony_ci    , type(pCreateInfo->queryType)
86cb93a386Sopenharmony_ci    , count(pCreateInfo->queryCount)
87cb93a386Sopenharmony_ci{
88cb93a386Sopenharmony_ci	// According to the Vulkan 1.2 spec, section 30. Features:
89cb93a386Sopenharmony_ci	// "pipelineStatisticsQuery specifies whether the pipeline statistics
90cb93a386Sopenharmony_ci	//  queries are supported. If this feature is not enabled, queries of
91cb93a386Sopenharmony_ci	//  type VK_QUERY_TYPE_PIPELINE_STATISTICS cannot be created, and
92cb93a386Sopenharmony_ci	//  none of the VkQueryPipelineStatisticFlagBits bits can be set in the
93cb93a386Sopenharmony_ci	//  pipelineStatistics member of the VkQueryPoolCreateInfo structure."
94cb93a386Sopenharmony_ci	if(type == VK_QUERY_TYPE_PIPELINE_STATISTICS)
95cb93a386Sopenharmony_ci	{
96cb93a386Sopenharmony_ci		UNSUPPORTED("VkPhysicalDeviceFeatures::pipelineStatisticsQuery");
97cb93a386Sopenharmony_ci	}
98cb93a386Sopenharmony_ci
99cb93a386Sopenharmony_ci	// Construct all queries
100cb93a386Sopenharmony_ci	for(uint32_t i = 0; i < count; i++)
101cb93a386Sopenharmony_ci	{
102cb93a386Sopenharmony_ci		new(&pool[i]) Query(type);
103cb93a386Sopenharmony_ci	}
104cb93a386Sopenharmony_ci}
105cb93a386Sopenharmony_ci
106cb93a386Sopenharmony_civoid QueryPool::destroy(const VkAllocationCallbacks *pAllocator)
107cb93a386Sopenharmony_ci{
108cb93a386Sopenharmony_ci	for(uint32_t i = 0; i < count; i++)
109cb93a386Sopenharmony_ci	{
110cb93a386Sopenharmony_ci		pool[i].~Query();
111cb93a386Sopenharmony_ci	}
112cb93a386Sopenharmony_ci
113cb93a386Sopenharmony_ci	vk::freeHostMemory(pool, pAllocator);
114cb93a386Sopenharmony_ci}
115cb93a386Sopenharmony_ci
116cb93a386Sopenharmony_cisize_t QueryPool::ComputeRequiredAllocationSize(const VkQueryPoolCreateInfo *pCreateInfo)
117cb93a386Sopenharmony_ci{
118cb93a386Sopenharmony_ci	return sizeof(Query) * pCreateInfo->queryCount;
119cb93a386Sopenharmony_ci}
120cb93a386Sopenharmony_ci
121cb93a386Sopenharmony_ciVkResult QueryPool::getResults(uint32_t firstQuery, uint32_t queryCount, size_t dataSize,
122cb93a386Sopenharmony_ci                               void *pData, VkDeviceSize stride, VkQueryResultFlags flags) const
123cb93a386Sopenharmony_ci{
124cb93a386Sopenharmony_ci	// dataSize must be large enough to contain the result of each query
125cb93a386Sopenharmony_ci	ASSERT(static_cast<size_t>(stride * queryCount) <= dataSize);
126cb93a386Sopenharmony_ci
127cb93a386Sopenharmony_ci	// The sum of firstQuery and queryCount must be less than or equal to the number of queries
128cb93a386Sopenharmony_ci	ASSERT((firstQuery + queryCount) <= count);
129cb93a386Sopenharmony_ci
130cb93a386Sopenharmony_ci	VkResult result = VK_SUCCESS;
131cb93a386Sopenharmony_ci	uint8_t *data = static_cast<uint8_t *>(pData);
132cb93a386Sopenharmony_ci	for(uint32_t i = firstQuery; i < (firstQuery + queryCount); i++, data += stride)
133cb93a386Sopenharmony_ci	{
134cb93a386Sopenharmony_ci		auto &query = pool[i];
135cb93a386Sopenharmony_ci
136cb93a386Sopenharmony_ci		if(flags & VK_QUERY_RESULT_WAIT_BIT)  // Must wait for query to finish
137cb93a386Sopenharmony_ci		{
138cb93a386Sopenharmony_ci			query.wait();
139cb93a386Sopenharmony_ci		}
140cb93a386Sopenharmony_ci
141cb93a386Sopenharmony_ci		const auto current = query.getData();
142cb93a386Sopenharmony_ci
143cb93a386Sopenharmony_ci		// "If VK_QUERY_RESULT_WAIT_BIT and VK_QUERY_RESULT_PARTIAL_BIT are both not set
144cb93a386Sopenharmony_ci		//  then no result values are written to pData for queries that are in the
145cb93a386Sopenharmony_ci		//  unavailable state at the time of the call, and vkGetQueryPoolResults returns
146cb93a386Sopenharmony_ci		//  VK_NOT_READY. However, availability state is still written to pData for those
147cb93a386Sopenharmony_ci		//  queries if VK_QUERY_RESULT_WITH_AVAILABILITY_BIT is set."
148cb93a386Sopenharmony_ci		bool writeResult = true;
149cb93a386Sopenharmony_ci		if(current.state == Query::ACTIVE || (current.state == Query::UNAVAILABLE && !(flags & VK_QUERY_RESULT_WAIT_BIT)))
150cb93a386Sopenharmony_ci		{
151cb93a386Sopenharmony_ci			result = VK_NOT_READY;
152cb93a386Sopenharmony_ci			writeResult = (flags & VK_QUERY_RESULT_PARTIAL_BIT);  // Allow writing partial results
153cb93a386Sopenharmony_ci		}
154cb93a386Sopenharmony_ci
155cb93a386Sopenharmony_ci		if(flags & VK_QUERY_RESULT_64_BIT)
156cb93a386Sopenharmony_ci		{
157cb93a386Sopenharmony_ci			uint64_t *result64 = reinterpret_cast<uint64_t *>(data);
158cb93a386Sopenharmony_ci			if(writeResult)
159cb93a386Sopenharmony_ci			{
160cb93a386Sopenharmony_ci				result64[0] = current.value;
161cb93a386Sopenharmony_ci			}
162cb93a386Sopenharmony_ci			if(flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT)  // Output query availablity
163cb93a386Sopenharmony_ci			{
164cb93a386Sopenharmony_ci				result64[1] = current.state;
165cb93a386Sopenharmony_ci			}
166cb93a386Sopenharmony_ci		}
167cb93a386Sopenharmony_ci		else
168cb93a386Sopenharmony_ci		{
169cb93a386Sopenharmony_ci			uint32_t *result32 = reinterpret_cast<uint32_t *>(data);
170cb93a386Sopenharmony_ci			if(writeResult)
171cb93a386Sopenharmony_ci			{
172cb93a386Sopenharmony_ci				result32[0] = static_cast<uint32_t>(current.value);
173cb93a386Sopenharmony_ci			}
174cb93a386Sopenharmony_ci			if(flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT)  // Output query availablity
175cb93a386Sopenharmony_ci			{
176cb93a386Sopenharmony_ci				result32[1] = current.state;
177cb93a386Sopenharmony_ci			}
178cb93a386Sopenharmony_ci		}
179cb93a386Sopenharmony_ci	}
180cb93a386Sopenharmony_ci
181cb93a386Sopenharmony_ci	return result;
182cb93a386Sopenharmony_ci}
183cb93a386Sopenharmony_ci
184cb93a386Sopenharmony_civoid QueryPool::begin(uint32_t query, VkQueryControlFlags flags)
185cb93a386Sopenharmony_ci{
186cb93a386Sopenharmony_ci	ASSERT(query < count);
187cb93a386Sopenharmony_ci
188cb93a386Sopenharmony_ci	// Only accept flags with valid bits set.
189cb93a386Sopenharmony_ci	if(flags & ~(VK_QUERY_CONTROL_PRECISE_BIT))
190cb93a386Sopenharmony_ci	{
191cb93a386Sopenharmony_ci		UNSUPPORTED("vkCmdBeginQuery::flags %d", int(flags));
192cb93a386Sopenharmony_ci	}
193cb93a386Sopenharmony_ci
194cb93a386Sopenharmony_ci	pool[query].start();
195cb93a386Sopenharmony_ci}
196cb93a386Sopenharmony_ci
197cb93a386Sopenharmony_civoid QueryPool::end(uint32_t query)
198cb93a386Sopenharmony_ci{
199cb93a386Sopenharmony_ci	ASSERT(query < count);
200cb93a386Sopenharmony_ci	pool[query].finish();
201cb93a386Sopenharmony_ci}
202cb93a386Sopenharmony_ci
203cb93a386Sopenharmony_civoid QueryPool::reset(uint32_t firstQuery, uint32_t queryCount)
204cb93a386Sopenharmony_ci{
205cb93a386Sopenharmony_ci	// The sum of firstQuery and queryCount must be less than or equal to the number of queries
206cb93a386Sopenharmony_ci	ASSERT((firstQuery + queryCount) <= count);
207cb93a386Sopenharmony_ci
208cb93a386Sopenharmony_ci	for(uint32_t i = firstQuery; i < (firstQuery + queryCount); i++)
209cb93a386Sopenharmony_ci	{
210cb93a386Sopenharmony_ci		pool[i].reset();
211cb93a386Sopenharmony_ci	}
212cb93a386Sopenharmony_ci}
213cb93a386Sopenharmony_ci
214cb93a386Sopenharmony_civoid QueryPool::writeTimestamp(uint32_t query)
215cb93a386Sopenharmony_ci{
216cb93a386Sopenharmony_ci	ASSERT(query < count);
217cb93a386Sopenharmony_ci	ASSERT(type == VK_QUERY_TYPE_TIMESTAMP);
218cb93a386Sopenharmony_ci
219cb93a386Sopenharmony_ci	pool[query].start();
220cb93a386Sopenharmony_ci	pool[query].set(std::chrono::time_point_cast<std::chrono::nanoseconds>(
221cb93a386Sopenharmony_ci	                    std::chrono::steady_clock::now())
222cb93a386Sopenharmony_ci	                    .time_since_epoch()
223cb93a386Sopenharmony_ci	                    .count());
224cb93a386Sopenharmony_ci	pool[query].finish();
225cb93a386Sopenharmony_ci}
226cb93a386Sopenharmony_ci
227cb93a386Sopenharmony_ci}  // namespace vk
228