xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/vulkan/QueryVk.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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/TransformFeedbackVk.h"
15 #include "libANGLE/renderer/vulkan/vk_renderer.h"
16 
17 #include "common/debug.h"
18 
19 namespace rx
20 {
21 
22 namespace
23 {
24 struct QueryReleaseHelper
25 {
operator ()rx::__anon14d9df8f0111::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(vk::Renderer * renderer) const442 bool QueryVk::isCurrentlyInUse(vk::Renderer *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     vk::Renderer *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     vk::Renderer *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->flushAndSubmitCommands(nullptr, nullptr,
496                                                     RenderPassClosureReason::GetQueryResult));
497 
498         ASSERT(contextVk->getRenderer()->hasResourceUseSubmitted(
499             mQueryHelperTimeElapsedBegin.getResourceUse()));
500         ASSERT(
501             contextVk->getRenderer()->hasResourceUseSubmitted(mQueryHelper.get().getResourceUse()));
502     }
503 
504     // If the command buffer this query is being written to is still in flight and uses
505     // vkCmdResetQueryPool, its reset command may not have been performed by the GPU yet.  To avoid
506     // a race condition in this case, wait for the batch to finish first before querying (or return
507     // not-ready if not waiting).
508     if (isCurrentlyInUse(renderer) &&
509         (!renderer->getFeatures().supportsHostQueryReset.enabled ||
510          renderer->getFeatures().forceWaitForSubmissionToCompleteForQueryResult.enabled ||
511          renderer->isAsyncCommandQueueEnabled()))
512     {
513         // The query might appear busy because there was no check for completed commands
514         // recently. Do that now and see if the query is still busy.  If the application is
515         // looping until the query results become available, there wouldn't be any forward
516         // progress without this.
517         ANGLE_TRY(renderer->checkCompletedCommandsAndCleanup(contextVk));
518 
519         if (isCurrentlyInUse(renderer))
520         {
521             if (!wait)
522             {
523                 return angle::Result::Continue;
524             }
525             ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_HIGH,
526                                   "GPU stall due to waiting on uncompleted query");
527 
528             // Assert that the work has been sent to the GPU
529             ASSERT(!contextVk->hasUnsubmittedUse(mQueryHelper.get()));
530             ANGLE_TRY(finishRunningCommands(contextVk));
531         }
532     }
533 
534     // If its a render pass query, the current query helper must have commands recorded (i.e. it's
535     // not a newly allocated query with the actual queries all stashed).  If this is not respected
536     // and !wait, |mQueryHelper.get().getUint64ResultNonBlocking()| will tell that the result is
537     // readily available, which may not be true.  The subsequent calls to |getUint64Result()| on the
538     // stashed queries will incur a wait that is not desired by the application.
539     ASSERT(!IsRenderPassQuery(contextVk, mType) || mQueryHelper.get().hasSubmittedCommands());
540 
541     vk::QueryResult result(getQueryResultCount(contextVk));
542 
543     if (wait)
544     {
545         ANGLE_TRY(mQueryHelper.get().getUint64Result(contextVk, &result));
546         ANGLE_TRY(accumulateStashedQueryResult(contextVk, &result));
547     }
548     else
549     {
550         bool available = false;
551         ANGLE_TRY(mQueryHelper.get().getUint64ResultNonBlocking(contextVk, &result, &available));
552         if (!available)
553         {
554             // If the results are not ready, do nothing.  mCachedResultValid remains false.
555             return angle::Result::Continue;
556         }
557         ANGLE_TRY(accumulateStashedQueryResult(contextVk, &result));
558     }
559 
560     double timestampPeriod = renderer->getPhysicalDeviceProperties().limits.timestampPeriod;
561 
562     // Fix up the results to what OpenGL expects.
563     switch (mType)
564     {
565         case gl::QueryType::AnySamples:
566         case gl::QueryType::AnySamplesConservative:
567             // OpenGL query result in these cases is binary
568             mCachedResult = !!result.getResult(vk::QueryResult::kDefaultResultIndex);
569             break;
570         case gl::QueryType::Timestamp:
571             mCachedResult = static_cast<uint64_t>(
572                 result.getResult(vk::QueryResult::kDefaultResultIndex) * timestampPeriod);
573             break;
574         case gl::QueryType::TimeElapsed:
575         {
576             vk::QueryResult timeElapsedBegin(1);
577 
578             // Since the result of the end query of time-elapsed is already available, the
579             // result of begin query must be available too.
580             ANGLE_TRY(mQueryHelperTimeElapsedBegin.getUint64Result(contextVk, &timeElapsedBegin));
581 
582             uint64_t delta = result.getResult(vk::QueryResult::kDefaultResultIndex) -
583                              timeElapsedBegin.getResult(vk::QueryResult::kDefaultResultIndex);
584             mCachedResult = static_cast<uint64_t>(delta * timestampPeriod);
585             break;
586         }
587         case gl::QueryType::TransformFeedbackPrimitivesWritten:
588             mCachedResult =
589                 result.getResult(IsPrimitivesGeneratedQueryShared(contextVk)
590                                      ? vk::QueryResult::kTransformFeedbackPrimitivesWrittenIndex
591                                      : vk::QueryResult::kDefaultResultIndex);
592             break;
593         case gl::QueryType::PrimitivesGenerated:
594             mCachedResult = result.getResult(IsPrimitivesGeneratedQueryShared(contextVk)
595                                                  ? vk::QueryResult::kPrimitivesGeneratedIndex
596                                                  : vk::QueryResult::kDefaultResultIndex);
597             break;
598         default:
599             UNREACHABLE();
600             break;
601     }
602 
603     mCachedResultValid = true;
604     return angle::Result::Continue;
605 }
getResult(const gl::Context * context,GLint * params)606 angle::Result QueryVk::getResult(const gl::Context *context, GLint *params)
607 {
608     ANGLE_TRY(getResult(context, true));
609     *params = static_cast<GLint>(mCachedResult);
610     return angle::Result::Continue;
611 }
612 
getResult(const gl::Context * context,GLuint * params)613 angle::Result QueryVk::getResult(const gl::Context *context, GLuint *params)
614 {
615     ANGLE_TRY(getResult(context, true));
616     *params = static_cast<GLuint>(mCachedResult);
617     return angle::Result::Continue;
618 }
619 
getResult(const gl::Context * context,GLint64 * params)620 angle::Result QueryVk::getResult(const gl::Context *context, GLint64 *params)
621 {
622     ANGLE_TRY(getResult(context, true));
623     *params = static_cast<GLint64>(mCachedResult);
624     return angle::Result::Continue;
625 }
626 
getResult(const gl::Context * context,GLuint64 * params)627 angle::Result QueryVk::getResult(const gl::Context *context, GLuint64 *params)
628 {
629     ANGLE_TRY(getResult(context, true));
630     *params = mCachedResult;
631     return angle::Result::Continue;
632 }
633 
isResultAvailable(const gl::Context * context,bool * available)634 angle::Result QueryVk::isResultAvailable(const gl::Context *context, bool *available)
635 {
636     ANGLE_TRY(getResult(context, false));
637     *available = mCachedResultValid;
638 
639     return angle::Result::Continue;
640 }
641 
onTransformFeedbackEnd(GLsizeiptr primitivesDrawn)642 void QueryVk::onTransformFeedbackEnd(GLsizeiptr primitivesDrawn)
643 {
644     mTransformFeedbackPrimitivesDrawn += primitivesDrawn;
645 }
646 
getQueryResultCount(ContextVk * contextVk) const647 uint32_t QueryVk::getQueryResultCount(ContextVk *contextVk) const
648 {
649     switch (mType)
650     {
651         case gl::QueryType::PrimitivesGenerated:
652             return IsPrimitivesGeneratedQueryShared(contextVk) ? 2 : 1;
653         case gl::QueryType::TransformFeedbackPrimitivesWritten:
654             return 2;
655         default:
656             return 1;
657     }
658 }
659 }  // namespace rx
660