Query11.cpp (11942B)
1 // 2 // Copyright 2013 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 // Query11.cpp: Defines the rx::Query11 class which implements rx::QueryImpl. 8 9 #include "libANGLE/renderer/d3d/d3d11/Query11.h" 10 11 #include <GLES2/gl2ext.h> 12 13 #include "common/utilities.h" 14 #include "libANGLE/Context.h" 15 #include "libANGLE/renderer/d3d/d3d11/Context11.h" 16 #include "libANGLE/renderer/d3d/d3d11/Renderer11.h" 17 #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" 18 19 namespace 20 { 21 22 GLuint64 MergeQueryResults(gl::QueryType type, GLuint64 currentResult, GLuint64 newResult) 23 { 24 switch (type) 25 { 26 case gl::QueryType::AnySamples: 27 case gl::QueryType::AnySamplesConservative: 28 return (currentResult == GL_TRUE || newResult == GL_TRUE) ? GL_TRUE : GL_FALSE; 29 30 case gl::QueryType::TransformFeedbackPrimitivesWritten: 31 return currentResult + newResult; 32 33 case gl::QueryType::TimeElapsed: 34 return currentResult + newResult; 35 36 case gl::QueryType::Timestamp: 37 return newResult; 38 39 case gl::QueryType::CommandsCompleted: 40 return newResult; 41 42 default: 43 UNREACHABLE(); 44 return 0; 45 } 46 } 47 48 } // anonymous namespace 49 50 namespace rx 51 { 52 53 Query11::QueryState::QueryState() 54 : getDataAttemptCount(0), query(), beginTimestamp(), endTimestamp(), finished(false) 55 {} 56 57 Query11::QueryState::~QueryState() {} 58 59 Query11::Query11(Renderer11 *renderer, gl::QueryType type) 60 : QueryImpl(type), mResult(0), mResultSum(0), mRenderer(renderer) 61 { 62 mActiveQuery = std::unique_ptr<QueryState>(new QueryState()); 63 } 64 65 Query11::~Query11() 66 { 67 mRenderer->getStateManager()->onDeleteQueryObject(this); 68 } 69 70 angle::Result Query11::begin(const gl::Context *context) 71 { 72 mResultSum = 0; 73 mRenderer->getStateManager()->onBeginQuery(this); 74 return resume(GetImplAs<Context11>(context)); 75 } 76 77 angle::Result Query11::end(const gl::Context *context) 78 { 79 return pause(GetImplAs<Context11>(context)); 80 } 81 82 angle::Result Query11::queryCounter(const gl::Context *context) 83 { 84 // This doesn't do anything for D3D11 as we don't support timestamps 85 ASSERT(getType() == gl::QueryType::Timestamp); 86 mResultSum = 0; 87 mPendingQueries.push_back(std::unique_ptr<QueryState>(new QueryState())); 88 return angle::Result::Continue; 89 } 90 91 template <typename T> 92 angle::Result Query11::getResultBase(Context11 *context11, T *params) 93 { 94 ASSERT(!mActiveQuery->query.valid()); 95 ANGLE_TRY(flush(context11, true)); 96 ASSERT(mPendingQueries.empty()); 97 *params = static_cast<T>(mResultSum); 98 99 return angle::Result::Continue; 100 } 101 102 angle::Result Query11::getResult(const gl::Context *context, GLint *params) 103 { 104 return getResultBase(GetImplAs<Context11>(context), params); 105 } 106 107 angle::Result Query11::getResult(const gl::Context *context, GLuint *params) 108 { 109 return getResultBase(GetImplAs<Context11>(context), params); 110 } 111 112 angle::Result Query11::getResult(const gl::Context *context, GLint64 *params) 113 { 114 return getResultBase(GetImplAs<Context11>(context), params); 115 } 116 117 angle::Result Query11::getResult(const gl::Context *context, GLuint64 *params) 118 { 119 return getResultBase(GetImplAs<Context11>(context), params); 120 } 121 122 angle::Result Query11::isResultAvailable(const gl::Context *context, bool *available) 123 { 124 ANGLE_TRY(flush(GetImplAs<Context11>(context), false)); 125 126 *available = mPendingQueries.empty(); 127 return angle::Result::Continue; 128 } 129 130 angle::Result Query11::pause(Context11 *context11) 131 { 132 if (mActiveQuery->query.valid()) 133 { 134 ID3D11DeviceContext *context = mRenderer->getDeviceContext(); 135 gl::QueryType type = getType(); 136 137 // If we are doing time elapsed query the end timestamp 138 if (type == gl::QueryType::TimeElapsed) 139 { 140 context->End(mActiveQuery->endTimestamp.get()); 141 } 142 143 context->End(mActiveQuery->query.get()); 144 145 mPendingQueries.push_back(std::move(mActiveQuery)); 146 mActiveQuery = std::unique_ptr<QueryState>(new QueryState()); 147 } 148 149 return flush(context11, false); 150 } 151 152 angle::Result Query11::resume(Context11 *context11) 153 { 154 if (!mActiveQuery->query.valid()) 155 { 156 ANGLE_TRY(flush(context11, false)); 157 158 gl::QueryType type = getType(); 159 D3D11_QUERY d3dQueryType = gl_d3d11::ConvertQueryType(type); 160 161 D3D11_QUERY_DESC queryDesc; 162 queryDesc.Query = d3dQueryType; 163 queryDesc.MiscFlags = 0; 164 165 ANGLE_TRY(mRenderer->allocateResource(context11, queryDesc, &mActiveQuery->query)); 166 167 // If we are doing time elapsed we also need a query to actually query the timestamp 168 if (type == gl::QueryType::TimeElapsed) 169 { 170 D3D11_QUERY_DESC desc; 171 desc.Query = D3D11_QUERY_TIMESTAMP; 172 desc.MiscFlags = 0; 173 174 ANGLE_TRY(mRenderer->allocateResource(context11, desc, &mActiveQuery->beginTimestamp)); 175 ANGLE_TRY(mRenderer->allocateResource(context11, desc, &mActiveQuery->endTimestamp)); 176 } 177 178 ID3D11DeviceContext *context = mRenderer->getDeviceContext(); 179 180 if (d3dQueryType != D3D11_QUERY_EVENT) 181 { 182 context->Begin(mActiveQuery->query.get()); 183 } 184 185 // If we are doing time elapsed, query the begin timestamp 186 if (type == gl::QueryType::TimeElapsed) 187 { 188 context->End(mActiveQuery->beginTimestamp.get()); 189 } 190 } 191 192 return angle::Result::Continue; 193 } 194 195 angle::Result Query11::flush(Context11 *context11, bool force) 196 { 197 while (!mPendingQueries.empty()) 198 { 199 QueryState *query = mPendingQueries.front().get(); 200 201 do 202 { 203 ANGLE_TRY(testQuery(context11, query)); 204 if (!query->finished && !force) 205 { 206 return angle::Result::Continue; 207 } 208 } while (!query->finished); 209 210 mResultSum = MergeQueryResults(getType(), mResultSum, mResult); 211 mPendingQueries.pop_front(); 212 } 213 214 return angle::Result::Continue; 215 } 216 217 angle::Result Query11::testQuery(Context11 *context11, QueryState *queryState) 218 { 219 if (!queryState->finished) 220 { 221 ID3D11DeviceContext *context = mRenderer->getDeviceContext(); 222 switch (getType()) 223 { 224 case gl::QueryType::AnySamples: 225 case gl::QueryType::AnySamplesConservative: 226 { 227 ASSERT(queryState->query.valid()); 228 UINT64 numPixels = 0; 229 HRESULT result = 230 context->GetData(queryState->query.get(), &numPixels, sizeof(numPixels), 0); 231 ANGLE_TRY_HR(context11, result, "Failed to get the data of an internal query"); 232 233 if (result == S_OK) 234 { 235 queryState->finished = true; 236 mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE; 237 } 238 } 239 break; 240 241 case gl::QueryType::TransformFeedbackPrimitivesWritten: 242 { 243 ASSERT(queryState->query.valid()); 244 D3D11_QUERY_DATA_SO_STATISTICS soStats = {}; 245 HRESULT result = 246 context->GetData(queryState->query.get(), &soStats, sizeof(soStats), 0); 247 ANGLE_TRY_HR(context11, result, "Failed to get the data of an internal query"); 248 249 if (result == S_OK) 250 { 251 queryState->finished = true; 252 mResult = static_cast<GLuint64>(soStats.NumPrimitivesWritten); 253 } 254 } 255 break; 256 257 case gl::QueryType::TimeElapsed: 258 { 259 ASSERT(queryState->query.valid()); 260 ASSERT(queryState->beginTimestamp.valid()); 261 ASSERT(queryState->endTimestamp.valid()); 262 D3D11_QUERY_DATA_TIMESTAMP_DISJOINT timeStats = {}; 263 HRESULT result = 264 context->GetData(queryState->query.get(), &timeStats, sizeof(timeStats), 0); 265 ANGLE_TRY_HR(context11, result, "Failed to get the data of an internal query"); 266 267 if (result == S_OK) 268 { 269 UINT64 beginTime = 0; 270 HRESULT beginRes = context->GetData(queryState->beginTimestamp.get(), 271 &beginTime, sizeof(UINT64), 0); 272 ANGLE_TRY_HR(context11, beginRes, 273 "Failed to get the data of an internal query"); 274 275 UINT64 endTime = 0; 276 HRESULT endRes = context->GetData(queryState->endTimestamp.get(), &endTime, 277 sizeof(UINT64), 0); 278 ANGLE_TRY_HR(context11, endRes, "Failed to get the data of an internal query"); 279 280 if (beginRes == S_OK && endRes == S_OK) 281 { 282 queryState->finished = true; 283 if (timeStats.Disjoint) 284 { 285 mRenderer->setGPUDisjoint(); 286 } 287 static_assert(sizeof(UINT64) == sizeof(unsigned long long), 288 "D3D UINT64 isn't 64 bits"); 289 290 angle::CheckedNumeric<UINT64> checkedTime(endTime); 291 checkedTime -= beginTime; 292 checkedTime *= 1000000000ull; 293 checkedTime /= timeStats.Frequency; 294 if (checkedTime.IsValid()) 295 { 296 mResult = checkedTime.ValueOrDie(); 297 } 298 else 299 { 300 mResult = std::numeric_limits<GLuint64>::max() / timeStats.Frequency; 301 // If an overflow does somehow occur, there is no way the elapsed time 302 // is accurate, so we generate a disjoint event 303 mRenderer->setGPUDisjoint(); 304 } 305 } 306 } 307 } 308 break; 309 310 case gl::QueryType::Timestamp: 311 { 312 // D3D11 doesn't support GL timestamp queries as D3D timestamps are not guaranteed 313 // to have any sort of continuity outside of a disjoint timestamp query block, which 314 // GL depends on 315 ASSERT(!queryState->query.valid()); 316 mResult = 0; 317 queryState->finished = true; 318 } 319 break; 320 321 case gl::QueryType::CommandsCompleted: 322 { 323 ASSERT(queryState->query.valid()); 324 BOOL completed = 0; 325 HRESULT result = 326 context->GetData(queryState->query.get(), &completed, sizeof(completed), 0); 327 ANGLE_TRY_HR(context11, result, "Failed to get the data of an internal query"); 328 329 if (result == S_OK) 330 { 331 queryState->finished = true; 332 ASSERT(completed == TRUE); 333 mResult = (completed == TRUE) ? GL_TRUE : GL_FALSE; 334 } 335 } 336 break; 337 338 default: 339 UNREACHABLE(); 340 break; 341 } 342 343 queryState->getDataAttemptCount++; 344 bool checkDeviceLost = 345 (queryState->getDataAttemptCount % kPollingD3DDeviceLostCheckFrequency) == 0; 346 if (!queryState->finished && checkDeviceLost && mRenderer->testDeviceLost()) 347 { 348 mRenderer->notifyDeviceLost(); 349 ANGLE_TRY_HR(context11, E_OUTOFMEMORY, 350 "Failed to test get query result, device is lost."); 351 } 352 } 353 354 return angle::Result::Continue; 355 } 356 357 } // namespace rx