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