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 &¶m)
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 &¶msIn)
139 : entryPoint(entryPointIn), params(std::move(paramsIn))
140 {}
141
CallCapture(const std::string & customFunctionNameIn,ParamBuffer && paramsIn)142 CallCapture::CallCapture(const std::string &customFunctionNameIn, ParamBuffer &¶msIn)
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 std::swap(contextID, other.contextID);
162 std::swap(isSyncPoint, other.isSyncPoint);
163 return *this;
164 }
165
name() const166 const char *CallCapture::name() const
167 {
168 if (customFunctionName.empty())
169 {
170 ASSERT(entryPoint != EntryPoint::Invalid);
171 return angle::GetEntryPointName(entryPoint);
172 }
173 else
174 {
175 return customFunctionName.c_str();
176 }
177 }
178
179 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLboolean value)180 void WriteParamValueReplay<ParamType::TGLboolean>(std::ostream &os,
181 const CallCapture &call,
182 GLboolean value)
183 {
184 switch (value)
185 {
186 case GL_TRUE:
187 os << "GL_TRUE";
188 break;
189 case GL_FALSE:
190 os << "GL_FALSE";
191 break;
192 default:
193 os << "0x" << std::hex << std::uppercase << GLint(value);
194 }
195 }
196
197 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLboolean * value)198 void WriteParamValueReplay<ParamType::TGLbooleanPointer>(std::ostream &os,
199 const CallCapture &call,
200 GLboolean *value)
201 {
202 if (value == 0)
203 {
204 os << kNullPointerString;
205 }
206 else
207 {
208 os << "(GLboolean *)" << static_cast<int>(reinterpret_cast<uintptr_t>(value));
209 }
210 }
211
212 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,const void * value)213 void WriteParamValueReplay<ParamType::TvoidConstPointer>(std::ostream &os,
214 const CallCapture &call,
215 const void *value)
216 {
217 if (value == 0)
218 {
219 os << kNullPointerString;
220 }
221 else
222 {
223 os << "(const void *)" << static_cast<int>(reinterpret_cast<uintptr_t>(value));
224 }
225 }
226
227 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,void * value)228 void WriteParamValueReplay<ParamType::TvoidPointer>(std::ostream &os,
229 const CallCapture &call,
230 void *value)
231 {
232 if (value == 0)
233 {
234 os << kNullPointerString;
235 }
236 else
237 {
238 os << "(void *)" << static_cast<int>(reinterpret_cast<uintptr_t>(value));
239 }
240 }
241
242 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,const GLfloat * value)243 void WriteParamValueReplay<ParamType::TGLfloatConstPointer>(std::ostream &os,
244 const CallCapture &call,
245 const GLfloat *value)
246 {
247 if (value == 0)
248 {
249 os << kNullPointerString;
250 }
251 else
252 {
253 os << "(const GLfloat *)" << static_cast<int>(reinterpret_cast<uintptr_t>(value));
254 }
255 }
256
257 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,const GLint * value)258 void WriteParamValueReplay<ParamType::TGLintConstPointer>(std::ostream &os,
259 const CallCapture &call,
260 const GLint *value)
261 {
262 if (value == 0)
263 {
264 os << kNullPointerString;
265 }
266 else
267 {
268 os << "(const GLint *)" << static_cast<int>(reinterpret_cast<intptr_t>(value));
269 }
270 }
271
272 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLsizei * value)273 void WriteParamValueReplay<ParamType::TGLsizeiPointer>(std::ostream &os,
274 const CallCapture &call,
275 GLsizei *value)
276 {
277 if (value == 0)
278 {
279 os << kNullPointerString;
280 }
281 else
282 {
283 os << "(GLsizei *)" << static_cast<int>(reinterpret_cast<intptr_t>(value));
284 }
285 }
286
287 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLuint * value)288 void WriteParamValueReplay<ParamType::TGLuintPointer>(std::ostream &os,
289 const CallCapture &call,
290 GLuint *value)
291 {
292 if (value == 0)
293 {
294 os << kNullPointerString;
295 }
296 else
297 {
298 os << "(GLuint *)" << static_cast<int>(reinterpret_cast<uintptr_t>(value));
299 }
300 }
301
302 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,const GLuint * value)303 void WriteParamValueReplay<ParamType::TGLuintConstPointer>(std::ostream &os,
304 const CallCapture &call,
305 const GLuint *value)
306 {
307 if (value == 0)
308 {
309 os << kNullPointerString;
310 }
311 else
312 {
313 os << "(const GLuint *)" << static_cast<int>(reinterpret_cast<uintptr_t>(value));
314 }
315 }
316
317 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLDEBUGPROCKHR value)318 void WriteParamValueReplay<ParamType::TGLDEBUGPROCKHR>(std::ostream &os,
319 const CallCapture &call,
320 GLDEBUGPROCKHR value)
321 {}
322
323 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLDEBUGPROC value)324 void WriteParamValueReplay<ParamType::TGLDEBUGPROC>(std::ostream &os,
325 const CallCapture &call,
326 GLDEBUGPROC value)
327 {}
328
329 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::BufferID value)330 void WriteParamValueReplay<ParamType::TBufferID>(std::ostream &os,
331 const CallCapture &call,
332 gl::BufferID value)
333 {
334 os << "gBufferMap[" << value.value << "]";
335 }
336
337 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::FenceNVID value)338 void WriteParamValueReplay<ParamType::TFenceNVID>(std::ostream &os,
339 const CallCapture &call,
340 gl::FenceNVID value)
341 {
342 os << "gFenceNVMap[" << value.value << "]";
343 }
344
345 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::FramebufferID value)346 void WriteParamValueReplay<ParamType::TFramebufferID>(std::ostream &os,
347 const CallCapture &call,
348 gl::FramebufferID value)
349 {
350 os << "gFramebufferMapPerContext[" << call.contextID.value << "][" << value.value << "]";
351 }
352
353 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::MemoryObjectID value)354 void WriteParamValueReplay<ParamType::TMemoryObjectID>(std::ostream &os,
355 const CallCapture &call,
356 gl::MemoryObjectID value)
357 {
358 os << "gMemoryObjectMap[" << value.value << "]";
359 }
360
361 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::ProgramPipelineID value)362 void WriteParamValueReplay<ParamType::TProgramPipelineID>(std::ostream &os,
363 const CallCapture &call,
364 gl::ProgramPipelineID value)
365 {
366 os << "gProgramPipelineMap[" << value.value << "]";
367 }
368
369 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::QueryID value)370 void WriteParamValueReplay<ParamType::TQueryID>(std::ostream &os,
371 const CallCapture &call,
372 gl::QueryID value)
373 {
374 os << "gQueryMap[" << value.value << "]";
375 }
376
377 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::RenderbufferID value)378 void WriteParamValueReplay<ParamType::TRenderbufferID>(std::ostream &os,
379 const CallCapture &call,
380 gl::RenderbufferID value)
381 {
382 os << "gRenderbufferMap[" << value.value << "]";
383 }
384
385 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::SamplerID value)386 void WriteParamValueReplay<ParamType::TSamplerID>(std::ostream &os,
387 const CallCapture &call,
388 gl::SamplerID value)
389 {
390 os << "gSamplerMap[" << value.value << "]";
391 }
392
393 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::SemaphoreID value)394 void WriteParamValueReplay<ParamType::TSemaphoreID>(std::ostream &os,
395 const CallCapture &call,
396 gl::SemaphoreID value)
397 {
398 os << "gSemaphoreMap[" << value.value << "]";
399 }
400
401 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::ShaderProgramID value)402 void WriteParamValueReplay<ParamType::TShaderProgramID>(std::ostream &os,
403 const CallCapture &call,
404 gl::ShaderProgramID value)
405 {
406 os << "gShaderProgramMap[" << value.value << "]";
407 }
408
409 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::SyncID value)410 void WriteParamValueReplay<ParamType::TSyncID>(std::ostream &os,
411 const CallCapture &call,
412 gl::SyncID value)
413 {
414 os << "gSyncMap2[" << value.value << "]";
415 }
416
417 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::TextureID value)418 void WriteParamValueReplay<ParamType::TTextureID>(std::ostream &os,
419 const CallCapture &call,
420 gl::TextureID value)
421 {
422 os << "gTextureMap[" << value.value << "]";
423 }
424
425 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::TransformFeedbackID value)426 void WriteParamValueReplay<ParamType::TTransformFeedbackID>(std::ostream &os,
427 const CallCapture &call,
428 gl::TransformFeedbackID value)
429 {
430 os << "gTransformFeedbackMap[" << value.value << "]";
431 }
432
433 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::VertexArrayID value)434 void WriteParamValueReplay<ParamType::TVertexArrayID>(std::ostream &os,
435 const CallCapture &call,
436 gl::VertexArrayID value)
437 {
438 os << "gVertexArrayMap[" << value.value << "]";
439 }
440
441 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::UniformLocation value)442 void WriteParamValueReplay<ParamType::TUniformLocation>(std::ostream &os,
443 const CallCapture &call,
444 gl::UniformLocation value)
445 {
446 if (value.value == -1)
447 {
448 os << "-1";
449 return;
450 }
451
452 os << "gUniformLocations[";
453
454 // Find the program from the call parameters.
455 std::vector<gl::ShaderProgramID> shaderProgramIDs;
456 if (FindResourceIDsInCall<gl::ShaderProgramID>(call, shaderProgramIDs))
457 {
458 ASSERT(shaderProgramIDs.size() == 1);
459 os << shaderProgramIDs[0].value;
460 }
461 else
462 {
463 os << "gCurrentProgram";
464 }
465
466 os << "][" << value.value << "]";
467 }
468
469 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::UniformBlockIndex value)470 void WriteParamValueReplay<ParamType::TUniformBlockIndex>(std::ostream &os,
471 const CallCapture &call,
472 gl::UniformBlockIndex value)
473 {
474 // We do not support directly using uniform block indexes due to their multiple indirections.
475 // Use CaptureCustomUniformBlockBinding if you end up hitting this assertion.
476 UNREACHABLE();
477 }
478
479 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLubyte value)480 void WriteParamValueReplay<ParamType::TGLubyte>(std::ostream &os,
481 const CallCapture &call,
482 GLubyte value)
483 {
484 const int v = value;
485 os << v;
486 }
487
488 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,EGLDEBUGPROCKHR value)489 void WriteParamValueReplay<ParamType::TEGLDEBUGPROCKHR>(std::ostream &os,
490 const CallCapture &call,
491 EGLDEBUGPROCKHR value)
492 {
493 // It's not necessary to implement correct capture for these types.
494 os << "0";
495 }
496
497 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,EGLGetBlobFuncANDROID value)498 void WriteParamValueReplay<ParamType::TEGLGetBlobFuncANDROID>(std::ostream &os,
499 const CallCapture &call,
500 EGLGetBlobFuncANDROID value)
501 {
502 // It's not necessary to implement correct capture for these types.
503 os << "0";
504 }
505
506 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,EGLSetBlobFuncANDROID value)507 void WriteParamValueReplay<ParamType::TEGLSetBlobFuncANDROID>(std::ostream &os,
508 const CallCapture &call,
509 EGLSetBlobFuncANDROID value)
510 {
511 // It's not necessary to implement correct capture for these types.
512 os << "0";
513 }
514
515 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,egl::Config * value)516 void WriteParamValueReplay<ParamType::Tegl_ConfigPointer>(std::ostream &os,
517 const CallCapture &call,
518 egl::Config *value)
519 {
520 os << "EGL_NO_CONFIG_KHR";
521 }
522
523 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,egl::SurfaceID value)524 void WriteParamValueReplay<ParamType::TSurfaceID>(std::ostream &os,
525 const CallCapture &call,
526 egl::SurfaceID value)
527 {
528 os << "gSurfaceMap2[" << value.value << "]";
529 }
530
531 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::ContextID value)532 void WriteParamValueReplay<ParamType::TContextID>(std::ostream &os,
533 const CallCapture &call,
534 gl::ContextID value)
535 {
536 os << "gContextMap2[" << value.value << "]";
537 }
538
539 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,egl::Display * value)540 void WriteParamValueReplay<ParamType::Tegl_DisplayPointer>(std::ostream &os,
541 const CallCapture &call,
542 egl::Display *value)
543 {
544 os << "gEGLDisplay";
545 }
546
547 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,egl::ImageID value)548 void WriteParamValueReplay<ParamType::TImageID>(std::ostream &os,
549 const CallCapture &call,
550 egl::ImageID value)
551 {
552 os << "gEGLImageMap2[" << value.value << "]";
553 }
554
555 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,EGLClientBuffer value)556 void WriteParamValueReplay<ParamType::TEGLClientBuffer>(std::ostream &os,
557 const CallCapture &call,
558 EGLClientBuffer value)
559 {
560 os << value;
561 }
562
563 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,egl::SyncID value)564 void WriteParamValueReplay<ParamType::Tegl_SyncID>(std::ostream &os,
565 const CallCapture &call,
566 egl::SyncID value)
567 {
568 os << "gEGLSyncMap[" << value.value << "]";
569 }
570
571 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,EGLAttrib * value)572 void WriteParamValueReplay<ParamType::TEGLAttribPointer>(std::ostream &os,
573 const CallCapture &call,
574 EGLAttrib *value)
575 {
576 if (value == 0)
577 {
578 os << kNullPointerString;
579 }
580 else
581 {
582 os << "(EGLAttrib *)" << static_cast<int>(reinterpret_cast<uintptr_t>(value));
583 }
584 }
585
586 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,const EGLAttrib * value)587 void WriteParamValueReplay<ParamType::TEGLAttribConstPointer>(std::ostream &os,
588 const CallCapture &call,
589 const EGLAttrib *value)
590 {
591 if (value == 0)
592 {
593 os << kNullPointerString;
594 }
595 else
596 {
597 os << "(const EGLAttrib *)" << static_cast<int>(reinterpret_cast<uintptr_t>(value));
598 }
599 }
600
601 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,const EGLint * value)602 void WriteParamValueReplay<ParamType::TEGLintConstPointer>(std::ostream &os,
603 const CallCapture &call,
604 const EGLint *value)
605 {
606 if (value == 0)
607 {
608 os << kNullPointerString;
609 }
610 else
611 {
612 os << "(const EGLint *)" << static_cast<int>(reinterpret_cast<uintptr_t>(value));
613 }
614 }
615
616 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,EGLint * value)617 void WriteParamValueReplay<ParamType::TEGLintPointer>(std::ostream &os,
618 const CallCapture &call,
619 EGLint *value)
620 {
621 if (value == 0)
622 {
623 os << kNullPointerString;
624 }
625 else
626 {
627 os << "(const EGLint *)" << static_cast<int>(reinterpret_cast<uintptr_t>(value));
628 }
629 }
630
631 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,EGLTime value)632 void WriteParamValueReplay<ParamType::TEGLTime>(std::ostream &os,
633 const CallCapture &call,
634 EGLTime value)
635 {
636 os << value << "ul";
637 }
638
639 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,EGLTimeKHR value)640 void WriteParamValueReplay<ParamType::TEGLTimeKHR>(std::ostream &os,
641 const CallCapture &call,
642 EGLTimeKHR value)
643 {
644 os << value << "ul";
645 }
646
647 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLGETBLOBPROCANGLE value)648 void WriteParamValueReplay<ParamType::TGLGETBLOBPROCANGLE>(std::ostream &os,
649 const CallCapture &call,
650 GLGETBLOBPROCANGLE value)
651 {
652 // It's not necessary to implement correct capture for these types.
653 os << "0";
654 }
655
656 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLSETBLOBPROCANGLE value)657 void WriteParamValueReplay<ParamType::TGLSETBLOBPROCANGLE>(std::ostream &os,
658 const CallCapture &call,
659 GLSETBLOBPROCANGLE value)
660 {
661 // It's not necessary to implement correct capture for these types.
662 os << "0";
663 }
664
665 template <typename ParamValueType>
FindResourceIDsInCall(const CallCapture & call,std::vector<ParamValueType> & idsOut)666 bool FindResourceIDsInCall(const CallCapture &call, std::vector<ParamValueType> &idsOut)
667 {
668 const ParamType paramType = ParamValueTrait<ParamValueType>::typeID;
669 for (const ParamCapture ¶m : call.params.getParamCaptures())
670 {
671 if (param.type == paramType)
672 {
673 const ParamValueType id = AccessParamValue<ParamValueType>(paramType, param.value);
674 idsOut.push_back(id);
675 }
676 }
677
678 return !idsOut.empty();
679 }
680
681 // Explicit instantiation
682 template bool FindResourceIDsInCall<gl::TextureID>(const CallCapture &call,
683 std::vector<gl::TextureID> &idsOut);
684 template bool FindResourceIDsInCall<gl::ShaderProgramID>(const CallCapture &call,
685 std::vector<gl::ShaderProgramID> &idsOut);
686 } // namespace angle
687