• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2022 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 // frame_capture_utils.cpp:
7 //   ANGLE Frame capture common classes.
8 //
9 
10 #include "common/frame_capture_utils.h"
11 
12 namespace angle
13 {
14 namespace
15 {
16 // Keep the simplest nullptr string for easy C parsing.
17 constexpr char kNullPointerString[] = "0";
18 }  // anonymous namespace
19 
ParamCapture()20 ParamCapture::ParamCapture() : type(ParamType::TGLenum), enumGroup(gl::GLESEnum::AllEnums) {}
21 
ParamCapture(const char * nameIn,ParamType typeIn)22 ParamCapture::ParamCapture(const char *nameIn, ParamType typeIn)
23     : name(nameIn),
24       type(typeIn),
25       enumGroup(gl::GLESEnum::AllEnums),
26       bigGLEnum(gl::BigGLEnum::AllEnums)
27 {}
28 
29 ParamCapture::~ParamCapture() = default;
30 
ParamCapture(ParamCapture && other)31 ParamCapture::ParamCapture(ParamCapture &&other)
32     : type(ParamType::TGLenum),
33       enumGroup(gl::GLESEnum::AllEnums),
34       bigGLEnum(gl::BigGLEnum::AllEnums)
35 {
36     *this = std::move(other);
37 }
38 
operator =(ParamCapture && other)39 ParamCapture &ParamCapture::operator=(ParamCapture &&other)
40 {
41     std::swap(name, other.name);
42     std::swap(type, other.type);
43     std::swap(value, other.value);
44     std::swap(enumGroup, other.enumGroup);
45     std::swap(bigGLEnum, other.bigGLEnum);
46     std::swap(data, other.data);
47     std::swap(arrayClientPointerIndex, other.arrayClientPointerIndex);
48     std::swap(readBufferSizeBytes, other.readBufferSizeBytes);
49     std::swap(dataNElements, other.dataNElements);
50     return *this;
51 }
52 
ParamBuffer()53 ParamBuffer::ParamBuffer() {}
54 
55 ParamBuffer::~ParamBuffer() = default;
56 
ParamBuffer(ParamBuffer && other)57 ParamBuffer::ParamBuffer(ParamBuffer &&other)
58 {
59     *this = std::move(other);
60 }
61 
operator =(ParamBuffer && other)62 ParamBuffer &ParamBuffer::operator=(ParamBuffer &&other)
63 {
64     std::swap(mParamCaptures, other.mParamCaptures);
65     std::swap(mClientArrayDataParam, other.mClientArrayDataParam);
66     std::swap(mReadBufferSize, other.mReadBufferSize);
67     std::swap(mReturnValueCapture, other.mReturnValueCapture);
68     return *this;
69 }
70 
getParam(const char * paramName,ParamType paramType,int index)71 ParamCapture &ParamBuffer::getParam(const char *paramName, ParamType paramType, int index)
72 {
73     ParamCapture &capture = mParamCaptures[index];
74     ASSERT(capture.name == paramName);
75     ASSERT(capture.type == paramType);
76     return capture;
77 }
78 
getParam(const char * paramName,ParamType paramType,int index) const79 const ParamCapture &ParamBuffer::getParam(const char *paramName,
80                                           ParamType paramType,
81                                           int index) const
82 {
83     return const_cast<ParamBuffer *>(this)->getParam(paramName, paramType, index);
84 }
85 
getParamFlexName(const char * paramName1,const char * paramName2,ParamType paramType,int index)86 ParamCapture &ParamBuffer::getParamFlexName(const char *paramName1,
87                                             const char *paramName2,
88                                             ParamType paramType,
89                                             int index)
90 {
91     ParamCapture &capture = mParamCaptures[index];
92     ASSERT(capture.name == paramName1 || capture.name == paramName2);
93     ASSERT(capture.type == paramType);
94     return capture;
95 }
96 
getParamFlexName(const char * paramName1,const char * paramName2,ParamType paramType,int index) const97 const ParamCapture &ParamBuffer::getParamFlexName(const char *paramName1,
98                                                   const char *paramName2,
99                                                   ParamType paramType,
100                                                   int index) const
101 {
102     return const_cast<ParamBuffer *>(this)->getParamFlexName(paramName1, paramName2, paramType,
103                                                              index);
104 }
105 
addParam(ParamCapture && param)106 void ParamBuffer::addParam(ParamCapture &&param)
107 {
108     if (param.arrayClientPointerIndex != -1)
109     {
110         ASSERT(mClientArrayDataParam == -1);
111         mClientArrayDataParam = static_cast<int>(mParamCaptures.size());
112     }
113 
114     mReadBufferSize = std::max(param.readBufferSizeBytes, mReadBufferSize);
115     mParamCaptures.emplace_back(std::move(param));
116 }
117 
addReturnValue(ParamCapture && returnValue)118 void ParamBuffer::addReturnValue(ParamCapture &&returnValue)
119 {
120     mReturnValueCapture = std::move(returnValue);
121 }
122 
getNextParamName()123 const char *ParamBuffer::getNextParamName()
124 {
125     static const char *kParamNames[] = {"p0",  "p1",  "p2",  "p3",  "p4",  "p5",  "p6",  "p7",
126                                         "p8",  "p9",  "p10", "p11", "p12", "p13", "p14", "p15",
127                                         "p16", "p17", "p18", "p19", "p20", "p21", "p22"};
128     ASSERT(mParamCaptures.size() < ArraySize(kParamNames));
129     return kParamNames[mParamCaptures.size()];
130 }
131 
getClientArrayPointerParameter()132 ParamCapture &ParamBuffer::getClientArrayPointerParameter()
133 {
134     ASSERT(hasClientArrayData());
135     return mParamCaptures[mClientArrayDataParam];
136 }
137 
CallCapture(EntryPoint entryPointIn,ParamBuffer && paramsIn)138 CallCapture::CallCapture(EntryPoint entryPointIn, ParamBuffer &&paramsIn)
139     : entryPoint(entryPointIn), params(std::move(paramsIn))
140 {}
141 
CallCapture(const std::string & customFunctionNameIn,ParamBuffer && paramsIn)142 CallCapture::CallCapture(const std::string &customFunctionNameIn, ParamBuffer &&paramsIn)
143     : entryPoint(EntryPoint::Invalid),
144       customFunctionName(customFunctionNameIn),
145       params(std::move(paramsIn))
146 {}
147 
148 CallCapture::~CallCapture() = default;
149 
CallCapture(CallCapture && other)150 CallCapture::CallCapture(CallCapture &&other)
151 {
152     *this = std::move(other);
153 }
154 
operator =(CallCapture && other)155 CallCapture &CallCapture::operator=(CallCapture &&other)
156 {
157     std::swap(entryPoint, other.entryPoint);
158     std::swap(customFunctionName, other.customFunctionName);
159     std::swap(params, other.params);
160     std::swap(isActive, other.isActive);
161     return *this;
162 }
163 
name() const164 const char *CallCapture::name() const
165 {
166     if (customFunctionName.empty())
167     {
168         ASSERT(entryPoint != EntryPoint::Invalid);
169         return angle::GetEntryPointName(entryPoint);
170     }
171     else
172     {
173         return customFunctionName.c_str();
174     }
175 }
176 
177 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLboolean value)178 void WriteParamValueReplay<ParamType::TGLboolean>(std::ostream &os,
179                                                   const CallCapture &call,
180                                                   GLboolean value)
181 {
182     switch (value)
183     {
184         case GL_TRUE:
185             os << "GL_TRUE";
186             break;
187         case GL_FALSE:
188             os << "GL_FALSE";
189             break;
190         default:
191             os << "0x" << std::hex << std::uppercase << GLint(value);
192     }
193 }
194 
195 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLboolean * value)196 void WriteParamValueReplay<ParamType::TGLbooleanPointer>(std::ostream &os,
197                                                          const CallCapture &call,
198                                                          GLboolean *value)
199 {
200     if (value == 0)
201     {
202         os << kNullPointerString;
203     }
204     else
205     {
206         os << "(GLboolean *)" << static_cast<int>(reinterpret_cast<uintptr_t>(value));
207     }
208 }
209 
210 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,const void * value)211 void WriteParamValueReplay<ParamType::TvoidConstPointer>(std::ostream &os,
212                                                          const CallCapture &call,
213                                                          const void *value)
214 {
215     if (value == 0)
216     {
217         os << kNullPointerString;
218     }
219     else
220     {
221         os << "(const void *)" << static_cast<int>(reinterpret_cast<uintptr_t>(value));
222     }
223 }
224 
225 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,void * value)226 void WriteParamValueReplay<ParamType::TvoidPointer>(std::ostream &os,
227                                                     const CallCapture &call,
228                                                     void *value)
229 {
230     if (value == 0)
231     {
232         os << kNullPointerString;
233     }
234     else
235     {
236         os << "(void *)" << static_cast<int>(reinterpret_cast<uintptr_t>(value));
237     }
238 }
239 
240 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,const GLfloat * value)241 void WriteParamValueReplay<ParamType::TGLfloatConstPointer>(std::ostream &os,
242                                                             const CallCapture &call,
243                                                             const GLfloat *value)
244 {
245     if (value == 0)
246     {
247         os << kNullPointerString;
248     }
249     else
250     {
251         os << "(const GLfloat *)" << static_cast<int>(reinterpret_cast<uintptr_t>(value));
252     }
253 }
254 
255 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,const GLint * value)256 void WriteParamValueReplay<ParamType::TGLintConstPointer>(std::ostream &os,
257                                                           const CallCapture &call,
258                                                           const GLint *value)
259 {
260     if (value == 0)
261     {
262         os << kNullPointerString;
263     }
264     else
265     {
266         os << "(const GLint *)" << static_cast<int>(reinterpret_cast<intptr_t>(value));
267     }
268 }
269 
270 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLsizei * value)271 void WriteParamValueReplay<ParamType::TGLsizeiPointer>(std::ostream &os,
272                                                        const CallCapture &call,
273                                                        GLsizei *value)
274 {
275     if (value == 0)
276     {
277         os << kNullPointerString;
278     }
279     else
280     {
281         os << "(GLsizei *)" << static_cast<int>(reinterpret_cast<intptr_t>(value));
282     }
283 }
284 
285 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,const GLuint * value)286 void WriteParamValueReplay<ParamType::TGLuintConstPointer>(std::ostream &os,
287                                                            const CallCapture &call,
288                                                            const GLuint *value)
289 {
290     if (value == 0)
291     {
292         os << kNullPointerString;
293     }
294     else
295     {
296         os << "(const GLuint *)" << static_cast<int>(reinterpret_cast<uintptr_t>(value));
297     }
298 }
299 
300 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLDEBUGPROCKHR value)301 void WriteParamValueReplay<ParamType::TGLDEBUGPROCKHR>(std::ostream &os,
302                                                        const CallCapture &call,
303                                                        GLDEBUGPROCKHR value)
304 {}
305 
306 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLDEBUGPROC value)307 void WriteParamValueReplay<ParamType::TGLDEBUGPROC>(std::ostream &os,
308                                                     const CallCapture &call,
309                                                     GLDEBUGPROC value)
310 {}
311 
312 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::BufferID value)313 void WriteParamValueReplay<ParamType::TBufferID>(std::ostream &os,
314                                                  const CallCapture &call,
315                                                  gl::BufferID value)
316 {
317     os << "gBufferMap[" << value.value << "]";
318 }
319 
320 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::FenceNVID value)321 void WriteParamValueReplay<ParamType::TFenceNVID>(std::ostream &os,
322                                                   const CallCapture &call,
323                                                   gl::FenceNVID value)
324 {
325     os << "gFenceNVMap[" << value.value << "]";
326 }
327 
328 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::FramebufferID value)329 void WriteParamValueReplay<ParamType::TFramebufferID>(std::ostream &os,
330                                                       const CallCapture &call,
331                                                       gl::FramebufferID value)
332 {
333     os << "gFramebufferMap[" << value.value << "]";
334 }
335 
336 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::MemoryObjectID value)337 void WriteParamValueReplay<ParamType::TMemoryObjectID>(std::ostream &os,
338                                                        const CallCapture &call,
339                                                        gl::MemoryObjectID value)
340 {
341     os << "gMemoryObjectMap[" << value.value << "]";
342 }
343 
344 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::ProgramPipelineID value)345 void WriteParamValueReplay<ParamType::TProgramPipelineID>(std::ostream &os,
346                                                           const CallCapture &call,
347                                                           gl::ProgramPipelineID value)
348 {
349     os << "gProgramPipelineMap[" << value.value << "]";
350 }
351 
352 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::QueryID value)353 void WriteParamValueReplay<ParamType::TQueryID>(std::ostream &os,
354                                                 const CallCapture &call,
355                                                 gl::QueryID value)
356 {
357     os << "gQueryMap[" << value.value << "]";
358 }
359 
360 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::RenderbufferID value)361 void WriteParamValueReplay<ParamType::TRenderbufferID>(std::ostream &os,
362                                                        const CallCapture &call,
363                                                        gl::RenderbufferID value)
364 {
365     os << "gRenderbufferMap[" << value.value << "]";
366 }
367 
368 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::SamplerID value)369 void WriteParamValueReplay<ParamType::TSamplerID>(std::ostream &os,
370                                                   const CallCapture &call,
371                                                   gl::SamplerID value)
372 {
373     os << "gSamplerMap[" << value.value << "]";
374 }
375 
376 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::SemaphoreID value)377 void WriteParamValueReplay<ParamType::TSemaphoreID>(std::ostream &os,
378                                                     const CallCapture &call,
379                                                     gl::SemaphoreID value)
380 {
381     os << "gSemaphoreMap[" << value.value << "]";
382 }
383 
384 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::ShaderProgramID value)385 void WriteParamValueReplay<ParamType::TShaderProgramID>(std::ostream &os,
386                                                         const CallCapture &call,
387                                                         gl::ShaderProgramID value)
388 {
389     os << "gShaderProgramMap[" << value.value << "]";
390 }
391 
392 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::SyncID value)393 void WriteParamValueReplay<ParamType::TSyncID>(std::ostream &os,
394                                                const CallCapture &call,
395                                                gl::SyncID value)
396 {
397     os << "gSyncMap2[" << value.value << "]";
398 }
399 
400 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::TextureID value)401 void WriteParamValueReplay<ParamType::TTextureID>(std::ostream &os,
402                                                   const CallCapture &call,
403                                                   gl::TextureID value)
404 {
405     os << "gTextureMap[" << value.value << "]";
406 }
407 
408 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::TransformFeedbackID value)409 void WriteParamValueReplay<ParamType::TTransformFeedbackID>(std::ostream &os,
410                                                             const CallCapture &call,
411                                                             gl::TransformFeedbackID value)
412 {
413     os << "gTransformFeedbackMap[" << value.value << "]";
414 }
415 
416 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::VertexArrayID value)417 void WriteParamValueReplay<ParamType::TVertexArrayID>(std::ostream &os,
418                                                       const CallCapture &call,
419                                                       gl::VertexArrayID value)
420 {
421     os << "gVertexArrayMap[" << value.value << "]";
422 }
423 
424 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::UniformLocation value)425 void WriteParamValueReplay<ParamType::TUniformLocation>(std::ostream &os,
426                                                         const CallCapture &call,
427                                                         gl::UniformLocation value)
428 {
429     if (value.value == -1)
430     {
431         os << "-1";
432         return;
433     }
434 
435     os << "gUniformLocations[";
436 
437     // Find the program from the call parameters.
438     std::vector<gl::ShaderProgramID> programIDs;
439     if (FindShaderProgramIDsInCall(call, programIDs))
440     {
441         ASSERT(programIDs.size() == 1);
442         os << programIDs[0].value;
443     }
444     else
445     {
446         os << "gCurrentProgram";
447     }
448 
449     os << "][" << value.value << "]";
450 }
451 
452 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::UniformBlockIndex value)453 void WriteParamValueReplay<ParamType::TUniformBlockIndex>(std::ostream &os,
454                                                           const CallCapture &call,
455                                                           gl::UniformBlockIndex value)
456 {
457     // We do not support directly using uniform block indexes due to their multiple indirections.
458     // Use CaptureCustomUniformBlockBinding if you end up hitting this assertion.
459     UNREACHABLE();
460 }
461 
462 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLubyte value)463 void WriteParamValueReplay<ParamType::TGLubyte>(std::ostream &os,
464                                                 const CallCapture &call,
465                                                 GLubyte value)
466 {
467     const int v = value;
468     os << v;
469 }
470 
471 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,EGLDEBUGPROCKHR value)472 void WriteParamValueReplay<ParamType::TEGLDEBUGPROCKHR>(std::ostream &os,
473                                                         const CallCapture &call,
474                                                         EGLDEBUGPROCKHR value)
475 {
476     // It's not necessary to implement correct capture for these types.
477     os << "0";
478 }
479 
480 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,EGLGetBlobFuncANDROID value)481 void WriteParamValueReplay<ParamType::TEGLGetBlobFuncANDROID>(std::ostream &os,
482                                                               const CallCapture &call,
483                                                               EGLGetBlobFuncANDROID value)
484 {
485     // It's not necessary to implement correct capture for these types.
486     os << "0";
487 }
488 
489 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,EGLSetBlobFuncANDROID value)490 void WriteParamValueReplay<ParamType::TEGLSetBlobFuncANDROID>(std::ostream &os,
491                                                               const CallCapture &call,
492                                                               EGLSetBlobFuncANDROID value)
493 {
494     // It's not necessary to implement correct capture for these types.
495     os << "0";
496 }
497 
498 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,egl::Config * value)499 void WriteParamValueReplay<ParamType::Tegl_ConfigPointer>(std::ostream &os,
500                                                           const CallCapture &call,
501                                                           egl::Config *value)
502 {
503     os << "EGL_NO_CONFIG_KHR";
504 }
505 
506 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,egl::SurfaceID value)507 void WriteParamValueReplay<ParamType::TSurfaceID>(std::ostream &os,
508                                                   const CallCapture &call,
509                                                   egl::SurfaceID value)
510 {
511     os << "gSurfaceMap2[" << value.value << "]";
512 }
513 
514 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::ContextID value)515 void WriteParamValueReplay<ParamType::TContextID>(std::ostream &os,
516                                                   const CallCapture &call,
517                                                   gl::ContextID value)
518 {
519     os << "gContextMap2[" << value.value << "]";
520 }
521 
522 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,egl::Display * value)523 void WriteParamValueReplay<ParamType::Tegl_DisplayPointer>(std::ostream &os,
524                                                            const CallCapture &call,
525                                                            egl::Display *value)
526 {
527     os << "gEGLDisplay";
528 }
529 
530 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,egl::ImageID value)531 void WriteParamValueReplay<ParamType::TImageID>(std::ostream &os,
532                                                 const CallCapture &call,
533                                                 egl::ImageID value)
534 {
535     os << "gEGLImageMap2[" << value.value << "]";
536 }
537 
538 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,EGLClientBuffer value)539 void WriteParamValueReplay<ParamType::TEGLClientBuffer>(std::ostream &os,
540                                                         const CallCapture &call,
541                                                         EGLClientBuffer value)
542 {
543     os << value;
544 }
545 
546 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,egl::SyncID value)547 void WriteParamValueReplay<ParamType::Tegl_SyncID>(std::ostream &os,
548                                                    const CallCapture &call,
549                                                    egl::SyncID value)
550 {
551     os << "gEGLSyncMap[" << value.value << "]";
552 }
553 
554 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,const EGLAttrib * value)555 void WriteParamValueReplay<ParamType::TEGLAttribPointer>(std::ostream &os,
556                                                          const CallCapture &call,
557                                                          const EGLAttrib *value)
558 {
559     if (value == 0)
560     {
561         os << kNullPointerString;
562     }
563     else
564     {
565         os << "(const EGLAttrib *)" << static_cast<int>(reinterpret_cast<uintptr_t>(value));
566     }
567 }
568 
569 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,const EGLint * value)570 void WriteParamValueReplay<ParamType::TEGLintConstPointer>(std::ostream &os,
571                                                            const CallCapture &call,
572                                                            const EGLint *value)
573 {
574     if (value == 0)
575     {
576         os << kNullPointerString;
577     }
578     else
579     {
580         os << "(const EGLint *)" << static_cast<int>(reinterpret_cast<uintptr_t>(value));
581     }
582 }
583 
584 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,EGLint * value)585 void WriteParamValueReplay<ParamType::TEGLintPointer>(std::ostream &os,
586                                                       const CallCapture &call,
587                                                       EGLint *value)
588 {
589     if (value == 0)
590     {
591         os << kNullPointerString;
592     }
593     else
594     {
595         os << "(const EGLint *)" << static_cast<int>(reinterpret_cast<uintptr_t>(value));
596     }
597 }
598 
599 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,EGLTime value)600 void WriteParamValueReplay<ParamType::TEGLTime>(std::ostream &os,
601                                                 const CallCapture &call,
602                                                 EGLTime value)
603 {
604     os << value << "ul";
605 }
606 
607 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,EGLTimeKHR value)608 void WriteParamValueReplay<ParamType::TEGLTimeKHR>(std::ostream &os,
609                                                    const CallCapture &call,
610                                                    EGLTimeKHR value)
611 {
612     os << value << "ul";
613 }
614 
FindShaderProgramIDsInCall(const CallCapture & call,std::vector<gl::ShaderProgramID> & idsOut)615 bool FindShaderProgramIDsInCall(const CallCapture &call, std::vector<gl::ShaderProgramID> &idsOut)
616 {
617     for (const ParamCapture &param : call.params.getParamCaptures())
618     {
619         // Only checking for programs right now, but could be expanded to all ResourceTypes
620         if (param.type == ParamType::TShaderProgramID)
621         {
622             idsOut.push_back(param.value.ShaderProgramIDVal);
623         }
624     }
625 
626     return !idsOut.empty();
627 }
628 }  // namespace angle
629