1 //
2 // Copyright 2016 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 // QueryVk.cpp:
7 // Implements the class methods for QueryVk.
8 //
9
10 #include "libANGLE/renderer/vulkan/QueryVk.h"
11 #include "libANGLE/Context.h"
12 #include "libANGLE/TransformFeedback.h"
13 #include "libANGLE/renderer/vulkan/ContextVk.h"
14 #include "libANGLE/renderer/vulkan/RendererVk.h"
15 #include "libANGLE/renderer/vulkan/TransformFeedbackVk.h"
16
17 #include "common/debug.h"
18
19 namespace rx
20 {
21
22 namespace
23 {
24 struct QueryReleaseHelper
25 {
operator ()rx::__anonda3221fe0111::QueryReleaseHelper26 void operator()(vk::QueryHelper &&query) { queryPool->freeQuery(contextVk, &query); }
27
28 ContextVk *contextVk;
29 vk::DynamicQueryPool *queryPool;
30 };
31
IsRenderPassQuery(ContextVk * contextVk,gl::QueryType type)32 bool IsRenderPassQuery(ContextVk *contextVk, gl::QueryType type)
33 {
34 switch (type)
35 {
36 case gl::QueryType::AnySamples:
37 case gl::QueryType::AnySamplesConservative:
38 case gl::QueryType::PrimitivesGenerated:
39 return true;
40 case gl::QueryType::TransformFeedbackPrimitivesWritten:
41 return contextVk->getFeatures().supportsTransformFeedbackExtension.enabled;
42 default:
43 return false;
44 }
45 }
46
IsEmulatedTransformFeedbackQuery(ContextVk * contextVk,gl::QueryType type)47 bool IsEmulatedTransformFeedbackQuery(ContextVk *contextVk, gl::QueryType type)
48 {
49 return type == gl::QueryType::TransformFeedbackPrimitivesWritten &&
50 contextVk->getFeatures().emulateTransformFeedback.enabled;
51 }
52
IsPrimitivesGeneratedQueryShared(ContextVk * contextVk)53 bool IsPrimitivesGeneratedQueryShared(ContextVk *contextVk)
54 {
55 return !contextVk->getFeatures().supportsPrimitivesGeneratedQuery.enabled &&
56 !contextVk->getFeatures().supportsPipelineStatisticsQuery.enabled;
57 }
58
GetShareQuery(ContextVk * contextVk,gl::QueryType type)59 QueryVk *GetShareQuery(ContextVk *contextVk, gl::QueryType type)
60 {
61 QueryVk *shareQuery = nullptr;
62
63 // If the primitives generated query has its own dedicated Vulkan query, there's no sharing.
64 if (!IsPrimitivesGeneratedQueryShared(contextVk))
65 {
66 return nullptr;
67 }
68
69 switch (type)
70 {
71 case gl::QueryType::PrimitivesGenerated:
72 shareQuery = contextVk->getActiveRenderPassQuery(
73 gl::QueryType::TransformFeedbackPrimitivesWritten);
74 break;
75 case gl::QueryType::TransformFeedbackPrimitivesWritten:
76 shareQuery = contextVk->getActiveRenderPassQuery(gl::QueryType::PrimitivesGenerated);
77 break;
78 default:
79 break;
80 }
81
82 return shareQuery;
83 }
84
85 // When a render pass starts/ends, onRenderPassStart/End is called for all active queries. For
86 // shared queries, the one that is called first would actually manage the query helper begin/end and
87 // allocation, and the one that follows would share it. PrimitivesGenerated and
88 // TransformFeedbackPrimitivesWritten share queries, and the former is processed first.
GetOnRenderPassStartEndShareQuery(ContextVk * contextVk,gl::QueryType type)89 QueryVk *GetOnRenderPassStartEndShareQuery(ContextVk *contextVk, gl::QueryType type)
90 {
91 static_assert(
92 gl::QueryType::PrimitivesGenerated < gl::QueryType::TransformFeedbackPrimitivesWritten,
93 "incorrect assumption about the order in which queries are started in a render pass");
94
95 if (type != gl::QueryType::TransformFeedbackPrimitivesWritten ||
96 !IsPrimitivesGeneratedQueryShared(contextVk))
97 {
98 return nullptr;
99 }
100
101 // For TransformFeedbackPrimitivesWritten, return the already-processed PrimitivesGenerated
102 // share query.
103 return contextVk->getActiveRenderPassQuery(gl::QueryType::PrimitivesGenerated);
104 }
105 } // anonymous namespace
106
QueryVk(gl::QueryType type)107 QueryVk::QueryVk(gl::QueryType type)
108 : QueryImpl(type),
109 mTransformFeedbackPrimitivesDrawn(0),
110 mCachedResult(0),
111 mCachedResultValid(false)
112 {}
113
114 QueryVk::~QueryVk() = default;
115
allocateQuery(ContextVk * contextVk)116 angle::Result QueryVk::allocateQuery(ContextVk *contextVk)
117 {
118 ASSERT(!mQueryHelper.isReferenced());
119 mQueryHelper.setUnreferenced(new vk::RefCounted<vk::QueryHelper>);
120
121 // When used with multiview, render pass queries write as many queries as the number of views.
122 // Render pass queries are always allocated at the beginning of the render pass, so the number
123 // of views is known at this time.
124 uint32_t queryCount = 1;
125 if (IsRenderPassQuery(contextVk, mType))
126 {
127 ASSERT(contextVk->hasActiveRenderPass());
128 queryCount = std::max(contextVk->getCurrentViewCount(), 1u);
129 }
130
131 return contextVk->getQueryPool(mType)->allocateQuery(contextVk, &mQueryHelper.get(),
132 queryCount);
133 }
134
assignSharedQuery(QueryVk * shareQuery)135 void QueryVk::assignSharedQuery(QueryVk *shareQuery)
136 {
137 ASSERT(!mQueryHelper.isReferenced());
138 ASSERT(shareQuery->mQueryHelper.isReferenced());
139 mQueryHelper.copyUnreferenced(shareQuery->mQueryHelper);
140 }
141
releaseQueries(ContextVk * contextVk)142 void QueryVk::releaseQueries(ContextVk *contextVk)
143 {
144 ASSERT(!IsEmulatedTransformFeedbackQuery(contextVk, mType));
145
146 vk::DynamicQueryPool *queryPool = contextVk->getQueryPool(mType);
147
148 // Free the main query
149 if (mQueryHelper.isReferenced())
150 {
151 QueryReleaseHelper releaseHelper = {contextVk, queryPool};
152 mQueryHelper.resetAndRelease(&releaseHelper);
153 }
154 // Free the secondary query used to emulate TimeElapsed
155 queryPool->freeQuery(contextVk, &mQueryHelperTimeElapsedBegin);
156
157 // Free any stashed queries used to support queries that start and stop with the render pass.
158 releaseStashedQueries(contextVk);
159 }
160
releaseStashedQueries(ContextVk * contextVk)161 void QueryVk::releaseStashedQueries(ContextVk *contextVk)
162 {
163 vk::DynamicQueryPool *queryPool = contextVk->getQueryPool(mType);
164
165 for (vk::Shared<vk::QueryHelper> &query : mStashedQueryHelpers)
166 {
167 ASSERT(query.isReferenced());
168
169 QueryReleaseHelper releaseHelper = {contextVk, queryPool};
170 query.resetAndRelease(&releaseHelper);
171 }
172 mStashedQueryHelpers.clear();
173 }
174
onDestroy(const gl::Context * context)175 void QueryVk::onDestroy(const gl::Context *context)
176 {
177 ContextVk *contextVk = vk::GetImpl(context);
178 if (!IsEmulatedTransformFeedbackQuery(contextVk, mType))
179 {
180 releaseQueries(contextVk);
181 }
182 }
183
stashQueryHelper()184 void QueryVk::stashQueryHelper()
185 {
186 ASSERT(mQueryHelper.isReferenced());
187 mStashedQueryHelpers.push_back(std::move(mQueryHelper));
188 ASSERT(!mQueryHelper.isReferenced());
189 }
190
onRenderPassStart(ContextVk * contextVk)191 angle::Result QueryVk::onRenderPassStart(ContextVk *contextVk)
192 {
193 ASSERT(IsRenderPassQuery(contextVk, mType));
194
195 // If there is a query helper already, stash it and allocate a new one for this render pass.
196 if (mQueryHelper.isReferenced())
197 {
198 stashQueryHelper();
199 }
200
201 QueryVk *shareQuery = GetOnRenderPassStartEndShareQuery(contextVk, mType);
202
203 if (shareQuery)
204 {
205 assignSharedQuery(shareQuery);
206
207 // shareQuery has already started the query.
208 return angle::Result::Continue;
209 }
210
211 ANGLE_TRY(allocateQuery(contextVk));
212 return mQueryHelper.get().beginRenderPassQuery(contextVk);
213 }
214
onRenderPassEnd(ContextVk * contextVk)215 void QueryVk::onRenderPassEnd(ContextVk *contextVk)
216 {
217 ASSERT(IsRenderPassQuery(contextVk, mType));
218
219 QueryVk *shareQuery = GetOnRenderPassStartEndShareQuery(contextVk, mType);
220
221 // If present, share query has already taken care of ending the query.
222 // The query may not be referenced if it's a transform feedback query that was never resumed due
223 // to transform feedback being paused when the render pass was broken.
224 if (shareQuery == nullptr && mQueryHelper.isReferenced())
225 {
226 mQueryHelper.get().endRenderPassQuery(contextVk);
227 }
228 }
229
accumulateStashedQueryResult(ContextVk * contextVk,vk::QueryResult * result)230 angle::Result QueryVk::accumulateStashedQueryResult(ContextVk *contextVk, vk::QueryResult *result)
231 {
232 for (vk::Shared<vk::QueryHelper> &query : mStashedQueryHelpers)
233 {
234 vk::QueryResult v(getQueryResultCount(contextVk));
235 ANGLE_TRY(query.get().getUint64Result(contextVk, &v));
236 *result += v;
237 }
238 releaseStashedQueries(contextVk);
239 return angle::Result::Continue;
240 }
241
setupBegin(ContextVk * contextVk)242 angle::Result QueryVk::setupBegin(ContextVk *contextVk)
243 {
244 if (IsRenderPassQuery(contextVk, mType))
245 {
246 // Clean up query helpers from the previous begin/end call on the same query. Only
247 // necessary for in-render-pass queries. The other queries can reuse query helpers as they
248 // are able to reset it ouside the render pass where they are recorded.
249 if (mQueryHelper.isReferenced())
250 {
251 releaseQueries(contextVk);
252 }
253
254 // If either of TransformFeedbackPrimitivesWritten or PrimitivesGenerated queries are
255 // already active when the other one is begun, we have to switch to a new query helper (if
256 // in render pass), and have them share the query helper from here on.
257
258 // If this is a transform feedback query, see if the other transform feedback query is
259 // already active.
260 QueryVk *shareQuery = GetShareQuery(contextVk, mType);
261
262 // If so, make the other query stash its results and continue with a new query helper.
263 if (contextVk->hasActiveRenderPass())
264 {
265 if (shareQuery)
266 {
267 // This serves the following scenario (TF = TransformFeedbackPrimitivesWritten, PG =
268 // PrimitivesGenerated):
269 //
270 // - TF starts <-- QueryHelper1 starts
271 // - Draw
272 // - PG starts <-- QueryHelper1 stashed in TF, TF starts QueryHelper2,
273 // PG shares QueryHelper2
274 // - Draw
275 shareQuery->onRenderPassEnd(contextVk);
276 shareQuery->stashQueryHelper();
277 ANGLE_TRY(shareQuery->allocateQuery(contextVk));
278
279 // Share the query helper with the other transform feedback query. After
280 // |setupBegin()| returns, they query helper is started on behalf of the shared
281 // query.
282 assignSharedQuery(shareQuery);
283 }
284 }
285 else
286 {
287 // Keep the query helper unallocated. When the render pass starts, a new one
288 // will be allocated / shared.
289 return angle::Result::Continue;
290 }
291 }
292
293 // If no query helper, create a new one.
294 if (!mQueryHelper.isReferenced())
295 {
296 ANGLE_TRY(allocateQuery(contextVk));
297 }
298
299 return angle::Result::Continue;
300 }
301
begin(const gl::Context * context)302 angle::Result QueryVk::begin(const gl::Context *context)
303 {
304 ContextVk *contextVk = vk::GetImpl(context);
305
306 // Ensure that we start with the right RenderPass when we begin a new query.
307 if (contextVk->getState().isDrawFramebufferBindingDirty())
308 {
309 ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass(
310 RenderPassClosureReason::FramebufferBindingChange));
311 }
312
313 mCachedResultValid = false;
314
315 // Transform feedback query is handled by a CPU-calculated value when emulated.
316 if (IsEmulatedTransformFeedbackQuery(contextVk, mType))
317 {
318 ASSERT(!contextVk->getFeatures().supportsTransformFeedbackExtension.enabled);
319 mTransformFeedbackPrimitivesDrawn = 0;
320
321 return angle::Result::Continue;
322 }
323
324 ANGLE_TRY(setupBegin(contextVk));
325
326 switch (mType)
327 {
328 case gl::QueryType::AnySamples:
329 case gl::QueryType::AnySamplesConservative:
330 case gl::QueryType::PrimitivesGenerated:
331 case gl::QueryType::TransformFeedbackPrimitivesWritten:
332 ANGLE_TRY(contextVk->beginRenderPassQuery(this));
333 break;
334 case gl::QueryType::Timestamp:
335 ANGLE_TRY(mQueryHelper.get().beginQuery(contextVk));
336 break;
337 case gl::QueryType::TimeElapsed:
338 // Note: TimeElapsed is implemented by using two Timestamp queries and taking the diff.
339 if (!mQueryHelperTimeElapsedBegin.valid())
340 {
341 // Note that timestamp queries are not allowed with multiview, so query count is
342 // always 1.
343 ANGLE_TRY(contextVk->getQueryPool(mType)->allocateQuery(
344 contextVk, &mQueryHelperTimeElapsedBegin, 1));
345 }
346
347 ANGLE_TRY(mQueryHelperTimeElapsedBegin.flushAndWriteTimestamp(contextVk));
348 break;
349 default:
350 UNREACHABLE();
351 break;
352 }
353
354 return angle::Result::Continue;
355 }
356
end(const gl::Context * context)357 angle::Result QueryVk::end(const gl::Context *context)
358 {
359 ContextVk *contextVk = vk::GetImpl(context);
360
361 // Transform feedback query is handled by a CPU-calculated value when emulated.
362 if (IsEmulatedTransformFeedbackQuery(contextVk, mType))
363 {
364 ASSERT(contextVk->getFeatures().emulateTransformFeedback.enabled);
365 mCachedResult = mTransformFeedbackPrimitivesDrawn;
366
367 // There could be transform feedback in progress, so add the primitives drawn so far
368 // from the current transform feedback object.
369 gl::TransformFeedback *transformFeedback =
370 context->getState().getCurrentTransformFeedback();
371 if (transformFeedback)
372 {
373 mCachedResult += transformFeedback->getPrimitivesDrawn();
374 }
375 mCachedResultValid = true;
376
377 return angle::Result::Continue;
378 }
379
380 switch (mType)
381 {
382 case gl::QueryType::AnySamples:
383 case gl::QueryType::AnySamplesConservative:
384 case gl::QueryType::PrimitivesGenerated:
385 case gl::QueryType::TransformFeedbackPrimitivesWritten:
386 {
387 QueryVk *shareQuery = GetShareQuery(contextVk, mType);
388 ASSERT(shareQuery == nullptr || &mQueryHelper.get() == &shareQuery->mQueryHelper.get());
389
390 ANGLE_TRY(contextVk->endRenderPassQuery(this));
391
392 // If another query shares its query helper with this one, its query has just ended!
393 // Make it stash its query and create a new one so it can continue.
394 if (shareQuery && shareQuery->mQueryHelper.isReferenced())
395 {
396 // This serves the following scenario (TF = TransformFeedbackPrimitivesWritten, PG =
397 // PrimitivesGenerated):
398 //
399 // - TF starts <-- QueryHelper1 starts
400 // - PG starts <-- PG shares QueryHelper1
401 // - Draw
402 // - TF ends <-- Results = QueryHelper1,
403 // QueryHelper1 stashed in PG, PG starts QueryHelper2
404 // - Draw
405 // - PG ends <-- Results = QueryHelper1 + QueryHelper2
406 if (contextVk->hasActiveRenderPass())
407 {
408 ANGLE_TRY(shareQuery->onRenderPassStart(contextVk));
409 }
410 }
411 break;
412 }
413 case gl::QueryType::Timestamp:
414 ANGLE_TRY(mQueryHelper.get().endQuery(contextVk));
415 break;
416 case gl::QueryType::TimeElapsed:
417 ANGLE_TRY(mQueryHelper.get().flushAndWriteTimestamp(contextVk));
418 break;
419 default:
420 UNREACHABLE();
421 break;
422 }
423
424 return angle::Result::Continue;
425 }
426
queryCounter(const gl::Context * context)427 angle::Result QueryVk::queryCounter(const gl::Context *context)
428 {
429 ASSERT(mType == gl::QueryType::Timestamp);
430 ContextVk *contextVk = vk::GetImpl(context);
431
432 mCachedResultValid = false;
433
434 if (!mQueryHelper.isReferenced())
435 {
436 ANGLE_TRY(allocateQuery(contextVk));
437 }
438
439 return mQueryHelper.get().flushAndWriteTimestamp(contextVk);
440 }
441
isCurrentlyInUse(RendererVk * renderer) const442 bool QueryVk::isCurrentlyInUse(RendererVk *renderer) const
443 {
444 ASSERT(mQueryHelper.isReferenced());
445 return !renderer->hasResourceUseFinished(mQueryHelper.get().getResourceUse());
446 }
447
finishRunningCommands(ContextVk * contextVk)448 angle::Result QueryVk::finishRunningCommands(ContextVk *contextVk)
449 {
450 RendererVk *renderer = contextVk->getRenderer();
451
452 // Caller already made sure query has been submitted.
453 if (!renderer->hasResourceUseFinished(mQueryHelper.get().getResourceUse()))
454 {
455 ANGLE_TRY(renderer->finishResourceUse(contextVk, mQueryHelper.get().getResourceUse()));
456 }
457
458 // Since mStashedQueryHelpers are older than mQueryHelper, these must also finished.
459 for (vk::Shared<vk::QueryHelper> &query : mStashedQueryHelpers)
460 {
461 ASSERT(renderer->hasResourceUseFinished(query.get().getResourceUse()));
462 }
463 return angle::Result::Continue;
464 }
465
getResult(const gl::Context * context,bool wait)466 angle::Result QueryVk::getResult(const gl::Context *context, bool wait)
467 {
468 ANGLE_TRACE_EVENT0("gpu.angle", "QueryVk::getResult");
469
470 if (mCachedResultValid)
471 {
472 return angle::Result::Continue;
473 }
474
475 ContextVk *contextVk = vk::GetImpl(context);
476 RendererVk *renderer = contextVk->getRenderer();
477
478 // Support the pathological case where begin/end is called on a render pass query but without
479 // any render passes in between. In this case, the query helper is never allocated.
480 if (!mQueryHelper.isReferenced())
481 {
482 ASSERT(IsRenderPassQuery(contextVk, mType));
483 mCachedResult = 0;
484 mCachedResultValid = true;
485 return angle::Result::Continue;
486 }
487
488 // glGetQueryObject* requires an implicit flush of the command buffers to guarantee execution in
489 // finite time.
490 // Note regarding time-elapsed: end should have been called after begin, so flushing when end
491 // has pending work should flush begin too.
492 // We only need to check mQueryHelper, not mStashedQueryHelper, since they are always in order.
493 if (contextVk->hasUnsubmittedUse(mQueryHelper.get()))
494 {
495 ANGLE_TRY(contextVk->flushImpl(nullptr, nullptr, RenderPassClosureReason::GetQueryResult));
496
497 ASSERT(contextVk->getRenderer()->hasResourceUseSubmitted(
498 mQueryHelperTimeElapsedBegin.getResourceUse()));
499 ASSERT(
500 contextVk->getRenderer()->hasResourceUseSubmitted(mQueryHelper.get().getResourceUse()));
501 }
502
503 // If the command buffer this query is being written to is still in flight and uses
504 // vkCmdResetQueryPool, its reset command may not have been performed by the GPU yet. To avoid
505 // a race condition in this case, wait for the batch to finish first before querying (or return
506 // not-ready if not waiting).
507 if (isCurrentlyInUse(renderer) &&
508 (!renderer->getFeatures().supportsHostQueryReset.enabled ||
509 renderer->getFeatures().forceWaitForSubmissionToCompleteForQueryResult.enabled ||
510 renderer->isAsyncCommandQueueEnabled()))
511 {
512 // The query might appear busy because there was no check for completed commands
513 // recently. Do that now and see if the query is still busy. If the application is
514 // looping until the query results become available, there wouldn't be any forward
515 // progress without this.
516 ANGLE_TRY(renderer->checkCompletedCommands(contextVk));
517
518 if (isCurrentlyInUse(renderer))
519 {
520 if (!wait)
521 {
522 return angle::Result::Continue;
523 }
524 ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_HIGH,
525 "GPU stall due to waiting on uncompleted query");
526
527 // Assert that the work has been sent to the GPU
528 ASSERT(!contextVk->hasUnsubmittedUse(mQueryHelper.get()));
529 ANGLE_TRY(finishRunningCommands(contextVk));
530 }
531 }
532
533 // If its a render pass query, the current query helper must have commands recorded (i.e. it's
534 // not a newly allocated query with the actual queries all stashed). If this is not respected
535 // and !wait, |mQueryHelper.get().getUint64ResultNonBlocking()| will tell that the result is
536 // readily available, which may not be true. The subsequent calls to |getUint64Result()| on the
537 // stashed queries will incur a wait that is not desired by the application.
538 ASSERT(!IsRenderPassQuery(contextVk, mType) || mQueryHelper.get().hasSubmittedCommands());
539
540 vk::QueryResult result(getQueryResultCount(contextVk));
541
542 if (wait)
543 {
544 ANGLE_TRY(mQueryHelper.get().getUint64Result(contextVk, &result));
545 ANGLE_TRY(accumulateStashedQueryResult(contextVk, &result));
546 }
547 else
548 {
549 bool available = false;
550 ANGLE_TRY(mQueryHelper.get().getUint64ResultNonBlocking(contextVk, &result, &available));
551 if (!available)
552 {
553 // If the results are not ready, do nothing. mCachedResultValid remains false.
554 return angle::Result::Continue;
555 }
556 ANGLE_TRY(accumulateStashedQueryResult(contextVk, &result));
557 }
558
559 double timestampPeriod = renderer->getPhysicalDeviceProperties().limits.timestampPeriod;
560
561 // Fix up the results to what OpenGL expects.
562 switch (mType)
563 {
564 case gl::QueryType::AnySamples:
565 case gl::QueryType::AnySamplesConservative:
566 // OpenGL query result in these cases is binary
567 mCachedResult = !!result.getResult(vk::QueryResult::kDefaultResultIndex);
568 break;
569 case gl::QueryType::Timestamp:
570 mCachedResult = static_cast<uint64_t>(
571 result.getResult(vk::QueryResult::kDefaultResultIndex) * timestampPeriod);
572 break;
573 case gl::QueryType::TimeElapsed:
574 {
575 vk::QueryResult timeElapsedBegin(1);
576
577 // Since the result of the end query of time-elapsed is already available, the
578 // result of begin query must be available too.
579 ANGLE_TRY(mQueryHelperTimeElapsedBegin.getUint64Result(contextVk, &timeElapsedBegin));
580
581 uint64_t delta = result.getResult(vk::QueryResult::kDefaultResultIndex) -
582 timeElapsedBegin.getResult(vk::QueryResult::kDefaultResultIndex);
583 mCachedResult = static_cast<uint64_t>(delta * timestampPeriod);
584 break;
585 }
586 case gl::QueryType::TransformFeedbackPrimitivesWritten:
587 mCachedResult =
588 result.getResult(IsPrimitivesGeneratedQueryShared(contextVk)
589 ? vk::QueryResult::kTransformFeedbackPrimitivesWrittenIndex
590 : vk::QueryResult::kDefaultResultIndex);
591 break;
592 case gl::QueryType::PrimitivesGenerated:
593 mCachedResult = result.getResult(IsPrimitivesGeneratedQueryShared(contextVk)
594 ? vk::QueryResult::kPrimitivesGeneratedIndex
595 : vk::QueryResult::kDefaultResultIndex);
596 break;
597 default:
598 UNREACHABLE();
599 break;
600 }
601
602 mCachedResultValid = true;
603 return angle::Result::Continue;
604 }
getResult(const gl::Context * context,GLint * params)605 angle::Result QueryVk::getResult(const gl::Context *context, GLint *params)
606 {
607 ANGLE_TRY(getResult(context, true));
608 *params = static_cast<GLint>(mCachedResult);
609 return angle::Result::Continue;
610 }
611
getResult(const gl::Context * context,GLuint * params)612 angle::Result QueryVk::getResult(const gl::Context *context, GLuint *params)
613 {
614 ANGLE_TRY(getResult(context, true));
615 *params = static_cast<GLuint>(mCachedResult);
616 return angle::Result::Continue;
617 }
618
getResult(const gl::Context * context,GLint64 * params)619 angle::Result QueryVk::getResult(const gl::Context *context, GLint64 *params)
620 {
621 ANGLE_TRY(getResult(context, true));
622 *params = static_cast<GLint64>(mCachedResult);
623 return angle::Result::Continue;
624 }
625
getResult(const gl::Context * context,GLuint64 * params)626 angle::Result QueryVk::getResult(const gl::Context *context, GLuint64 *params)
627 {
628 ANGLE_TRY(getResult(context, true));
629 *params = mCachedResult;
630 return angle::Result::Continue;
631 }
632
isResultAvailable(const gl::Context * context,bool * available)633 angle::Result QueryVk::isResultAvailable(const gl::Context *context, bool *available)
634 {
635 ANGLE_TRY(getResult(context, false));
636 *available = mCachedResultValid;
637
638 return angle::Result::Continue;
639 }
640
onTransformFeedbackEnd(GLsizeiptr primitivesDrawn)641 void QueryVk::onTransformFeedbackEnd(GLsizeiptr primitivesDrawn)
642 {
643 mTransformFeedbackPrimitivesDrawn += primitivesDrawn;
644 }
645
getQueryResultCount(ContextVk * contextVk) const646 uint32_t QueryVk::getQueryResultCount(ContextVk *contextVk) const
647 {
648 switch (mType)
649 {
650 case gl::QueryType::PrimitivesGenerated:
651 return IsPrimitivesGeneratedQueryShared(contextVk) ? 2 : 1;
652 case gl::QueryType::TransformFeedbackPrimitivesWritten:
653 return 2;
654 default:
655 return 1;
656 }
657 }
658 } // namespace rx
659