• 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::__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