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