• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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