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