1 //
2 // Copyright 2019 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 // FrameCapture.cpp:
7 // ANGLE Frame capture implementation.
8 //
9
10 #include "libANGLE/FrameCapture.h"
11
12 #include <cerrno>
13 #include <cstring>
14 #include <fstream>
15 #include <string>
16
17 #include "sys/stat.h"
18
19 #include "common/system_utils.h"
20 #include "libANGLE/Context.h"
21 #include "libANGLE/Framebuffer.h"
22 #include "libANGLE/Query.h"
23 #include "libANGLE/ResourceMap.h"
24 #include "libANGLE/Shader.h"
25 #include "libANGLE/VertexArray.h"
26 #include "libANGLE/capture_gles_2_0_autogen.h"
27 #include "libANGLE/capture_gles_3_0_autogen.h"
28 #include "libANGLE/gl_enum_utils.h"
29 #include "libANGLE/queryconversions.h"
30 #include "libANGLE/queryutils.h"
31
32 #define USE_SYSTEM_ZLIB
33 #include "compression_utils_portable.h"
34
35 #if !ANGLE_CAPTURE_ENABLED
36 # error Frame capture must be enbled to include this file.
37 #endif // !ANGLE_CAPTURE_ENABLED
38
39 namespace angle
40 {
41 namespace
42 {
43
44 constexpr char kEnabledVarName[] = "ANGLE_CAPTURE_ENABLED";
45 constexpr char kOutDirectoryVarName[] = "ANGLE_CAPTURE_OUT_DIR";
46 constexpr char kFrameStartVarName[] = "ANGLE_CAPTURE_FRAME_START";
47 constexpr char kFrameEndVarName[] = "ANGLE_CAPTURE_FRAME_END";
48 constexpr char kCaptureLabel[] = "ANGLE_CAPTURE_LABEL";
49 constexpr char kCompression[] = "ANGLE_CAPTURE_COMPRESSION";
50
51 #if defined(ANGLE_PLATFORM_ANDROID)
52
53 constexpr char kAndroidCaptureEnabled[] = "debug.angle.capture.enabled";
54 constexpr char kAndroidOutDir[] = "debug.angle.capture.out_dir";
55 constexpr char kAndroidFrameStart[] = "debug.angle.capture.frame_start";
56 constexpr char kAndroidFrameEnd[] = "debug.angle.capture.frame_end";
57 constexpr char kAndroidCaptureLabel[] = "debug.angle.capture.label";
58 constexpr char kAndroidCompression[] = "debug.angle.capture.compression";
59
60 constexpr int kStreamSize = 64;
61
62 constexpr char kAndroidOutputSubdir[] = "/angle_capture/";
63
64 // Call out to 'getprop' on a shell and return a string if the value was set
AndroidGetEnvFromProp(const char * key)65 std::string AndroidGetEnvFromProp(const char *key)
66 {
67 std::string command("getprop ");
68 command += key;
69
70 // Run the command and open a I/O stream to read results
71 char stream[kStreamSize] = {};
72 FILE *pipe = popen(command.c_str(), "r");
73 if (pipe != nullptr)
74 {
75 fgets(stream, kStreamSize, pipe);
76 pclose(pipe);
77 }
78
79 // Right strip white space
80 std::string result(stream);
81 result.erase(result.find_last_not_of(" \n\r\t") + 1);
82 return result;
83 }
84
PrimeAndroidEnvironmentVariables()85 void PrimeAndroidEnvironmentVariables()
86 {
87 std::string enabled = AndroidGetEnvFromProp(kAndroidCaptureEnabled);
88 if (!enabled.empty())
89 {
90 INFO() << "Frame capture read " << enabled << " from " << kAndroidCaptureEnabled;
91 setenv(kEnabledVarName, enabled.c_str(), 1);
92 }
93
94 std::string outDir = AndroidGetEnvFromProp(kAndroidOutDir);
95 if (!outDir.empty())
96 {
97 INFO() << "Frame capture read " << outDir << " from " << kAndroidOutDir;
98 setenv(kOutDirectoryVarName, outDir.c_str(), 1);
99 }
100
101 std::string frameStart = AndroidGetEnvFromProp(kAndroidFrameStart);
102 if (!frameStart.empty())
103 {
104 INFO() << "Frame capture read " << frameStart << " from " << kAndroidFrameStart;
105 setenv(kFrameStartVarName, frameStart.c_str(), 1);
106 }
107
108 std::string frameEnd = AndroidGetEnvFromProp(kAndroidFrameEnd);
109 if (!frameEnd.empty())
110 {
111 INFO() << "Frame capture read " << frameEnd << " from " << kAndroidFrameEnd;
112 setenv(kFrameEndVarName, frameEnd.c_str(), 1);
113 }
114
115 std::string captureLabel = AndroidGetEnvFromProp(kAndroidCaptureLabel);
116 if (!captureLabel.empty())
117 {
118 INFO() << "Frame capture read " << captureLabel << " from " << kAndroidCaptureLabel;
119 setenv(kCaptureLabel, captureLabel.c_str(), 1);
120 }
121
122 std::string compression = AndroidGetEnvFromProp(kAndroidCompression);
123 if (!compression.empty())
124 {
125 INFO() << "Frame capture read " << compression << " from " << kAndroidCompression;
126 setenv(kCompression, compression.c_str(), 1);
127 }
128 }
129 #endif
130
GetDefaultOutDirectory()131 std::string GetDefaultOutDirectory()
132 {
133 #if defined(ANGLE_PLATFORM_ANDROID)
134 std::string path = "/sdcard/Android/data/";
135
136 // Linux interface to get application id of the running process
137 FILE *cmdline = fopen("/proc/self/cmdline", "r");
138 char applicationId[512];
139 if (cmdline)
140 {
141 fread(applicationId, 1, sizeof(applicationId), cmdline);
142 fclose(cmdline);
143
144 // Some package may have application id as <app_name>:<cmd_name>
145 char *colonSep = strchr(applicationId, ':');
146 if (colonSep)
147 {
148 *colonSep = '\0';
149 }
150 }
151 else
152 {
153 ERR() << "not able to lookup application id";
154 }
155
156 path += std::string(applicationId) + kAndroidOutputSubdir;
157
158 // Check for existance of output path
159 struct stat dir_stat;
160 if (stat(path.c_str(), &dir_stat) == -1)
161 {
162 ERR() << "Output directory '" << path
163 << "' does not exist. Create it over adb using mkdir.";
164 }
165
166 return path;
167 #else
168 return std::string("./");
169 #endif // defined(ANGLE_PLATFORM_ANDROID)
170 }
171
172 struct FmtCapturePrefix
173 {
FmtCapturePrefixangle::__anoncf1522460111::FmtCapturePrefix174 FmtCapturePrefix(gl::ContextID contextIdIn, const std::string &captureLabelIn)
175 : contextId(contextIdIn), captureLabel(captureLabelIn)
176 {}
177 gl::ContextID contextId;
178 const std::string &captureLabel;
179 };
180
operator <<(std::ostream & os,const FmtCapturePrefix & fmt)181 std::ostream &operator<<(std::ostream &os, const FmtCapturePrefix &fmt)
182 {
183 if (fmt.captureLabel.empty())
184 {
185 os << "angle";
186 }
187 else
188 {
189 os << fmt.captureLabel;
190 }
191 os << "_capture_context" << static_cast<int>(fmt.contextId);
192 return os;
193 }
194
195 struct FmtReplayFunction
196 {
FmtReplayFunctionangle::__anoncf1522460111::FmtReplayFunction197 FmtReplayFunction(gl::ContextID contextIdIn, uint32_t frameIndexIn)
198 : contextId(contextIdIn), frameIndex(frameIndexIn)
199 {}
200 gl::ContextID contextId;
201 uint32_t frameIndex;
202 };
203
operator <<(std::ostream & os,const FmtReplayFunction & fmt)204 std::ostream &operator<<(std::ostream &os, const FmtReplayFunction &fmt)
205 {
206 os << "ReplayContext" << static_cast<int>(fmt.contextId) << "Frame" << fmt.frameIndex << "()";
207 return os;
208 }
209
GetCaptureFileName(gl::ContextID contextId,const std::string & captureLabel,uint32_t frameIndex,const char * suffix)210 std::string GetCaptureFileName(gl::ContextID contextId,
211 const std::string &captureLabel,
212 uint32_t frameIndex,
213 const char *suffix)
214 {
215 std::stringstream fnameStream;
216 fnameStream << FmtCapturePrefix(contextId, captureLabel) << "_frame" << std::setfill('0')
217 << std::setw(3) << frameIndex << suffix;
218 return fnameStream.str();
219 }
220
GetCaptureFilePath(const std::string & outDir,gl::ContextID contextId,const std::string & captureLabel,uint32_t frameIndex,const char * suffix)221 std::string GetCaptureFilePath(const std::string &outDir,
222 gl::ContextID contextId,
223 const std::string &captureLabel,
224 uint32_t frameIndex,
225 const char *suffix)
226 {
227 return outDir + GetCaptureFileName(contextId, captureLabel, frameIndex, suffix);
228 }
229
WriteParamStaticVarName(const CallCapture & call,const ParamCapture & param,int counter,std::ostream & out)230 void WriteParamStaticVarName(const CallCapture &call,
231 const ParamCapture ¶m,
232 int counter,
233 std::ostream &out)
234 {
235 out << call.name() << "_" << param.name << "_" << counter;
236 }
237
WriteGLFloatValue(std::ostream & out,GLfloat value)238 void WriteGLFloatValue(std::ostream &out, GLfloat value)
239 {
240 // Check for non-representable values
241 ASSERT(std::numeric_limits<float>::has_infinity);
242 ASSERT(std::numeric_limits<float>::has_quiet_NaN);
243
244 if (std::isinf(value))
245 {
246 float negativeInf = -std::numeric_limits<float>::infinity();
247 if (value == negativeInf)
248 {
249 out << "-";
250 }
251 out << "std::numeric_limits<float>::infinity()";
252 }
253 else if (std::isnan(value))
254 {
255 out << "std::numeric_limits<float>::quiet_NaN()";
256 }
257 else
258 {
259 out << value;
260 }
261 }
262
263 template <typename T, typename CastT = T>
WriteInlineData(const std::vector<uint8_t> & vec,std::ostream & out)264 void WriteInlineData(const std::vector<uint8_t> &vec, std::ostream &out)
265 {
266 const T *data = reinterpret_cast<const T *>(vec.data());
267 size_t count = vec.size() / sizeof(T);
268
269 if (data == nullptr)
270 {
271 return;
272 }
273
274 out << static_cast<CastT>(data[0]);
275
276 for (size_t dataIndex = 1; dataIndex < count; ++dataIndex)
277 {
278 out << ", " << static_cast<CastT>(data[dataIndex]);
279 }
280 }
281
282 template <>
WriteInlineData(const std::vector<uint8_t> & vec,std::ostream & out)283 void WriteInlineData<GLfloat>(const std::vector<uint8_t> &vec, std::ostream &out)
284 {
285 const float *data = reinterpret_cast<const GLfloat *>(vec.data());
286 size_t count = vec.size() / sizeof(GLfloat);
287
288 if (data == nullptr)
289 {
290 return;
291 }
292
293 WriteGLFloatValue(out, data[0]);
294
295 for (size_t dataIndex = 1; dataIndex < count; ++dataIndex)
296 {
297 out << ", ";
298 WriteGLFloatValue(out, data[dataIndex]);
299 }
300 }
301
302 template <>
WriteInlineData(const std::vector<uint8_t> & vec,std::ostream & out)303 void WriteInlineData<GLchar>(const std::vector<uint8_t> &vec, std::ostream &out)
304 {
305 const GLchar *data = reinterpret_cast<const GLchar *>(vec.data());
306 size_t count = vec.size() / sizeof(GLchar);
307
308 if (data == nullptr || data[0] == '\0')
309 {
310 return;
311 }
312
313 out << "\"";
314
315 for (size_t dataIndex = 0; dataIndex < count; ++dataIndex)
316 {
317 if (data[dataIndex] == '\0')
318 break;
319
320 out << static_cast<GLchar>(data[dataIndex]);
321 }
322
323 out << "\"";
324 }
325
326 constexpr size_t kInlineDataThreshold = 128;
327
WriteStringParamReplay(std::ostream & out,const ParamCapture & param)328 void WriteStringParamReplay(std::ostream &out, const ParamCapture ¶m)
329 {
330 const std::vector<uint8_t> &data = param.data[0];
331 // null terminate C style string
332 ASSERT(data.size() > 0 && data.back() == '\0');
333 std::string str(data.begin(), data.end() - 1);
334 out << "\"" << str << "\"";
335 }
336
WriteStringPointerParamReplay(DataCounters * counters,std::ostream & out,std::ostream & header,const CallCapture & call,const ParamCapture & param)337 void WriteStringPointerParamReplay(DataCounters *counters,
338 std::ostream &out,
339 std::ostream &header,
340 const CallCapture &call,
341 const ParamCapture ¶m)
342 {
343 int counter = counters->getAndIncrement(call.entryPoint, param.name);
344
345 header << "const char *";
346 WriteParamStaticVarName(call, param, counter, header);
347 header << "[] = { \n";
348
349 for (const std::vector<uint8_t> &data : param.data)
350 {
351 // null terminate C style string
352 ASSERT(data.size() > 0 && data.back() == '\0');
353 std::string str(data.begin(), data.end() - 1);
354 header << " R\"(" << str << ")\",\n";
355 }
356
357 header << " };\n";
358 WriteParamStaticVarName(call, param, counter, out);
359 }
360
361 template <typename ParamT>
WriteResourceIDPointerParamReplay(DataCounters * counters,std::ostream & out,std::ostream & header,const CallCapture & call,const ParamCapture & param)362 void WriteResourceIDPointerParamReplay(DataCounters *counters,
363 std::ostream &out,
364 std::ostream &header,
365 const CallCapture &call,
366 const ParamCapture ¶m)
367 {
368 int counter = counters->getAndIncrement(call.entryPoint, param.name);
369
370 header << "const GLuint ";
371 WriteParamStaticVarName(call, param, counter, header);
372 header << "[] = { ";
373
374 const ResourceIDType resourceIDType = GetResourceIDTypeFromParamType(param.type);
375 ASSERT(resourceIDType != ResourceIDType::InvalidEnum);
376 const char *name = GetResourceIDTypeName(resourceIDType);
377
378 GLsizei n = call.params.getParamFlexName("n", "count", ParamType::TGLsizei, 0).value.GLsizeiVal;
379 ASSERT(param.data.size() == 1);
380 const ParamT *returnedIDs = reinterpret_cast<const ParamT *>(param.data[0].data());
381 for (GLsizei resIndex = 0; resIndex < n; ++resIndex)
382 {
383 ParamT id = returnedIDs[resIndex];
384 if (resIndex > 0)
385 {
386 header << ", ";
387 }
388 header << "g" << name << "Map[" << id.value << "]";
389 }
390
391 header << " };\n ";
392
393 WriteParamStaticVarName(call, param, counter, out);
394 }
395
WriteBinaryParamReplay(DataCounters * counters,std::ostream & out,std::ostream & header,const CallCapture & call,const ParamCapture & param,std::vector<uint8_t> * binaryData)396 void WriteBinaryParamReplay(DataCounters *counters,
397 std::ostream &out,
398 std::ostream &header,
399 const CallCapture &call,
400 const ParamCapture ¶m,
401 std::vector<uint8_t> *binaryData)
402 {
403 int counter = counters->getAndIncrement(call.entryPoint, param.name);
404
405 ASSERT(param.data.size() == 1);
406 const std::vector<uint8_t> &data = param.data[0];
407
408 if (data.size() > kInlineDataThreshold)
409 {
410 size_t offset = binaryData->size();
411 binaryData->resize(offset + data.size());
412 memcpy(binaryData->data() + offset, data.data(), data.size());
413 if (param.type == ParamType::TvoidConstPointer || param.type == ParamType::TvoidPointer)
414 {
415 out << "&gBinaryData[" << offset << "]";
416 }
417 else
418 {
419 out << "reinterpret_cast<" << ParamTypeToString(param.type) << ">(&gBinaryData["
420 << offset << "])";
421 }
422 }
423 else
424 {
425 ParamType overrideType = param.type;
426 if (param.type == ParamType::TGLvoidConstPointer ||
427 param.type == ParamType::TvoidConstPointer)
428 {
429 overrideType = ParamType::TGLubyteConstPointer;
430 }
431
432 std::string paramTypeString = ParamTypeToString(overrideType);
433 header << paramTypeString.substr(0, paramTypeString.length() - 1);
434 WriteParamStaticVarName(call, param, counter, header);
435
436 header << "[] = { ";
437
438 switch (overrideType)
439 {
440 case ParamType::TGLintConstPointer:
441 WriteInlineData<GLint>(data, header);
442 break;
443 case ParamType::TGLshortConstPointer:
444 WriteInlineData<GLshort>(data, header);
445 break;
446 case ParamType::TGLfloatConstPointer:
447 WriteInlineData<GLfloat>(data, header);
448 break;
449 case ParamType::TGLubyteConstPointer:
450 WriteInlineData<GLubyte, int>(data, header);
451 break;
452 case ParamType::TGLuintConstPointer:
453 case ParamType::TGLenumConstPointer:
454 WriteInlineData<GLuint>(data, header);
455 break;
456 case ParamType::TGLcharPointer:
457 WriteInlineData<GLchar>(data, header);
458 break;
459 default:
460 INFO() << "Unhandled ParamType: " << angle::ParamTypeToString(overrideType)
461 << " in " << call.name();
462 UNIMPLEMENTED();
463 break;
464 }
465
466 header << " };\n";
467
468 WriteParamStaticVarName(call, param, counter, out);
469 }
470 }
471
SyncIndexValue(GLsync sync)472 uintptr_t SyncIndexValue(GLsync sync)
473 {
474 return reinterpret_cast<uintptr_t>(sync);
475 }
476
WriteCppReplayForCall(const CallCapture & call,DataCounters * counters,std::ostream & out,std::ostream & header,std::vector<uint8_t> * binaryData)477 void WriteCppReplayForCall(const CallCapture &call,
478 DataCounters *counters,
479 std::ostream &out,
480 std::ostream &header,
481 std::vector<uint8_t> *binaryData)
482 {
483 std::ostringstream callOut;
484
485 if (call.entryPoint == gl::EntryPoint::CreateShader ||
486 call.entryPoint == gl::EntryPoint::CreateProgram)
487 {
488 GLuint id = call.params.getReturnValue().value.GLuintVal;
489 callOut << "gShaderProgramMap[" << id << "] = ";
490 }
491
492 if (call.entryPoint == gl::EntryPoint::FenceSync)
493 {
494 GLsync sync = call.params.getReturnValue().value.GLsyncVal;
495 callOut << "gSyncMap[" << SyncIndexValue(sync) << "] = ";
496 }
497
498 if (call.entryPoint == gl::EntryPoint::MapBufferRange ||
499 call.entryPoint == gl::EntryPoint::MapBufferRangeEXT)
500 {
501 GLbitfield access =
502 call.params.getParam("access", ParamType::TGLbitfield, 3).value.GLbitfieldVal;
503
504 if (access & GL_MAP_WRITE_BIT)
505 {
506 // Track the returned pointer so we update its data when unmapped
507 gl::BufferID bufferID = call.params.getMappedBufferID();
508 callOut << "gMappedBufferData[";
509 WriteParamValueReplay<ParamType::TBufferID>(callOut, call, bufferID);
510 callOut << "] = ";
511 }
512 }
513
514 callOut << call.name() << "(";
515
516 bool first = true;
517 for (const ParamCapture ¶m : call.params.getParamCaptures())
518 {
519 if (!first)
520 {
521 callOut << ", ";
522 }
523
524 if (param.arrayClientPointerIndex != -1)
525 {
526 callOut << "gClientArrays[" << param.arrayClientPointerIndex << "]";
527 }
528 else if (param.readBufferSizeBytes > 0)
529 {
530 callOut << "reinterpret_cast<" << ParamTypeToString(param.type) << ">(gReadBuffer)";
531 }
532 else if (param.data.empty())
533 {
534 if (param.type == ParamType::TGLenum)
535 {
536 OutputGLenumString(callOut, param.enumGroup, param.value.GLenumVal);
537 }
538 else if (param.type == ParamType::TGLbitfield)
539 {
540 OutputGLbitfieldString(callOut, param.enumGroup, param.value.GLbitfieldVal);
541 }
542 else if (param.type == ParamType::TGLfloat)
543 {
544 WriteGLFloatValue(callOut, param.value.GLfloatVal);
545 }
546 else if (param.type == ParamType::TGLsync)
547 {
548 callOut << "gSyncMap[" << SyncIndexValue(param.value.GLsyncVal) << "]";
549 }
550 else if (param.type == ParamType::TGLuint64 && param.name == "timeout")
551 {
552 if (param.value.GLuint64Val == GL_TIMEOUT_IGNORED)
553 {
554 callOut << "GL_TIMEOUT_IGNORED";
555 }
556 else
557 {
558 WriteParamCaptureReplay(callOut, call, param);
559 }
560 }
561 else
562 {
563 WriteParamCaptureReplay(callOut, call, param);
564 }
565 }
566 else
567 {
568 switch (param.type)
569 {
570 case ParamType::TGLcharConstPointer:
571 WriteStringParamReplay(callOut, param);
572 break;
573 case ParamType::TGLcharConstPointerPointer:
574 WriteStringPointerParamReplay(counters, callOut, header, call, param);
575 break;
576 case ParamType::TBufferIDConstPointer:
577 WriteResourceIDPointerParamReplay<gl::BufferID>(counters, callOut, out, call,
578 param);
579 break;
580 case ParamType::TFenceNVIDConstPointer:
581 WriteResourceIDPointerParamReplay<gl::FenceNVID>(counters, callOut, out, call,
582 param);
583 break;
584 case ParamType::TFramebufferIDConstPointer:
585 WriteResourceIDPointerParamReplay<gl::FramebufferID>(counters, callOut, out,
586 call, param);
587 break;
588 case ParamType::TMemoryObjectIDConstPointer:
589 WriteResourceIDPointerParamReplay<gl::MemoryObjectID>(counters, callOut, out,
590 call, param);
591 break;
592 case ParamType::TProgramPipelineIDConstPointer:
593 WriteResourceIDPointerParamReplay<gl::ProgramPipelineID>(counters, callOut, out,
594 call, param);
595 break;
596 case ParamType::TQueryIDConstPointer:
597 WriteResourceIDPointerParamReplay<gl::QueryID>(counters, callOut, out, call,
598 param);
599 break;
600 case ParamType::TRenderbufferIDConstPointer:
601 WriteResourceIDPointerParamReplay<gl::RenderbufferID>(counters, callOut, out,
602 call, param);
603 break;
604 case ParamType::TSamplerIDConstPointer:
605 WriteResourceIDPointerParamReplay<gl::SamplerID>(counters, callOut, out, call,
606 param);
607 break;
608 case ParamType::TSemaphoreIDConstPointer:
609 WriteResourceIDPointerParamReplay<gl::SemaphoreID>(counters, callOut, out, call,
610 param);
611 break;
612 case ParamType::TTextureIDConstPointer:
613 WriteResourceIDPointerParamReplay<gl::TextureID>(counters, callOut, out, call,
614 param);
615 break;
616 case ParamType::TTransformFeedbackIDConstPointer:
617 WriteResourceIDPointerParamReplay<gl::TransformFeedbackID>(counters, callOut,
618 out, call, param);
619 break;
620 case ParamType::TVertexArrayIDConstPointer:
621 WriteResourceIDPointerParamReplay<gl::VertexArrayID>(counters, callOut, out,
622 call, param);
623 break;
624 default:
625 WriteBinaryParamReplay(counters, callOut, header, call, param, binaryData);
626 break;
627 }
628 }
629
630 first = false;
631 }
632
633 callOut << ")";
634
635 out << callOut.str();
636 }
637
MaxClientArraySize(const gl::AttribArray<size_t> & clientArraySizes)638 size_t MaxClientArraySize(const gl::AttribArray<size_t> &clientArraySizes)
639 {
640 size_t found = 0;
641 for (size_t size : clientArraySizes)
642 {
643 if (size > found)
644 found = size;
645 }
646
647 return found;
648 }
649
650 struct SaveFileHelper
651 {
SaveFileHelperangle::__anoncf1522460111::SaveFileHelper652 SaveFileHelper(const std::string &filePathIn, std::ios_base::openmode mode = std::ios::out)
653 : ofs(filePathIn, mode), filePath(filePathIn)
654 {
655 if (!ofs.is_open())
656 {
657 FATAL() << "Could not open " << filePathIn;
658 }
659 }
660
~SaveFileHelperangle::__anoncf1522460111::SaveFileHelper661 ~SaveFileHelper() { printf("Saved '%s'.\n", filePath.c_str()); }
662
663 template <typename T>
operator <<angle::__anoncf1522460111::SaveFileHelper664 SaveFileHelper &operator<<(const T &value)
665 {
666 ofs << value;
667 if (ofs.bad())
668 {
669 FATAL() << "Error writing to " << filePath;
670 }
671 return *this;
672 }
673
674 std::ofstream ofs;
675 std::string filePath;
676 };
677
GetBinaryDataFilePath(bool compression,gl::ContextID contextId,const std::string & captureLabel)678 std::string GetBinaryDataFilePath(bool compression,
679 gl::ContextID contextId,
680 const std::string &captureLabel)
681 {
682 std::stringstream fnameStream;
683 fnameStream << FmtCapturePrefix(contextId, captureLabel) << ".angledata";
684 if (compression)
685 {
686 fnameStream << ".gz";
687 }
688 return fnameStream.str();
689 }
690
SaveBinaryData(bool compression,const std::string & outDir,gl::ContextID contextId,const std::string & captureLabel,const std::vector<uint8_t> & binaryData)691 void SaveBinaryData(bool compression,
692 const std::string &outDir,
693 gl::ContextID contextId,
694 const std::string &captureLabel,
695 const std::vector<uint8_t> &binaryData)
696 {
697 std::string binaryDataFileName = GetBinaryDataFilePath(compression, contextId, captureLabel);
698 std::string dataFilepath = outDir + binaryDataFileName;
699
700 SaveFileHelper saveData(dataFilepath, std::ios::binary);
701
702 if (compression)
703 {
704 // Save compressed data.
705 uLong uncompressedSize = static_cast<uLong>(binaryData.size());
706 uLong expectedCompressedSize = zlib_internal::GzipExpectedCompressedSize(uncompressedSize);
707
708 std::vector<uint8_t> compressedData(expectedCompressedSize, 0);
709
710 uLong compressedSize = expectedCompressedSize;
711 int zResult = zlib_internal::GzipCompressHelper(compressedData.data(), &compressedSize,
712 binaryData.data(), uncompressedSize,
713 nullptr, nullptr);
714
715 if (zResult != Z_OK)
716 {
717 FATAL() << "Error compressing binary data: " << zResult;
718 }
719
720 saveData.ofs.write(reinterpret_cast<const char *>(compressedData.data()), compressedSize);
721 }
722 else
723 {
724 saveData.ofs.write(reinterpret_cast<const char *>(binaryData.data()), binaryData.size());
725 }
726 }
727
WriteLoadBinaryDataCall(bool compression,std::ostream & out,gl::ContextID contextId,const std::string & captureLabel)728 void WriteLoadBinaryDataCall(bool compression,
729 std::ostream &out,
730 gl::ContextID contextId,
731 const std::string &captureLabel)
732 {
733 std::string binaryDataFileName = GetBinaryDataFilePath(compression, contextId, captureLabel);
734 out << " LoadBinaryData(\"" << binaryDataFileName << "\");\n";
735 }
736
WriteCppReplay(bool compression,const std::string & outDir,gl::ContextID contextId,const std::string & captureLabel,uint32_t frameIndex,const std::vector<CallCapture> & frameCalls,const std::vector<CallCapture> & setupCalls,std::vector<uint8_t> * binaryData)737 void WriteCppReplay(bool compression,
738 const std::string &outDir,
739 gl::ContextID contextId,
740 const std::string &captureLabel,
741 uint32_t frameIndex,
742 const std::vector<CallCapture> &frameCalls,
743 const std::vector<CallCapture> &setupCalls,
744 std::vector<uint8_t> *binaryData)
745 {
746 DataCounters counters;
747
748 std::stringstream out;
749 std::stringstream header;
750
751 header << "#include \"" << FmtCapturePrefix(contextId, captureLabel) << ".h\"\n";
752 header << "";
753 header << "\n";
754 header << "namespace\n";
755 header << "{\n";
756
757 if (!captureLabel.empty())
758 {
759 out << "namespace " << captureLabel << "\n";
760 out << "{\n";
761 }
762
763 if (frameIndex == 0 || !setupCalls.empty())
764 {
765 out << "void SetupContext" << Str(static_cast<int>(contextId)) << "Replay()\n";
766 out << "{\n";
767
768 std::stringstream setupCallStream;
769
770 WriteLoadBinaryDataCall(compression, setupCallStream, contextId, captureLabel);
771
772 for (const CallCapture &call : setupCalls)
773 {
774 setupCallStream << " ";
775 WriteCppReplayForCall(call, &counters, setupCallStream, header, binaryData);
776 setupCallStream << ";\n";
777 }
778
779 out << setupCallStream.str();
780
781 out << "}\n";
782 out << "\n";
783 }
784
785 out << "void " << FmtReplayFunction(contextId, frameIndex) << "\n";
786 out << "{\n";
787
788 std::stringstream callStream;
789
790 for (const CallCapture &call : frameCalls)
791 {
792 callStream << " ";
793 WriteCppReplayForCall(call, &counters, callStream, header, binaryData);
794 callStream << ";\n";
795 }
796
797 out << callStream.str();
798 out << "}\n";
799
800 if (!captureLabel.empty())
801 {
802 out << "} // namespace " << captureLabel << "\n";
803 }
804
805 header << "} // namespace\n";
806
807 {
808 std::string outString = out.str();
809 std::string headerString = header.str();
810
811 std::string cppFilePath =
812 GetCaptureFilePath(outDir, contextId, captureLabel, frameIndex, ".cpp");
813
814 SaveFileHelper saveCpp(cppFilePath);
815 saveCpp << headerString << "\n" << outString;
816 }
817 }
818
WriteCppReplayIndexFiles(bool compression,const std::string & outDir,gl::ContextID contextId,const std::string & captureLabel,uint32_t frameStart,uint32_t frameEnd,size_t readBufferSize,const gl::AttribArray<size_t> & clientArraySizes,const HasResourceTypeMap & hasResourceType)819 void WriteCppReplayIndexFiles(bool compression,
820 const std::string &outDir,
821 gl::ContextID contextId,
822 const std::string &captureLabel,
823 uint32_t frameStart,
824 uint32_t frameEnd,
825 size_t readBufferSize,
826 const gl::AttribArray<size_t> &clientArraySizes,
827 const HasResourceTypeMap &hasResourceType)
828 {
829 size_t maxClientArraySize = MaxClientArraySize(clientArraySizes);
830
831 std::stringstream header;
832 std::stringstream source;
833
834 header << "#pragma once\n";
835 header << "\n";
836 header << "#include \"util/gles_loader_autogen.h\"\n";
837 header << "\n";
838 header << "#include <cstdint>\n";
839 header << "#include <cstdio>\n";
840 header << "#include <cstring>\n";
841 header << "#include <limits>\n";
842 header << "#include <vector>\n";
843 header << "#include <unordered_map>\n";
844 header << "\n";
845
846 if (!captureLabel.empty())
847 {
848 header << "namespace " << captureLabel << "\n";
849 header << "{\n";
850 }
851 header << "// Replay functions\n";
852 header << "\n";
853 header << "// Maps from <captured Program ID, captured location> to run-time location.\n";
854 header
855 << "using LocationsMap = std::unordered_map<GLuint, std::unordered_map<GLint, GLint>>;\n";
856 header << "extern LocationsMap gUniformLocations;\n";
857 header << "extern GLuint gCurrentProgram;\n";
858 header << "void UpdateUniformLocation(GLuint program, const char *name, GLint location);\n";
859 header << "void DeleteUniformLocations(GLuint program);\n";
860 header << "void UpdateCurrentProgram(GLuint program);\n";
861 header << "\n";
862 header << "// Maps from captured Resource ID to run-time Resource ID.\n";
863 header << "using ResourceMap = std::unordered_map<GLuint, GLuint>;\n";
864 header << "\n";
865 header << "\n";
866 header << "constexpr uint32_t kReplayFrameStart = " << frameStart << ";\n";
867 header << "constexpr uint32_t kReplayFrameEnd = " << frameEnd << ";\n";
868 header << "\n";
869 header << "void SetupContext" << static_cast<int>(contextId) << "Replay();\n";
870 header << "void ReplayContext" << static_cast<int>(contextId)
871 << "Frame(uint32_t frameIndex);\n";
872 header << "\n";
873 header << "using FramebufferChangeCallback = void(*)(void *userData, GLenum target, GLuint "
874 "framebuffer);\n";
875 header << "void SetFramebufferChangeCallback(void *userData, FramebufferChangeCallback "
876 "callback);\n";
877 header << "void OnFramebufferChange(GLenum target, GLuint framebuffer);\n";
878 header << "\n";
879 for (uint32_t frameIndex = frameStart; frameIndex < frameEnd; ++frameIndex)
880 {
881 header << "void " << FmtReplayFunction(contextId, frameIndex) << ";\n";
882 }
883 header << "\n";
884 header << "constexpr bool kIsBinaryDataCompressed = " << (compression ? "true" : "false")
885 << ";\n";
886 header << "\n";
887 header << "using DecompressCallback = uint8_t *(*)(const std::vector<uint8_t> &);\n";
888 header << "void SetBinaryDataDecompressCallback(DecompressCallback callback);\n";
889 header << "void SetBinaryDataDir(const char *dataDir);\n";
890 header << "void LoadBinaryData(const char *fileName);\n";
891 header << "\n";
892 header << "// Global state\n";
893 header << "\n";
894 header << "extern uint8_t *gBinaryData;\n";
895
896 source << "#include \"" << FmtCapturePrefix(contextId, captureLabel) << ".h\"\n";
897 source << "\n";
898
899 if (!captureLabel.empty())
900 {
901 source << "namespace " << captureLabel << "\n";
902 source << "{\n";
903 }
904
905 source << "namespace\n";
906 source << "{\n";
907 source << "void UpdateResourceMap(ResourceMap *resourceMap, GLuint id, GLsizei "
908 "readBufferOffset)\n";
909 source << "{\n";
910 source << " GLuint returnedID;\n";
911 std::string captureNamespace = !captureLabel.empty() ? captureLabel + "::" : "";
912 source << " memcpy(&returnedID, &" << captureNamespace
913 << "gReadBuffer[readBufferOffset], sizeof(GLuint));\n";
914 source << " (*resourceMap)[id] = returnedID;\n";
915 source << "}\n";
916 source << "\n";
917 source << "DecompressCallback gDecompressCallback;\n";
918 source << "const char *gBinaryDataDir = \".\";\n";
919 source << "FramebufferChangeCallback gFramebufferChangeCallback;\n";
920 source << "void *gFramebufferChangeCallbackUserData;\n";
921 source << "} // namespace\n";
922 source << "\n";
923 source << "LocationsMap gUniformLocations;\n";
924 source << "GLuint gCurrentProgram = 0;\n";
925 source << "\n";
926 source << "void UpdateUniformLocation(GLuint program, const char *name, GLint location)\n";
927 source << "{\n";
928 source << " gUniformLocations[program][location] = glGetUniformLocation(program, name);\n";
929 source << "}\n";
930 source << "void DeleteUniformLocations(GLuint program)\n";
931 source << "{\n";
932 source << " gUniformLocations.erase(program);\n";
933 source << "}\n";
934 source << "void UpdateCurrentProgram(GLuint program)\n";
935 source << "{\n";
936 source << " gCurrentProgram = program;\n";
937 source << "}\n";
938 source << "\n";
939
940 source << "uint8_t *gBinaryData = nullptr;\n";
941
942 if (readBufferSize > 0)
943 {
944 header << "extern uint8_t gReadBuffer[" << readBufferSize << "];\n";
945 source << "uint8_t gReadBuffer[" << readBufferSize << "];\n";
946 }
947 if (maxClientArraySize > 0)
948 {
949 header << "extern uint8_t gClientArrays[" << gl::MAX_VERTEX_ATTRIBS << "]["
950 << maxClientArraySize << "];\n";
951 source << "uint8_t gClientArrays[" << gl::MAX_VERTEX_ATTRIBS << "][" << maxClientArraySize
952 << "];\n";
953 }
954 for (ResourceIDType resourceType : AllEnums<ResourceIDType>())
955 {
956 // TODO: Only emit resources needed by the frames (anglebug.com/4223)
957 const char *name = GetResourceIDTypeName(resourceType);
958 header << "extern ResourceMap g" << name << "Map;\n";
959 source << "ResourceMap g" << name << "Map;\n";
960 }
961
962 header << "using SyncResourceMap = std::unordered_map<uintptr_t, GLsync>;\n";
963 header << "extern SyncResourceMap gSyncMap;\n";
964 source << "SyncResourceMap gSyncMap;\n";
965
966 header << "\n";
967
968 source << "\n";
969 source << "void SetFramebufferChangeCallback(void *userData, FramebufferChangeCallback "
970 "callback)\n";
971 source << "{\n";
972 source << " gFramebufferChangeCallbackUserData = userData;\n";
973 source << " gFramebufferChangeCallback = callback;\n";
974 source << "}\n";
975 source << "\n";
976 source << "void OnFramebufferChange(GLenum target, GLuint framebuffer)\n";
977 source << "{\n";
978 source << " if (gFramebufferChangeCallback)\n";
979 source << " gFramebufferChangeCallback(gFramebufferChangeCallbackUserData, target, "
980 "framebuffer);\n";
981 source << "}\n";
982
983 source << "\n";
984 source << "void ReplayContext" << static_cast<int>(contextId) << "Frame(uint32_t frameIndex)\n";
985 source << "{\n";
986 source << " switch (frameIndex)\n";
987 source << " {\n";
988 for (uint32_t frameIndex = frameStart; frameIndex < frameEnd; ++frameIndex)
989 {
990 source << " case " << frameIndex << ":\n";
991 source << " ReplayContext" << static_cast<int>(contextId) << "Frame"
992 << frameIndex << "();\n";
993 source << " break;\n";
994 }
995 source << " default:\n";
996 source << " break;\n";
997 source << " }\n";
998 source << "}\n";
999 source << "\n";
1000 source << "void SetBinaryDataDecompressCallback(DecompressCallback callback)\n";
1001 source << "{\n";
1002 source << " gDecompressCallback = callback;\n";
1003 source << "}\n";
1004 source << "\n";
1005 source << "void SetBinaryDataDir(const char *dataDir)\n";
1006 source << "{\n";
1007 source << " gBinaryDataDir = dataDir;\n";
1008 source << "}\n";
1009 source << "\n";
1010 source << "void LoadBinaryData(const char *fileName)\n";
1011 source << "{\n";
1012 source << " if (gBinaryData != nullptr)\n";
1013 source << " {\n";
1014 source << " delete [] gBinaryData;\n";
1015 source << " }\n";
1016 source << " char pathBuffer[1000] = {};\n";
1017 source << " sprintf(pathBuffer, \"%s/%s\", gBinaryDataDir, fileName);\n";
1018 source << " FILE *fp = fopen(pathBuffer, \"rb\");\n";
1019 source << " if (fp == 0)\n";
1020 source << " {\n";
1021 source << " fprintf(stderr, \"Error loading binary data file: %s\\n\", fileName);\n";
1022 source << " exit(1);\n";
1023 source << " }\n";
1024 source << " fseek(fp, 0, SEEK_END);\n";
1025 source << " long size = ftell(fp);\n";
1026 source << " fseek(fp, 0, SEEK_SET);\n";
1027 source << " if (gDecompressCallback)\n";
1028 source << " {\n";
1029 source << " if (!strstr(fileName, \".gz\"))\n";
1030 source << " {\n";
1031 source << " fprintf(stderr, \"Filename does not end in .gz\");\n";
1032 source << " exit(1);\n";
1033 source << " }\n";
1034 source << " std::vector<uint8_t> compressedData(size);\n";
1035 source << " (void)fread(compressedData.data(), 1, size, fp);\n";
1036 source << " gBinaryData = gDecompressCallback(compressedData);\n";
1037 source << " }\n";
1038 source << " else\n";
1039 source << " {\n";
1040 source << " if (!strstr(fileName, \".angledata\"))\n";
1041 source << " {\n";
1042 source << " fprintf(stderr, \"Filename does not end in .angledata\");\n";
1043 source << " exit(1);\n";
1044 source << " }\n";
1045 source << " gBinaryData = new uint8_t[size];\n";
1046 source << " (void)fread(gBinaryData, 1, size, fp);\n";
1047 source << " }\n";
1048 source << " fclose(fp);\n";
1049 source << "}\n";
1050
1051 if (maxClientArraySize > 0)
1052 {
1053 header
1054 << "void UpdateClientArrayPointer(int arrayIndex, const void *data, uint64_t size);\n";
1055
1056 source << "\n";
1057 source << "void UpdateClientArrayPointer(int arrayIndex, const void *data, uint64_t size)"
1058 << "\n";
1059 source << "{\n";
1060 source << " memcpy(gClientArrays[arrayIndex], data, static_cast<size_t>(size));\n";
1061 source << "}\n";
1062 }
1063
1064 // Data types and functions for tracking contents of mapped buffers
1065 header << "using BufferHandleMap = std::unordered_map<GLuint, void*>;\n";
1066 header << "extern BufferHandleMap gMappedBufferData;\n";
1067 header << "void UpdateClientBufferData(GLuint bufferID, const void *source, GLsizei size);\n";
1068 source << "BufferHandleMap gMappedBufferData;\n";
1069 source << "\n";
1070 source << "void UpdateClientBufferData(GLuint bufferID, const void *source, GLsizei size)";
1071 source << "\n";
1072 source << "{\n";
1073 source << " memcpy(gMappedBufferData[gBufferMap[bufferID]], source, size);\n";
1074 source << "}\n";
1075
1076 for (ResourceIDType resourceType : AllEnums<ResourceIDType>())
1077 {
1078 // TODO: Only emit resources needed by the frames (anglebug.com/4223)
1079 const char *name = GetResourceIDTypeName(resourceType);
1080 header << "void Update" << name << "ID(GLuint id, GLsizei readBufferOffset);\n";
1081
1082 source << "\n";
1083 source << "void Update" << name << "ID(GLuint id, GLsizei readBufferOffset)\n";
1084 source << "{\n";
1085 source << " UpdateResourceMap(&g" << name << "Map, id, readBufferOffset);\n";
1086 source << "}\n";
1087 }
1088
1089 if (!captureLabel.empty())
1090 {
1091 header << "} // namespace " << captureLabel << "\n";
1092 source << "} // namespace " << captureLabel << "\n";
1093 }
1094
1095 {
1096 std::string headerContents = header.str();
1097
1098 std::stringstream headerPathStream;
1099 headerPathStream << outDir << FmtCapturePrefix(contextId, captureLabel) << ".h";
1100 std::string headerPath = headerPathStream.str();
1101
1102 SaveFileHelper saveHeader(headerPath);
1103 saveHeader << headerContents;
1104 }
1105
1106 {
1107 std::string sourceContents = source.str();
1108
1109 std::stringstream sourcePathStream;
1110 sourcePathStream << outDir << FmtCapturePrefix(contextId, captureLabel) << ".cpp";
1111 std::string sourcePath = sourcePathStream.str();
1112
1113 SaveFileHelper saveSource(sourcePath);
1114 saveSource << sourceContents;
1115 }
1116
1117 {
1118 std::stringstream indexPathStream;
1119 indexPathStream << outDir << FmtCapturePrefix(contextId, captureLabel) << "_files.txt";
1120 std::string indexPath = indexPathStream.str();
1121
1122 SaveFileHelper saveIndex(indexPath);
1123 for (uint32_t frameIndex = frameStart; frameIndex <= frameEnd; ++frameIndex)
1124 {
1125 saveIndex << GetCaptureFileName(contextId, captureLabel, frameIndex, ".cpp") << "\n";
1126 }
1127 }
1128 }
1129
GetAttachedProgramSources(const gl::Program * program)1130 ProgramSources GetAttachedProgramSources(const gl::Program *program)
1131 {
1132 ProgramSources sources;
1133 for (gl::ShaderType shaderType : gl::AllShaderTypes())
1134 {
1135 const gl::Shader *shader = program->getAttachedShader(shaderType);
1136 if (shader)
1137 {
1138 sources[shaderType] = shader->getSourceString();
1139 }
1140 }
1141 return sources;
1142 }
1143
1144 template <typename IDType>
CaptureUpdateResourceIDs(const CallCapture & call,const ParamCapture & param,std::vector<CallCapture> * callsOut)1145 void CaptureUpdateResourceIDs(const CallCapture &call,
1146 const ParamCapture ¶m,
1147 std::vector<CallCapture> *callsOut)
1148 {
1149 GLsizei n = call.params.getParamFlexName("n", "count", ParamType::TGLsizei, 0).value.GLsizeiVal;
1150 ASSERT(param.data.size() == 1);
1151 ResourceIDType resourceIDType = GetResourceIDTypeFromParamType(param.type);
1152 ASSERT(resourceIDType != ResourceIDType::InvalidEnum);
1153 const char *resourceName = GetResourceIDTypeName(resourceIDType);
1154
1155 std::stringstream updateFuncNameStr;
1156 updateFuncNameStr << "Update" << resourceName << "ID";
1157 std::string updateFuncName = updateFuncNameStr.str();
1158
1159 const IDType *returnedIDs = reinterpret_cast<const IDType *>(param.data[0].data());
1160
1161 for (GLsizei idIndex = 0; idIndex < n; ++idIndex)
1162 {
1163 IDType id = returnedIDs[idIndex];
1164 GLsizei readBufferOffset = idIndex * sizeof(gl::RenderbufferID);
1165 ParamBuffer params;
1166 params.addValueParam("id", ParamType::TGLuint, id.value);
1167 params.addValueParam("readBufferOffset", ParamType::TGLsizei, readBufferOffset);
1168 callsOut->emplace_back(updateFuncName, std::move(params));
1169 }
1170 }
1171
CaptureUpdateUniformLocations(const gl::Program * program,std::vector<CallCapture> * callsOut)1172 void CaptureUpdateUniformLocations(const gl::Program *program, std::vector<CallCapture> *callsOut)
1173 {
1174 const std::vector<gl::LinkedUniform> &uniforms = program->getState().getUniforms();
1175 const std::vector<gl::VariableLocation> &locations = program->getUniformLocations();
1176
1177 for (GLint location = 0; location < static_cast<GLint>(locations.size()); ++location)
1178 {
1179 const gl::VariableLocation &locationVar = locations[location];
1180 const gl::LinkedUniform &uniform = uniforms[locationVar.index];
1181
1182 ParamBuffer params;
1183 params.addValueParam("program", ParamType::TShaderProgramID, program->id());
1184
1185 std::string name = uniform.name;
1186
1187 if (uniform.isArray())
1188 {
1189 if (locationVar.arrayIndex > 0)
1190 {
1191 // Non-sequential array uniform locations are not currently handled.
1192 // In practice array locations shouldn't ever be non-sequential.
1193 ASSERT(uniform.location == -1 ||
1194 location == uniform.location + static_cast<int>(locationVar.arrayIndex));
1195 continue;
1196 }
1197
1198 if (uniform.isArrayOfArrays())
1199 {
1200 UNIMPLEMENTED();
1201 }
1202
1203 name = gl::StripLastArrayIndex(name);
1204 }
1205
1206 ParamCapture nameParam("name", ParamType::TGLcharConstPointer);
1207 CaptureString(name.c_str(), &nameParam);
1208 params.addParam(std::move(nameParam));
1209
1210 params.addValueParam("location", ParamType::TGLint, location);
1211 callsOut->emplace_back("UpdateUniformLocation", std::move(params));
1212 }
1213 }
1214
CaptureDeleteUniformLocations(gl::ShaderProgramID program,std::vector<CallCapture> * callsOut)1215 void CaptureDeleteUniformLocations(gl::ShaderProgramID program, std::vector<CallCapture> *callsOut)
1216 {
1217 ParamBuffer params;
1218 params.addValueParam("program", ParamType::TShaderProgramID, program);
1219 callsOut->emplace_back("DeleteUniformLocations", std::move(params));
1220 }
1221
CaptureOnFramebufferChange(GLenum target,gl::FramebufferID framebufferID,std::vector<CallCapture> * callsOut)1222 void CaptureOnFramebufferChange(GLenum target,
1223 gl::FramebufferID framebufferID,
1224 std::vector<CallCapture> *callsOut)
1225 {
1226 ParamBuffer params;
1227 params.addValueParam("target", ParamType::TGLenum, target);
1228 params.addValueParam("framebuffer", ParamType::TFramebufferID, framebufferID);
1229 callsOut->emplace_back("OnFramebufferChange", std::move(params));
1230 }
1231
MaybeCaptureUpdateResourceIDs(std::vector<CallCapture> * callsOut)1232 void MaybeCaptureUpdateResourceIDs(std::vector<CallCapture> *callsOut)
1233 {
1234 const CallCapture &call = callsOut->back();
1235
1236 switch (call.entryPoint)
1237 {
1238 case gl::EntryPoint::GenBuffers:
1239 {
1240 const ParamCapture &buffers =
1241 call.params.getParam("buffersPacked", ParamType::TBufferIDPointer, 1);
1242 CaptureUpdateResourceIDs<gl::BufferID>(call, buffers, callsOut);
1243 break;
1244 }
1245
1246 case gl::EntryPoint::GenFencesNV:
1247 {
1248 const ParamCapture &fences =
1249 call.params.getParam("fencesPacked", ParamType::TFenceNVIDPointer, 1);
1250 CaptureUpdateResourceIDs<gl::FenceNVID>(call, fences, callsOut);
1251 break;
1252 }
1253
1254 case gl::EntryPoint::GenFramebuffers:
1255 case gl::EntryPoint::GenFramebuffersOES:
1256 {
1257 const ParamCapture &framebuffers =
1258 call.params.getParam("framebuffersPacked", ParamType::TFramebufferIDPointer, 1);
1259 CaptureUpdateResourceIDs<gl::FramebufferID>(call, framebuffers, callsOut);
1260 break;
1261 }
1262
1263 case gl::EntryPoint::GenProgramPipelines:
1264 {
1265 const ParamCapture &pipelines =
1266 call.params.getParam("pipelinesPacked", ParamType::TProgramPipelineIDPointer, 1);
1267 CaptureUpdateResourceIDs<gl::ProgramPipelineID>(call, pipelines, callsOut);
1268 break;
1269 }
1270
1271 case gl::EntryPoint::GenQueries:
1272 case gl::EntryPoint::GenQueriesEXT:
1273 {
1274 const ParamCapture &queries =
1275 call.params.getParam("idsPacked", ParamType::TQueryIDPointer, 1);
1276 CaptureUpdateResourceIDs<gl::QueryID>(call, queries, callsOut);
1277 break;
1278 }
1279
1280 case gl::EntryPoint::GenRenderbuffers:
1281 case gl::EntryPoint::GenRenderbuffersOES:
1282 {
1283 const ParamCapture &renderbuffers =
1284 call.params.getParam("renderbuffersPacked", ParamType::TRenderbufferIDPointer, 1);
1285 CaptureUpdateResourceIDs<gl::RenderbufferID>(call, renderbuffers, callsOut);
1286 break;
1287 }
1288
1289 case gl::EntryPoint::GenSamplers:
1290 {
1291 const ParamCapture &samplers =
1292 call.params.getParam("samplersPacked", ParamType::TSamplerIDPointer, 1);
1293 CaptureUpdateResourceIDs<gl::SamplerID>(call, samplers, callsOut);
1294 break;
1295 }
1296
1297 case gl::EntryPoint::GenSemaphoresEXT:
1298 {
1299 const ParamCapture &semaphores =
1300 call.params.getParam("semaphoresPacked", ParamType::TSemaphoreIDPointer, 1);
1301 CaptureUpdateResourceIDs<gl::SemaphoreID>(call, semaphores, callsOut);
1302 break;
1303 }
1304
1305 case gl::EntryPoint::GenTextures:
1306 {
1307 const ParamCapture &textures =
1308 call.params.getParam("texturesPacked", ParamType::TTextureIDPointer, 1);
1309 CaptureUpdateResourceIDs<gl::TextureID>(call, textures, callsOut);
1310 break;
1311 }
1312
1313 case gl::EntryPoint::GenTransformFeedbacks:
1314 {
1315 const ParamCapture &xfbs =
1316 call.params.getParam("idsPacked", ParamType::TTransformFeedbackIDPointer, 1);
1317 CaptureUpdateResourceIDs<gl::TransformFeedbackID>(call, xfbs, callsOut);
1318 break;
1319 }
1320
1321 case gl::EntryPoint::GenVertexArrays:
1322 case gl::EntryPoint::GenVertexArraysOES:
1323 {
1324 const ParamCapture &vertexArrays =
1325 call.params.getParam("arraysPacked", ParamType::TVertexArrayIDPointer, 1);
1326 CaptureUpdateResourceIDs<gl::VertexArrayID>(call, vertexArrays, callsOut);
1327 break;
1328 }
1329
1330 default:
1331 break;
1332 }
1333 }
1334
CaptureUpdateCurrentProgram(const CallCapture & call,std::vector<CallCapture> * callsOut)1335 void CaptureUpdateCurrentProgram(const CallCapture &call, std::vector<CallCapture> *callsOut)
1336 {
1337 const ParamCapture ¶m =
1338 call.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
1339 gl::ShaderProgramID programID = param.value.ShaderProgramIDVal;
1340
1341 ParamBuffer paramBuffer;
1342 paramBuffer.addValueParam("program", ParamType::TShaderProgramID, programID);
1343
1344 callsOut->emplace_back("UpdateCurrentProgram", std::move(paramBuffer));
1345 }
1346
IsDefaultCurrentValue(const gl::VertexAttribCurrentValueData & currentValue)1347 bool IsDefaultCurrentValue(const gl::VertexAttribCurrentValueData ¤tValue)
1348 {
1349 if (currentValue.Type != gl::VertexAttribType::Float)
1350 return false;
1351
1352 return currentValue.Values.FloatValues[0] == 0.0f &&
1353 currentValue.Values.FloatValues[1] == 0.0f &&
1354 currentValue.Values.FloatValues[2] == 0.0f && currentValue.Values.FloatValues[3] == 1.0f;
1355 }
1356
IsQueryActive(const gl::State & glState,gl::QueryID & queryID)1357 bool IsQueryActive(const gl::State &glState, gl::QueryID &queryID)
1358 {
1359 const gl::ActiveQueryMap &activeQueries = glState.getActiveQueriesForCapture();
1360 for (const auto &activeQueryIter : activeQueries)
1361 {
1362 const gl::Query *activeQuery = activeQueryIter.get();
1363 if (activeQuery && activeQuery->id() == queryID)
1364 {
1365 return true;
1366 }
1367 }
1368
1369 return false;
1370 }
1371
Capture(std::vector<CallCapture> * setupCalls,CallCapture && call)1372 void Capture(std::vector<CallCapture> *setupCalls, CallCapture &&call)
1373 {
1374 setupCalls->emplace_back(std::move(call));
1375 }
1376
CaptureFramebufferAttachment(std::vector<CallCapture> * setupCalls,const gl::State & replayState,const gl::FramebufferAttachment & attachment)1377 void CaptureFramebufferAttachment(std::vector<CallCapture> *setupCalls,
1378 const gl::State &replayState,
1379 const gl::FramebufferAttachment &attachment)
1380 {
1381 GLuint resourceID = attachment.getResource()->getId();
1382
1383 // TODO(jmadill): Layer attachments. http://anglebug.com/3662
1384 if (attachment.type() == GL_TEXTURE)
1385 {
1386 gl::ImageIndex index = attachment.getTextureImageIndex();
1387
1388 Capture(setupCalls, CaptureFramebufferTexture2D(replayState, true, GL_FRAMEBUFFER,
1389 attachment.getBinding(), index.getTarget(),
1390 {resourceID}, index.getLevelIndex()));
1391 }
1392 else
1393 {
1394 ASSERT(attachment.type() == GL_RENDERBUFFER);
1395 Capture(setupCalls, CaptureFramebufferRenderbuffer(replayState, true, GL_FRAMEBUFFER,
1396 attachment.getBinding(), GL_RENDERBUFFER,
1397 {resourceID}));
1398 }
1399 }
1400
CaptureUpdateUniformValues(const gl::State & replayState,const gl::Context * context,const gl::Program * program,std::vector<CallCapture> * callsOut)1401 void CaptureUpdateUniformValues(const gl::State &replayState,
1402 const gl::Context *context,
1403 const gl::Program *program,
1404 std::vector<CallCapture> *callsOut)
1405 {
1406 const std::vector<gl::LinkedUniform> &uniforms = program->getState().getUniforms();
1407 const std::vector<gl::VariableLocation> &locations = program->getUniformLocations();
1408
1409 for (const gl::VariableLocation &location : locations)
1410 {
1411 const gl::LinkedUniform &uniform = uniforms[location.index];
1412
1413 if (!program->isLinked())
1414 {
1415 // We can't populate uniforms if the program hasn't been linked
1416 continue;
1417 }
1418
1419 if (uniform.isArray())
1420 {
1421 UNIMPLEMENTED();
1422 }
1423
1424 // We need to bind the program and update its uniforms
1425 // TODO (http://anglebug.com/3662): Only bind if different from currently bound
1426 Capture(callsOut, CaptureUseProgram(replayState, true, program->id()));
1427 CaptureUpdateCurrentProgram(callsOut->back(), callsOut);
1428
1429 const gl::UniformTypeInfo *typeInfo = uniform.typeInfo;
1430 gl::UniformLocation uniformLoc = {static_cast<int>(location.index)};
1431
1432 switch (typeInfo->componentType)
1433 {
1434 case GL_FLOAT:
1435 {
1436 std::vector<GLfloat> components(typeInfo->componentCount);
1437 program->getUniformfv(context, uniformLoc, components.data());
1438 switch (typeInfo->type)
1439 {
1440 // Note: All matrix uniforms are populated without transpose
1441 case GL_FLOAT_MAT4x3:
1442 Capture(callsOut, CaptureUniformMatrix4x3fv(replayState, true, uniformLoc,
1443 1, false, components.data()));
1444 break;
1445 case GL_FLOAT_MAT4x2:
1446 Capture(callsOut, CaptureUniformMatrix4x2fv(replayState, true, uniformLoc,
1447 1, false, components.data()));
1448 break;
1449 case GL_FLOAT_MAT4:
1450 Capture(callsOut, CaptureUniformMatrix4fv(replayState, true, uniformLoc, 1,
1451 false, components.data()));
1452 break;
1453 case GL_FLOAT_MAT3x4:
1454 Capture(callsOut, CaptureUniformMatrix3x4fv(replayState, true, uniformLoc,
1455 1, false, components.data()));
1456 break;
1457 case GL_FLOAT_MAT3x2:
1458 Capture(callsOut, CaptureUniformMatrix3x2fv(replayState, true, uniformLoc,
1459 1, false, components.data()));
1460 break;
1461 case GL_FLOAT_MAT3:
1462 Capture(callsOut, CaptureUniformMatrix3fv(replayState, true, uniformLoc, 1,
1463 false, components.data()));
1464 break;
1465 case GL_FLOAT_MAT2x4:
1466 Capture(callsOut, CaptureUniformMatrix2x4fv(replayState, true, uniformLoc,
1467 1, false, components.data()));
1468 break;
1469 case GL_FLOAT_MAT2x3:
1470 Capture(callsOut, CaptureUniformMatrix2x3fv(replayState, true, uniformLoc,
1471 1, false, components.data()));
1472 break;
1473 case GL_FLOAT_MAT2:
1474 Capture(callsOut, CaptureUniformMatrix2fv(replayState, true, uniformLoc, 1,
1475 false, components.data()));
1476 break;
1477 case GL_FLOAT_VEC4:
1478 Capture(callsOut, CaptureUniform4fv(replayState, true, uniformLoc, 1,
1479 components.data()));
1480 break;
1481 case GL_FLOAT_VEC3:
1482 Capture(callsOut, CaptureUniform3fv(replayState, true, uniformLoc, 1,
1483 components.data()));
1484 break;
1485 case GL_FLOAT_VEC2:
1486 Capture(callsOut, CaptureUniform2fv(replayState, true, uniformLoc, 1,
1487 components.data()));
1488 break;
1489 case GL_FLOAT:
1490 Capture(callsOut, CaptureUniform1fv(replayState, true, uniformLoc, 1,
1491 components.data()));
1492 break;
1493 default:
1494 UNIMPLEMENTED();
1495 break;
1496 }
1497 break;
1498 }
1499 case GL_INT:
1500 {
1501 std::vector<GLint> components(typeInfo->componentCount);
1502 program->getUniformiv(context, uniformLoc, components.data());
1503 switch (typeInfo->componentCount)
1504 {
1505 case 4:
1506 Capture(callsOut, CaptureUniform4iv(replayState, true, uniformLoc, 1,
1507 components.data()));
1508 break;
1509 case 3:
1510 Capture(callsOut, CaptureUniform3iv(replayState, true, uniformLoc, 1,
1511 components.data()));
1512 break;
1513 case 2:
1514 Capture(callsOut, CaptureUniform2iv(replayState, true, uniformLoc, 1,
1515 components.data()));
1516 break;
1517 case 1:
1518 Capture(callsOut, CaptureUniform1iv(replayState, true, uniformLoc, 1,
1519 components.data()));
1520 break;
1521 default:
1522 UNIMPLEMENTED();
1523 break;
1524 }
1525 break;
1526 }
1527 case GL_UNSIGNED_INT:
1528 {
1529 std::vector<GLuint> components(typeInfo->componentCount);
1530 program->getUniformuiv(context, uniformLoc, components.data());
1531 switch (typeInfo->componentCount)
1532 {
1533 case 4:
1534 Capture(callsOut, CaptureUniform4uiv(replayState, true, uniformLoc, 1,
1535 components.data()));
1536 break;
1537 case 3:
1538 Capture(callsOut, CaptureUniform3uiv(replayState, true, uniformLoc, 1,
1539 components.data()));
1540 break;
1541 case 2:
1542 Capture(callsOut, CaptureUniform2uiv(replayState, true, uniformLoc, 1,
1543 components.data()));
1544 break;
1545 case 1:
1546 Capture(callsOut, CaptureUniform1uiv(replayState, true, uniformLoc, 1,
1547 components.data()));
1548 break;
1549 default:
1550 UNIMPLEMENTED();
1551 break;
1552 }
1553 break;
1554 }
1555 default:
1556 UNIMPLEMENTED();
1557 break;
1558 }
1559 }
1560 }
1561
CaptureVertexArrayData(std::vector<CallCapture> * setupCalls,const gl::Context * context,const gl::VertexArray * vertexArray,gl::State * replayState)1562 void CaptureVertexArrayData(std::vector<CallCapture> *setupCalls,
1563 const gl::Context *context,
1564 const gl::VertexArray *vertexArray,
1565 gl::State *replayState)
1566 {
1567 const std::vector<gl::VertexAttribute> &vertexAttribs = vertexArray->getVertexAttributes();
1568 const std::vector<gl::VertexBinding> &vertexBindings = vertexArray->getVertexBindings();
1569
1570 for (GLuint attribIndex = 0; attribIndex < gl::MAX_VERTEX_ATTRIBS; ++attribIndex)
1571 {
1572 const gl::VertexAttribute defaultAttrib(attribIndex);
1573 const gl::VertexBinding defaultBinding;
1574
1575 const gl::VertexAttribute &attrib = vertexAttribs[attribIndex];
1576 const gl::VertexBinding &binding = vertexBindings[attrib.bindingIndex];
1577
1578 if (attrib.enabled != defaultAttrib.enabled)
1579 {
1580 Capture(setupCalls, CaptureEnableVertexAttribArray(*replayState, false, attribIndex));
1581 }
1582
1583 if (attrib.format != defaultAttrib.format || attrib.pointer != defaultAttrib.pointer ||
1584 binding.getStride() != defaultBinding.getStride() ||
1585 binding.getBuffer().get() != nullptr)
1586 {
1587 gl::Buffer *buffer = binding.getBuffer().get();
1588
1589 if (buffer != replayState->getArrayBuffer())
1590 {
1591 replayState->setBufferBinding(context, gl::BufferBinding::Array, buffer);
1592 Capture(setupCalls, CaptureBindBuffer(*replayState, true, gl::BufferBinding::Array,
1593 buffer->id()));
1594 }
1595
1596 Capture(setupCalls, CaptureVertexAttribPointer(
1597 *replayState, true, attribIndex, attrib.format->channelCount,
1598 attrib.format->vertexAttribType, attrib.format->isNorm(),
1599 binding.getStride(), attrib.pointer));
1600 }
1601
1602 if (binding.getDivisor() != 0)
1603 {
1604 Capture(setupCalls, CaptureVertexAttribDivisor(*replayState, true, attribIndex,
1605 binding.getDivisor()));
1606 }
1607 }
1608 }
1609
CaptureTextureStorage(std::vector<CallCapture> * setupCalls,gl::State * replayState,const gl::Texture * texture)1610 void CaptureTextureStorage(std::vector<CallCapture> *setupCalls,
1611 gl::State *replayState,
1612 const gl::Texture *texture)
1613 {
1614 // Use mip-level 0 for the base dimensions
1615 gl::ImageIndex imageIndex = gl::ImageIndex::MakeFromType(texture->getType(), 0);
1616 const gl::ImageDesc &desc = texture->getTextureState().getImageDesc(imageIndex);
1617
1618 switch (texture->getType())
1619 {
1620 case gl::TextureType::_2D:
1621 case gl::TextureType::CubeMap:
1622 {
1623 Capture(setupCalls, CaptureTexStorage2D(*replayState, true, texture->getType(),
1624 texture->getImmutableLevels(),
1625 desc.format.info->internalFormat,
1626 desc.size.width, desc.size.height));
1627 break;
1628 }
1629 case gl::TextureType::_3D:
1630 case gl::TextureType::_2DArray:
1631 {
1632 Capture(setupCalls, CaptureTexStorage3D(
1633 *replayState, true, texture->getType(),
1634 texture->getImmutableLevels(), desc.format.info->internalFormat,
1635 desc.size.width, desc.size.height, desc.size.depth));
1636 break;
1637 }
1638 default:
1639 UNIMPLEMENTED();
1640 break;
1641 }
1642 }
1643
CaptureTextureContents(std::vector<CallCapture> * setupCalls,gl::State * replayState,const gl::Texture * texture,const gl::ImageIndex & index,const gl::ImageDesc & desc,GLuint size,const void * data)1644 void CaptureTextureContents(std::vector<CallCapture> *setupCalls,
1645 gl::State *replayState,
1646 const gl::Texture *texture,
1647 const gl::ImageIndex &index,
1648 const gl::ImageDesc &desc,
1649 GLuint size,
1650 const void *data)
1651 {
1652 const gl::InternalFormat &format = *desc.format.info;
1653
1654 bool is3D =
1655 (index.getType() == gl::TextureType::_3D || index.getType() == gl::TextureType::_2DArray);
1656
1657 if (format.compressed)
1658 {
1659 if (is3D)
1660 {
1661 if (texture->getImmutableFormat())
1662 {
1663 Capture(setupCalls,
1664 CaptureCompressedTexSubImage3D(
1665 *replayState, true, index.getTarget(), index.getLevelIndex(), 0, 0, 0,
1666 desc.size.width, desc.size.height, desc.size.depth,
1667 format.internalFormat, size, data));
1668 }
1669 else
1670 {
1671 Capture(setupCalls,
1672 CaptureCompressedTexImage3D(*replayState, true, index.getTarget(),
1673 index.getLevelIndex(), format.internalFormat,
1674 desc.size.width, desc.size.height,
1675 desc.size.depth, 0, size, data));
1676 }
1677 }
1678 else
1679 {
1680 if (texture->getImmutableFormat())
1681 {
1682 Capture(setupCalls,
1683 CaptureCompressedTexSubImage2D(
1684 *replayState, true, index.getTarget(), index.getLevelIndex(), 0, 0,
1685 desc.size.width, desc.size.height, format.internalFormat, size, data));
1686 }
1687 else
1688 {
1689 Capture(setupCalls, CaptureCompressedTexImage2D(
1690 *replayState, true, index.getTarget(),
1691 index.getLevelIndex(), format.internalFormat,
1692 desc.size.width, desc.size.height, 0, size, data));
1693 }
1694 }
1695 }
1696 else
1697 {
1698 if (is3D)
1699 {
1700 if (texture->getImmutableFormat())
1701 {
1702 Capture(setupCalls,
1703 CaptureTexSubImage3D(*replayState, true, index.getTarget(),
1704 index.getLevelIndex(), 0, 0, 0, desc.size.width,
1705 desc.size.height, desc.size.depth, format.format,
1706 format.type, data));
1707 }
1708 else
1709 {
1710 Capture(
1711 setupCalls,
1712 CaptureTexImage3D(*replayState, true, index.getTarget(), index.getLevelIndex(),
1713 format.internalFormat, desc.size.width, desc.size.height,
1714 desc.size.depth, 0, format.format, format.type, data));
1715 }
1716 }
1717 else
1718 {
1719 if (texture->getImmutableFormat())
1720 {
1721 Capture(setupCalls,
1722 CaptureTexSubImage2D(*replayState, true, index.getTarget(),
1723 index.getLevelIndex(), 0, 0, desc.size.width,
1724 desc.size.height, format.format, format.type, data));
1725 }
1726 else
1727 {
1728 Capture(setupCalls, CaptureTexImage2D(*replayState, true, index.getTarget(),
1729 index.getLevelIndex(), format.internalFormat,
1730 desc.size.width, desc.size.height, 0,
1731 format.format, format.type, data));
1732 }
1733 }
1734 }
1735 }
1736
CaptureMidExecutionSetup(const gl::Context * context,std::vector<CallCapture> * setupCalls,const ShaderSourceMap & cachedShaderSources,const ProgramSourceMap & cachedProgramSources,const TextureLevelDataMap & cachedTextureLevelData)1737 void CaptureMidExecutionSetup(const gl::Context *context,
1738 std::vector<CallCapture> *setupCalls,
1739 const ShaderSourceMap &cachedShaderSources,
1740 const ProgramSourceMap &cachedProgramSources,
1741 const TextureLevelDataMap &cachedTextureLevelData)
1742 {
1743 const gl::State &apiState = context->getState();
1744 gl::State replayState(nullptr, nullptr, nullptr, EGL_OPENGL_ES_API, apiState.getClientVersion(),
1745 false, true, true, true, false, EGL_CONTEXT_PRIORITY_MEDIUM_IMG);
1746
1747 // Small helper function to make the code more readable.
1748 auto cap = [setupCalls](CallCapture &&call) { setupCalls->emplace_back(std::move(call)); };
1749
1750 // Currently this code assumes we can use create-on-bind. It does not support 'Gen' usage.
1751 // TODO(jmadill): Use handle mapping for captured objects. http://anglebug.com/3662
1752
1753 // Capture Buffer data.
1754 const gl::BufferManager &buffers = apiState.getBufferManagerForCapture();
1755 const gl::BoundBufferMap &boundBuffers = apiState.getBoundBuffersForCapture();
1756
1757 for (const auto &bufferIter : buffers)
1758 {
1759 gl::BufferID id = {bufferIter.first};
1760 gl::Buffer *buffer = bufferIter.second;
1761
1762 if (id.value == 0)
1763 {
1764 continue;
1765 }
1766
1767 // glBufferData. Would possibly be better implemented using a getData impl method.
1768 // Saving buffers that are mapped during a swap is not yet handled.
1769 if (buffer->getSize() == 0)
1770 {
1771 continue;
1772 }
1773 ASSERT(!buffer->isMapped());
1774 (void)buffer->mapRange(context, 0, static_cast<GLsizeiptr>(buffer->getSize()),
1775 GL_MAP_READ_BIT);
1776
1777 // Generate binding.
1778 cap(CaptureGenBuffers(replayState, true, 1, &id));
1779 MaybeCaptureUpdateResourceIDs(setupCalls);
1780
1781 // Always use the array buffer binding point to upload data to keep things simple.
1782 if (buffer != replayState.getArrayBuffer())
1783 {
1784 replayState.setBufferBinding(context, gl::BufferBinding::Array, buffer);
1785 cap(CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, id));
1786 }
1787
1788 cap(CaptureBufferData(replayState, true, gl::BufferBinding::Array,
1789 static_cast<GLsizeiptr>(buffer->getSize()), buffer->getMapPointer(),
1790 buffer->getUsage()));
1791
1792 GLboolean dontCare;
1793 (void)buffer->unmap(context, &dontCare);
1794 }
1795
1796 // Vertex input states. Only handles GLES 2.0 states right now.
1797 // Must happen after buffer data initialization.
1798 // TODO(http://anglebug.com/3662): Complete state capture.
1799
1800 // Capture default vertex attribs
1801 const std::vector<gl::VertexAttribCurrentValueData> ¤tValues =
1802 apiState.getVertexAttribCurrentValues();
1803
1804 for (GLuint attribIndex = 0; attribIndex < gl::MAX_VERTEX_ATTRIBS; ++attribIndex)
1805 {
1806 const gl::VertexAttribCurrentValueData &defaultValue = currentValues[attribIndex];
1807 if (!IsDefaultCurrentValue(defaultValue))
1808 {
1809 Capture(setupCalls, CaptureVertexAttrib4fv(replayState, true, attribIndex,
1810 defaultValue.Values.FloatValues));
1811 }
1812 }
1813
1814 // Capture vertex array objects
1815 const gl::VertexArrayMap &vertexArrayMap = context->getVertexArraysForCapture();
1816 gl::VertexArrayID boundVertexArrayID = {0};
1817 for (const auto &vertexArrayIter : vertexArrayMap)
1818 {
1819 gl::VertexArrayID vertexArrayID = {vertexArrayIter.first};
1820 cap(CaptureGenVertexArrays(replayState, true, 1, &vertexArrayID));
1821 MaybeCaptureUpdateResourceIDs(setupCalls);
1822
1823 if (vertexArrayIter.second)
1824 {
1825 const gl::VertexArray *vertexArray = vertexArrayIter.second;
1826
1827 // Bind the vertexArray (unless default) and populate it
1828 if (vertexArrayID.value != 0)
1829 {
1830 cap(CaptureBindVertexArray(replayState, true, vertexArrayID));
1831 boundVertexArrayID = vertexArrayID;
1832 }
1833 CaptureVertexArrayData(setupCalls, context, vertexArray, &replayState);
1834 }
1835 }
1836
1837 // Bind the current vertex array
1838 const gl::VertexArray *currentVertexArray = apiState.getVertexArray();
1839 if (currentVertexArray->id() != boundVertexArrayID)
1840 {
1841 cap(CaptureBindVertexArray(replayState, true, currentVertexArray->id()));
1842 }
1843
1844 // Capture Buffer bindings.
1845 for (gl::BufferBinding binding : angle::AllEnums<gl::BufferBinding>())
1846 {
1847 gl::BufferID bufferID = boundBuffers[binding].id();
1848
1849 // Filter out redundant buffer binding commands. Note that the code in the previous section
1850 // only binds to ARRAY_BUFFER. Therefore we only check the array binding against the binding
1851 // we set earlier.
1852 bool isArray = binding == gl::BufferBinding::Array;
1853 const gl::Buffer *arrayBuffer = replayState.getArrayBuffer();
1854 if ((isArray && arrayBuffer && arrayBuffer->id() != bufferID) ||
1855 (!isArray && bufferID.value != 0))
1856 {
1857 cap(CaptureBindBuffer(replayState, true, binding, bufferID));
1858 }
1859 }
1860
1861 // Set a unpack alignment of 1.
1862 gl::PixelUnpackState ¤tUnpackState = replayState.getUnpackState();
1863 if (currentUnpackState.alignment != 1)
1864 {
1865 cap(CapturePixelStorei(replayState, true, GL_UNPACK_ALIGNMENT, 1));
1866 currentUnpackState.alignment = 1;
1867 }
1868
1869 // Capture Texture setup and data.
1870 const gl::TextureManager &textures = apiState.getTextureManagerForCapture();
1871 const gl::TextureBindingMap &boundTextures = apiState.getBoundTexturesForCapture();
1872
1873 gl::TextureTypeMap<gl::TextureID> currentTextureBindings;
1874
1875 for (const auto &textureIter : textures)
1876 {
1877 gl::TextureID id = {textureIter.first};
1878 const gl::Texture *texture = textureIter.second;
1879
1880 if (id.value == 0)
1881 {
1882 continue;
1883 }
1884
1885 // Gen the Texture.
1886 cap(CaptureGenTextures(replayState, true, 1, &id));
1887 MaybeCaptureUpdateResourceIDs(setupCalls);
1888 cap(CaptureBindTexture(replayState, true, texture->getType(), id));
1889
1890 currentTextureBindings[texture->getType()] = id;
1891
1892 // Capture sampler parameter states.
1893 // TODO(jmadill): More sampler / texture states. http://anglebug.com/3662
1894 gl::SamplerState defaultSamplerState =
1895 gl::SamplerState::CreateDefaultForTarget(texture->getType());
1896 const gl::SamplerState &textureSamplerState = texture->getSamplerState();
1897
1898 auto capTexParam = [cap, &replayState, texture](GLenum pname, GLint param) {
1899 cap(CaptureTexParameteri(replayState, true, texture->getType(), pname, param));
1900 };
1901
1902 auto capTexParamf = [cap, &replayState, texture](GLenum pname, GLfloat param) {
1903 cap(CaptureTexParameterf(replayState, true, texture->getType(), pname, param));
1904 };
1905
1906 if (textureSamplerState.getMinFilter() != defaultSamplerState.getMinFilter())
1907 {
1908 capTexParam(GL_TEXTURE_MIN_FILTER, textureSamplerState.getMinFilter());
1909 }
1910
1911 if (textureSamplerState.getMagFilter() != defaultSamplerState.getMagFilter())
1912 {
1913 capTexParam(GL_TEXTURE_MAG_FILTER, textureSamplerState.getMagFilter());
1914 }
1915
1916 if (textureSamplerState.getWrapR() != defaultSamplerState.getWrapR())
1917 {
1918 capTexParam(GL_TEXTURE_WRAP_R, textureSamplerState.getWrapR());
1919 }
1920
1921 if (textureSamplerState.getWrapS() != defaultSamplerState.getWrapS())
1922 {
1923 capTexParam(GL_TEXTURE_WRAP_S, textureSamplerState.getWrapS());
1924 }
1925
1926 if (textureSamplerState.getWrapT() != defaultSamplerState.getWrapT())
1927 {
1928 capTexParam(GL_TEXTURE_WRAP_T, textureSamplerState.getWrapT());
1929 }
1930
1931 if (textureSamplerState.getMinLod() != defaultSamplerState.getMinLod())
1932 {
1933 capTexParamf(GL_TEXTURE_MIN_LOD, textureSamplerState.getMinLod());
1934 }
1935
1936 if (textureSamplerState.getMaxLod() != defaultSamplerState.getMaxLod())
1937 {
1938 capTexParamf(GL_TEXTURE_MAX_LOD, textureSamplerState.getMaxLod());
1939 }
1940
1941 if (textureSamplerState.getCompareMode() != defaultSamplerState.getCompareMode())
1942 {
1943 capTexParam(GL_TEXTURE_COMPARE_MODE, textureSamplerState.getCompareMode());
1944 }
1945
1946 if (textureSamplerState.getCompareFunc() != defaultSamplerState.getCompareFunc())
1947 {
1948 capTexParam(GL_TEXTURE_COMPARE_FUNC, textureSamplerState.getCompareFunc());
1949 }
1950
1951 // Texture parameters
1952 if (texture->getSwizzleRed() != GL_RED)
1953 {
1954 capTexParam(GL_TEXTURE_SWIZZLE_R, texture->getSwizzleRed());
1955 }
1956
1957 if (texture->getSwizzleGreen() != GL_GREEN)
1958 {
1959 capTexParam(GL_TEXTURE_SWIZZLE_G, texture->getSwizzleGreen());
1960 }
1961
1962 if (texture->getSwizzleBlue() != GL_BLUE)
1963 {
1964 capTexParam(GL_TEXTURE_SWIZZLE_B, texture->getSwizzleBlue());
1965 }
1966
1967 if (texture->getSwizzleAlpha() != GL_ALPHA)
1968 {
1969 capTexParam(GL_TEXTURE_SWIZZLE_A, texture->getSwizzleAlpha());
1970 }
1971
1972 if (texture->getBaseLevel() != 0)
1973 {
1974 capTexParam(GL_TEXTURE_BASE_LEVEL, texture->getBaseLevel());
1975 }
1976
1977 if (texture->getMaxLevel() != 1000)
1978 {
1979 capTexParam(GL_TEXTURE_MAX_LEVEL, texture->getMaxLevel());
1980 }
1981
1982 // If the texture is immutable, initialize it with TexStorage
1983 if (texture->getImmutableFormat())
1984 {
1985 CaptureTextureStorage(setupCalls, &replayState, texture);
1986 }
1987
1988 // Iterate texture levels and layers.
1989 gl::ImageIndexIterator imageIter = gl::ImageIndexIterator::MakeGeneric(
1990 texture->getType(), 0, texture->getMipmapMaxLevel() + 1, gl::ImageIndex::kEntireLevel,
1991 gl::ImageIndex::kEntireLevel);
1992 while (imageIter.hasNext())
1993 {
1994 gl::ImageIndex index = imageIter.next();
1995
1996 const gl::ImageDesc &desc = texture->getTextureState().getImageDesc(index);
1997
1998 if (desc.size.empty())
1999 continue;
2000
2001 const gl::InternalFormat &format = *desc.format.info;
2002
2003 // Check for supported textures
2004 ASSERT(index.getType() == gl::TextureType::_2D ||
2005 index.getType() == gl::TextureType::_3D ||
2006 index.getType() == gl::TextureType::_2DArray ||
2007 index.getType() == gl::TextureType::CubeMap);
2008
2009 if (format.compressed)
2010 {
2011 // For compressed images, we've tracked a copy of the incoming data, so we can
2012 // use that rather than try to read data back that may have been converted.
2013
2014 // Look up the data for the requested texture
2015 const auto &foundTextureLevels = cachedTextureLevelData.find(texture->id());
2016 ASSERT(foundTextureLevels != cachedTextureLevelData.end());
2017
2018 // For that texture, look up the data for the given level
2019 GLint level = index.getLevelIndex();
2020 const auto &foundTextureLevel = foundTextureLevels->second.find(level);
2021 ASSERT(foundTextureLevel != foundTextureLevels->second.end());
2022 const std::vector<uint8_t> &capturedTextureLevel = foundTextureLevel->second;
2023
2024 // Use the shadow copy of the data to populate the call
2025 CaptureTextureContents(setupCalls, &replayState, texture, index, desc,
2026 static_cast<GLuint>(capturedTextureLevel.size()),
2027 capturedTextureLevel.data());
2028 }
2029 else
2030 {
2031 // Use ANGLE_get_image to read back pixel data.
2032 if (context->getExtensions().getImageANGLE)
2033 {
2034 GLenum getFormat = format.format;
2035 GLenum getType = format.type;
2036
2037 angle::MemoryBuffer data;
2038
2039 const gl::Extents size(desc.size.width, desc.size.height, desc.size.depth);
2040 const gl::PixelUnpackState &unpack = apiState.getUnpackState();
2041
2042 GLuint endByte = 0;
2043 bool unpackSize =
2044 format.computePackUnpackEndByte(getType, size, unpack, true, &endByte);
2045 ASSERT(unpackSize);
2046
2047 bool result = data.resize(endByte);
2048 ASSERT(result);
2049
2050 gl::PixelPackState packState;
2051 packState.alignment = 1;
2052
2053 (void)texture->getTexImage(context, packState, nullptr, index.getTarget(),
2054 index.getLevelIndex(), getFormat, getType,
2055 data.data());
2056
2057 CaptureTextureContents(setupCalls, &replayState, texture, index, desc,
2058 static_cast<GLuint>(data.size()), data.data());
2059 }
2060 else
2061 {
2062 CaptureTextureContents(setupCalls, &replayState, texture, index, desc, 0,
2063 nullptr);
2064 }
2065 }
2066 }
2067 }
2068
2069 // Set Texture bindings.
2070 size_t currentActiveTexture = 0;
2071 for (gl::TextureType textureType : angle::AllEnums<gl::TextureType>())
2072 {
2073 const gl::TextureBindingVector &bindings = boundTextures[textureType];
2074 for (size_t bindingIndex = 0; bindingIndex < bindings.size(); ++bindingIndex)
2075 {
2076 gl::TextureID textureID = bindings[bindingIndex].id();
2077
2078 if (textureID.value != 0)
2079 {
2080 if (currentActiveTexture != bindingIndex)
2081 {
2082 cap(CaptureActiveTexture(replayState, true,
2083 GL_TEXTURE0 + static_cast<GLenum>(bindingIndex)));
2084 currentActiveTexture = bindingIndex;
2085 }
2086
2087 if (currentTextureBindings[textureType] != textureID)
2088 {
2089 cap(CaptureBindTexture(replayState, true, textureType, textureID));
2090 currentTextureBindings[textureType] = textureID;
2091 }
2092 }
2093 }
2094 }
2095
2096 // Set active Texture.
2097 size_t stateActiveTexture = apiState.getActiveSampler();
2098 if (currentActiveTexture != stateActiveTexture)
2099 {
2100 cap(CaptureActiveTexture(replayState, true,
2101 GL_TEXTURE0 + static_cast<GLenum>(stateActiveTexture)));
2102 }
2103
2104 // Capture Renderbuffers.
2105 const gl::RenderbufferManager &renderbuffers = apiState.getRenderbufferManagerForCapture();
2106
2107 gl::RenderbufferID currentRenderbuffer = {0};
2108 for (const auto &renderbufIter : renderbuffers)
2109 {
2110 gl::RenderbufferID id = {renderbufIter.first};
2111 const gl::Renderbuffer *renderbuffer = renderbufIter.second;
2112
2113 // Generate renderbuffer id.
2114 cap(CaptureGenRenderbuffers(replayState, true, 1, &id));
2115 MaybeCaptureUpdateResourceIDs(setupCalls);
2116 cap(CaptureBindRenderbuffer(replayState, true, GL_RENDERBUFFER, id));
2117
2118 currentRenderbuffer = id;
2119
2120 GLenum internalformat = renderbuffer->getFormat().info->internalFormat;
2121
2122 if (renderbuffer->getSamples() > 0)
2123 {
2124 // Note: We could also use extensions if available.
2125 cap(CaptureRenderbufferStorageMultisample(
2126 replayState, true, GL_RENDERBUFFER, renderbuffer->getSamples(), internalformat,
2127 renderbuffer->getWidth(), renderbuffer->getHeight()));
2128 }
2129 else
2130 {
2131 cap(CaptureRenderbufferStorage(replayState, true, GL_RENDERBUFFER, internalformat,
2132 renderbuffer->getWidth(), renderbuffer->getHeight()));
2133 }
2134
2135 // TODO(jmadill): Capture renderbuffer contents. http://anglebug.com/3662
2136 }
2137
2138 // Set Renderbuffer binding.
2139 if (currentRenderbuffer != apiState.getRenderbufferId())
2140 {
2141 cap(CaptureBindRenderbuffer(replayState, true, GL_RENDERBUFFER,
2142 apiState.getRenderbufferId()));
2143 }
2144
2145 // Capture Framebuffers.
2146 const gl::FramebufferManager &framebuffers = apiState.getFramebufferManagerForCapture();
2147
2148 gl::FramebufferID currentDrawFramebuffer = {0};
2149 gl::FramebufferID currentReadFramebuffer = {0};
2150
2151 for (const auto &framebufferIter : framebuffers)
2152 {
2153 gl::FramebufferID id = {framebufferIter.first};
2154 const gl::Framebuffer *framebuffer = framebufferIter.second;
2155
2156 // The default Framebuffer exists (by default).
2157 if (framebuffer->isDefault())
2158 continue;
2159
2160 cap(CaptureGenFramebuffers(replayState, true, 1, &id));
2161 MaybeCaptureUpdateResourceIDs(setupCalls);
2162 cap(CaptureBindFramebuffer(replayState, true, GL_FRAMEBUFFER, id));
2163 currentDrawFramebuffer = currentReadFramebuffer = id;
2164
2165 // Color Attachments.
2166 for (const gl::FramebufferAttachment &colorAttachment : framebuffer->getColorAttachments())
2167 {
2168 if (!colorAttachment.isAttached())
2169 {
2170 continue;
2171 }
2172
2173 CaptureFramebufferAttachment(setupCalls, replayState, colorAttachment);
2174 }
2175
2176 const gl::FramebufferAttachment *depthAttachment = framebuffer->getDepthAttachment();
2177 if (depthAttachment)
2178 {
2179 ASSERT(depthAttachment->getBinding() == GL_DEPTH_ATTACHMENT);
2180 CaptureFramebufferAttachment(setupCalls, replayState, *depthAttachment);
2181 }
2182
2183 const gl::FramebufferAttachment *stencilAttachment = framebuffer->getStencilAttachment();
2184 if (stencilAttachment)
2185 {
2186 ASSERT(stencilAttachment->getBinding() == GL_STENCIL_ATTACHMENT);
2187 CaptureFramebufferAttachment(setupCalls, replayState, *stencilAttachment);
2188 }
2189
2190 // TODO(jmadill): Draw buffer states. http://anglebug.com/3662
2191 }
2192
2193 // Capture framebuffer bindings.
2194 gl::FramebufferID stateReadFramebuffer = apiState.getReadFramebuffer()->id();
2195 gl::FramebufferID stateDrawFramebuffer = apiState.getDrawFramebuffer()->id();
2196 if (stateDrawFramebuffer == stateReadFramebuffer)
2197 {
2198 if (currentDrawFramebuffer != stateDrawFramebuffer ||
2199 currentReadFramebuffer != stateReadFramebuffer)
2200 {
2201 cap(CaptureBindFramebuffer(replayState, true, GL_FRAMEBUFFER, stateDrawFramebuffer));
2202 currentDrawFramebuffer = currentReadFramebuffer = stateDrawFramebuffer;
2203 }
2204 }
2205 else
2206 {
2207 if (currentDrawFramebuffer != stateDrawFramebuffer)
2208 {
2209 cap(CaptureBindFramebuffer(replayState, true, GL_DRAW_FRAMEBUFFER,
2210 currentDrawFramebuffer));
2211 currentDrawFramebuffer = stateDrawFramebuffer;
2212 }
2213
2214 if (currentReadFramebuffer != stateReadFramebuffer)
2215 {
2216 cap(CaptureBindFramebuffer(replayState, true, GL_READ_FRAMEBUFFER,
2217 replayState.getReadFramebuffer()->id()));
2218 currentReadFramebuffer = stateReadFramebuffer;
2219 }
2220 }
2221
2222 // Capture Shaders and Programs.
2223 const gl::ShaderProgramManager &shadersAndPrograms =
2224 apiState.getShaderProgramManagerForCapture();
2225 const gl::ResourceMap<gl::Shader, gl::ShaderProgramID> &shaders =
2226 shadersAndPrograms.getShadersForCapture();
2227 const gl::ResourceMap<gl::Program, gl::ShaderProgramID> &programs =
2228 shadersAndPrograms.getProgramsForCapture();
2229
2230 // Capture Program binary state. Use shader ID 1 as a temporary shader ID.
2231 gl::ShaderProgramID tempShaderID = {1};
2232 for (const auto &programIter : programs)
2233 {
2234 gl::ShaderProgramID id = {programIter.first};
2235 const gl::Program *program = programIter.second;
2236
2237 // Get last compiled shader source.
2238 const auto &foundSources = cachedProgramSources.find(id);
2239 ASSERT(foundSources != cachedProgramSources.end());
2240 const ProgramSources &linkedSources = foundSources->second;
2241
2242 // Unlinked programs don't have an executable. Thus they don't need to be linked.
2243 if (!program->isLinked())
2244 {
2245 continue;
2246 }
2247
2248 cap(CaptureCreateProgram(replayState, true, id.value));
2249
2250 // Compile with last linked sources.
2251 for (gl::ShaderType shaderType : program->getExecutable().getLinkedShaderStages())
2252 {
2253 const std::string &sourceString = linkedSources[shaderType];
2254 const char *sourcePointer = sourceString.c_str();
2255
2256 // Compile and attach the temporary shader. Then free it immediately.
2257 cap(CaptureCreateShader(replayState, true, shaderType, tempShaderID.value));
2258 cap(CaptureShaderSource(replayState, true, tempShaderID, 1, &sourcePointer, nullptr));
2259 cap(CaptureCompileShader(replayState, true, tempShaderID));
2260 cap(CaptureAttachShader(replayState, true, id, tempShaderID));
2261 cap(CaptureDeleteShader(replayState, true, tempShaderID));
2262 }
2263
2264 // Gather XFB varyings
2265 std::vector<std::string> xfbVaryings;
2266 for (const gl::TransformFeedbackVarying &xfbVarying :
2267 program->getState().getLinkedTransformFeedbackVaryings())
2268 {
2269 xfbVaryings.push_back(xfbVarying.nameWithArrayIndex());
2270 }
2271
2272 if (!xfbVaryings.empty())
2273 {
2274 std::vector<const char *> varyingsStrings;
2275 for (const std::string &varyingString : xfbVaryings)
2276 {
2277 varyingsStrings.push_back(varyingString.data());
2278 }
2279
2280 GLenum xfbMode = program->getState().getTransformFeedbackBufferMode();
2281 cap(CaptureTransformFeedbackVaryings(replayState, true, id,
2282 static_cast<GLint>(xfbVaryings.size()),
2283 varyingsStrings.data(), xfbMode));
2284 }
2285
2286 cap(CaptureLinkProgram(replayState, true, id));
2287 CaptureUpdateUniformLocations(program, setupCalls);
2288 CaptureUpdateUniformValues(replayState, context, program, setupCalls);
2289 }
2290
2291 // Handle shaders.
2292 for (const auto &shaderIter : shaders)
2293 {
2294 gl::ShaderProgramID id = {shaderIter.first};
2295 gl::Shader *shader = shaderIter.second;
2296 cap(CaptureCreateShader(replayState, true, shader->getType(), id.value));
2297
2298 std::string shaderSource = shader->getSourceString();
2299 const char *sourcePointer = shaderSource.empty() ? nullptr : shaderSource.c_str();
2300
2301 // This does not handle some more tricky situations like attaching shaders to a non-linked
2302 // program. Or attaching uncompiled shaders. Or attaching and then deleting a shader.
2303 // TODO(jmadill): Handle trickier program uses. http://anglebug.com/3662
2304 if (shader->isCompiled())
2305 {
2306 const auto &foundSources = cachedShaderSources.find(id);
2307 ASSERT(foundSources != cachedShaderSources.end());
2308 const std::string &capturedSource = foundSources->second;
2309
2310 if (capturedSource != shaderSource)
2311 {
2312 ASSERT(!capturedSource.empty());
2313 sourcePointer = capturedSource.c_str();
2314 }
2315
2316 cap(CaptureShaderSource(replayState, true, id, 1, &sourcePointer, nullptr));
2317 cap(CaptureCompileShader(replayState, true, id));
2318 }
2319
2320 if (sourcePointer && (!shader->isCompiled() || sourcePointer != shaderSource.c_str()))
2321 {
2322 cap(CaptureShaderSource(replayState, true, id, 1, &sourcePointer, nullptr));
2323 }
2324 }
2325
2326 // For now we assume the installed program executable is the same as the current program.
2327 // TODO(jmadill): Handle installed program executable. http://anglebug.com/3662
2328 if (apiState.getProgram())
2329 {
2330 cap(CaptureUseProgram(replayState, true, apiState.getProgram()->id()));
2331 CaptureUpdateCurrentProgram(setupCalls->back(), setupCalls);
2332 }
2333
2334 // TODO(http://anglebug.com/3662): ES 3.x objects.
2335
2336 // Create existing queries. Note that queries may be genned and not yet started. In that
2337 // case the queries will exist in the query map as nullptr entries.
2338 const gl::QueryMap &queryMap = context->getQueriesForCapture();
2339 for (gl::QueryMap::Iterator queryIter = queryMap.beginWithNull();
2340 queryIter != queryMap.endWithNull(); ++queryIter)
2341 {
2342 ASSERT(queryIter->first);
2343 gl::QueryID queryID = {queryIter->first};
2344
2345 cap(CaptureGenQueries(replayState, true, 1, &queryID));
2346 MaybeCaptureUpdateResourceIDs(setupCalls);
2347
2348 gl::Query *query = queryIter->second;
2349 if (query)
2350 {
2351 gl::QueryType queryType = query->getType();
2352
2353 // Begin the query to generate the object
2354 cap(CaptureBeginQuery(replayState, true, queryType, queryID));
2355
2356 // End the query if it was not active
2357 if (!IsQueryActive(apiState, queryID))
2358 {
2359 cap(CaptureEndQuery(replayState, true, queryType));
2360 }
2361 }
2362 }
2363
2364 // Transform Feedback
2365 const gl::TransformFeedbackMap &xfbMap = context->getTransformFeedbacksForCapture();
2366 for (const auto &xfbIter : xfbMap)
2367 {
2368 gl::TransformFeedbackID xfbID = {xfbIter.first};
2369 cap(CaptureGenTransformFeedbacks(replayState, true, 1, &xfbID));
2370 MaybeCaptureUpdateResourceIDs(setupCalls);
2371
2372 gl::TransformFeedback *xfb = xfbIter.second;
2373 if (!xfb)
2374 {
2375 // The object was never created
2376 continue;
2377 }
2378
2379 // Bind XFB to create the object
2380 cap(CaptureBindTransformFeedback(replayState, true, GL_TRANSFORM_FEEDBACK, xfbID));
2381
2382 // Bind the buffers associated with this XFB object
2383 for (size_t i = 0; i < xfb->getIndexedBufferCount(); ++i)
2384 {
2385 const gl::OffsetBindingPointer<gl::Buffer> &xfbBuffer = xfb->getIndexedBuffer(i);
2386
2387 // Note: Buffers bound with BindBufferBase can be used with BindBuffer
2388 cap(CaptureBindBufferRange(replayState, true, gl::BufferBinding::TransformFeedback, 0,
2389 xfbBuffer.id(), xfbBuffer.getOffset(), xfbBuffer.getSize()));
2390 }
2391
2392 if (xfb->isActive() || xfb->isPaused())
2393 {
2394 // We don't support active XFB in MEC yet
2395 UNIMPLEMENTED();
2396 }
2397 }
2398
2399 // Bind the current XFB buffer after populating XFB objects
2400 gl::TransformFeedback *currentXFB = apiState.getCurrentTransformFeedback();
2401 cap(CaptureBindTransformFeedback(replayState, true, GL_TRANSFORM_FEEDBACK, currentXFB->id()));
2402
2403 // Capture Sampler Objects
2404 const gl::SamplerManager &samplers = apiState.getSamplerManagerForCapture();
2405 for (const auto &samplerIter : samplers)
2406 {
2407 gl::SamplerID samplerID = {samplerIter.first};
2408 cap(CaptureGenSamplers(replayState, true, 1, &samplerID));
2409 MaybeCaptureUpdateResourceIDs(setupCalls);
2410
2411 gl::Sampler *sampler = samplerIter.second;
2412 if (!sampler)
2413 {
2414 continue;
2415 }
2416
2417 gl::SamplerState defaultSamplerState;
2418 if (sampler->getMinFilter() != defaultSamplerState.getMinFilter())
2419 {
2420 cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_MIN_FILTER,
2421 sampler->getMinFilter()));
2422 }
2423 if (sampler->getMagFilter() != defaultSamplerState.getMagFilter())
2424 {
2425 cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_MAG_FILTER,
2426 sampler->getMagFilter()));
2427 }
2428 if (sampler->getWrapS() != defaultSamplerState.getWrapS())
2429 {
2430 cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_WRAP_S,
2431 sampler->getWrapS()));
2432 }
2433 if (sampler->getWrapR() != defaultSamplerState.getWrapR())
2434 {
2435 cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_WRAP_R,
2436 sampler->getWrapR()));
2437 }
2438 if (sampler->getWrapT() != defaultSamplerState.getWrapT())
2439 {
2440 cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_WRAP_T,
2441 sampler->getWrapT()));
2442 }
2443 if (sampler->getMinLod() != defaultSamplerState.getMinLod())
2444 {
2445 cap(CaptureSamplerParameterf(replayState, true, samplerID, GL_TEXTURE_MIN_LOD,
2446 sampler->getMinLod()));
2447 }
2448 if (sampler->getMaxLod() != defaultSamplerState.getMaxLod())
2449 {
2450 cap(CaptureSamplerParameterf(replayState, true, samplerID, GL_TEXTURE_MAX_LOD,
2451 sampler->getMaxLod()));
2452 }
2453 if (sampler->getCompareMode() != defaultSamplerState.getCompareMode())
2454 {
2455 cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_COMPARE_MODE,
2456 sampler->getCompareMode()));
2457 }
2458 if (sampler->getCompareFunc() != defaultSamplerState.getCompareFunc())
2459 {
2460 cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_COMPARE_FUNC,
2461 sampler->getCompareFunc()));
2462 }
2463 }
2464
2465 // Bind samplers
2466 gl::SamplerBindingVector samplerBindings = apiState.getSamplers();
2467 for (GLuint bindingIndex = 0; bindingIndex < static_cast<GLuint>(samplerBindings.size());
2468 ++bindingIndex)
2469 {
2470 gl::SamplerID samplerID = samplerBindings[bindingIndex].id();
2471 if (samplerID.value != 0)
2472 {
2473 cap(CaptureBindSampler(replayState, true, bindingIndex, samplerID));
2474 }
2475 }
2476
2477 // Capture GL Context states.
2478 // TODO(http://anglebug.com/3662): Complete state capture.
2479 auto capCap = [cap, &replayState](GLenum capEnum, bool capValue) {
2480 if (capValue)
2481 {
2482 cap(CaptureEnable(replayState, true, capEnum));
2483 }
2484 else
2485 {
2486 cap(CaptureDisable(replayState, true, capEnum));
2487 }
2488 };
2489
2490 // Rasterizer state. Missing ES 3.x features.
2491 // TODO(http://anglebug.com/3662): Complete state capture.
2492 const gl::RasterizerState &defaultRasterState = replayState.getRasterizerState();
2493 const gl::RasterizerState ¤tRasterState = apiState.getRasterizerState();
2494 if (currentRasterState.cullFace != defaultRasterState.cullFace)
2495 {
2496 capCap(GL_CULL_FACE, currentRasterState.cullFace);
2497 }
2498
2499 if (currentRasterState.cullMode != defaultRasterState.cullMode)
2500 {
2501 cap(CaptureCullFace(replayState, true, currentRasterState.cullMode));
2502 }
2503
2504 if (currentRasterState.frontFace != defaultRasterState.frontFace)
2505 {
2506 cap(CaptureFrontFace(replayState, true, currentRasterState.frontFace));
2507 }
2508
2509 // Depth/stencil state.
2510 const gl::DepthStencilState &defaultDSState = replayState.getDepthStencilState();
2511 const gl::DepthStencilState ¤tDSState = apiState.getDepthStencilState();
2512 if (defaultDSState.depthFunc != currentDSState.depthFunc)
2513 {
2514 cap(CaptureDepthFunc(replayState, true, currentDSState.depthFunc));
2515 }
2516
2517 if (defaultDSState.depthMask != currentDSState.depthMask)
2518 {
2519 cap(CaptureDepthMask(replayState, true, gl::ConvertToGLBoolean(currentDSState.depthMask)));
2520 }
2521
2522 if (defaultDSState.depthTest != currentDSState.depthTest)
2523 {
2524 capCap(GL_DEPTH_TEST, currentDSState.depthTest);
2525 }
2526
2527 if (defaultDSState.stencilTest != currentDSState.stencilTest)
2528 {
2529 capCap(GL_STENCIL_TEST, currentDSState.stencilTest);
2530 }
2531
2532 if (defaultDSState.stencilFunc != currentDSState.stencilFunc ||
2533 defaultDSState.stencilMask != currentDSState.stencilMask || apiState.getStencilRef() != 0)
2534 {
2535 cap(CaptureStencilFuncSeparate(replayState, true, GL_FRONT, currentDSState.stencilFunc,
2536 apiState.getStencilRef(), currentDSState.stencilMask));
2537 }
2538
2539 if (defaultDSState.stencilBackFunc != currentDSState.stencilBackFunc ||
2540 defaultDSState.stencilBackMask != currentDSState.stencilBackMask ||
2541 apiState.getStencilBackRef() != 0)
2542 {
2543 cap(CaptureStencilFuncSeparate(replayState, true, GL_BACK, currentDSState.stencilBackFunc,
2544 apiState.getStencilBackRef(),
2545 currentDSState.stencilBackMask));
2546 }
2547
2548 if (defaultDSState.stencilFail != currentDSState.stencilFail ||
2549 defaultDSState.stencilPassDepthFail != currentDSState.stencilPassDepthFail ||
2550 defaultDSState.stencilPassDepthPass != currentDSState.stencilPassDepthPass)
2551 {
2552 cap(CaptureStencilOpSeparate(replayState, true, GL_FRONT, currentDSState.stencilFail,
2553 currentDSState.stencilPassDepthFail,
2554 currentDSState.stencilPassDepthPass));
2555 }
2556
2557 if (defaultDSState.stencilBackFail != currentDSState.stencilBackFail ||
2558 defaultDSState.stencilBackPassDepthFail != currentDSState.stencilBackPassDepthFail ||
2559 defaultDSState.stencilBackPassDepthPass != currentDSState.stencilBackPassDepthPass)
2560 {
2561 cap(CaptureStencilOpSeparate(replayState, true, GL_BACK, currentDSState.stencilBackFail,
2562 currentDSState.stencilBackPassDepthFail,
2563 currentDSState.stencilBackPassDepthPass));
2564 }
2565
2566 if (defaultDSState.stencilWritemask != currentDSState.stencilWritemask)
2567 {
2568 cap(CaptureStencilMaskSeparate(replayState, true, GL_FRONT,
2569 currentDSState.stencilWritemask));
2570 }
2571
2572 if (defaultDSState.stencilBackWritemask != currentDSState.stencilBackWritemask)
2573 {
2574 cap(CaptureStencilMaskSeparate(replayState, true, GL_BACK,
2575 currentDSState.stencilBackWritemask));
2576 }
2577
2578 // Blend state.
2579 const gl::BlendState &defaultBlendState = replayState.getBlendState();
2580 const gl::BlendState ¤tBlendState = apiState.getBlendState();
2581
2582 if (currentBlendState.blend != defaultBlendState.blend)
2583 {
2584 capCap(GL_BLEND, currentBlendState.blend);
2585 }
2586
2587 if (currentBlendState.sourceBlendRGB != defaultBlendState.sourceBlendRGB ||
2588 currentBlendState.destBlendRGB != defaultBlendState.destBlendRGB ||
2589 currentBlendState.sourceBlendAlpha != defaultBlendState.sourceBlendAlpha ||
2590 currentBlendState.destBlendAlpha != defaultBlendState.destBlendAlpha)
2591 {
2592 cap(CaptureBlendFuncSeparate(
2593 replayState, true, currentBlendState.sourceBlendRGB, currentBlendState.destBlendRGB,
2594 currentBlendState.sourceBlendAlpha, currentBlendState.destBlendAlpha));
2595 }
2596
2597 if (currentBlendState.blendEquationRGB != defaultBlendState.blendEquationRGB ||
2598 currentBlendState.blendEquationAlpha != defaultBlendState.blendEquationAlpha)
2599 {
2600 cap(CaptureBlendEquationSeparate(replayState, true, currentBlendState.blendEquationRGB,
2601 currentBlendState.blendEquationAlpha));
2602 }
2603
2604 if (currentBlendState.colorMaskRed != defaultBlendState.colorMaskRed ||
2605 currentBlendState.colorMaskGreen != defaultBlendState.colorMaskGreen ||
2606 currentBlendState.colorMaskBlue != defaultBlendState.colorMaskBlue ||
2607 currentBlendState.colorMaskAlpha != defaultBlendState.colorMaskAlpha)
2608 {
2609 cap(CaptureColorMask(replayState, true,
2610 gl::ConvertToGLBoolean(currentBlendState.colorMaskRed),
2611 gl::ConvertToGLBoolean(currentBlendState.colorMaskGreen),
2612 gl::ConvertToGLBoolean(currentBlendState.colorMaskBlue),
2613 gl::ConvertToGLBoolean(currentBlendState.colorMaskAlpha)));
2614 }
2615
2616 const gl::ColorF ¤tBlendColor = apiState.getBlendColor();
2617 if (currentBlendColor != gl::ColorF())
2618 {
2619 cap(CaptureBlendColor(replayState, true, currentBlendColor.red, currentBlendColor.green,
2620 currentBlendColor.blue, currentBlendColor.alpha));
2621 }
2622
2623 // Pixel storage states.
2624 gl::PixelPackState ¤tPackState = replayState.getPackState();
2625 if (currentPackState.alignment != apiState.getPackAlignment())
2626 {
2627 cap(CapturePixelStorei(replayState, true, GL_PACK_ALIGNMENT, apiState.getPackAlignment()));
2628 currentPackState.alignment = apiState.getPackAlignment();
2629 }
2630
2631 if (currentPackState.rowLength != apiState.getPackRowLength())
2632 {
2633 cap(CapturePixelStorei(replayState, true, GL_PACK_ROW_LENGTH, apiState.getPackRowLength()));
2634 currentPackState.rowLength = apiState.getPackRowLength();
2635 }
2636
2637 if (currentPackState.skipRows != apiState.getPackSkipRows())
2638 {
2639 cap(CapturePixelStorei(replayState, true, GL_PACK_SKIP_ROWS, apiState.getPackSkipRows()));
2640 currentPackState.skipRows = apiState.getPackSkipRows();
2641 }
2642
2643 if (currentPackState.skipPixels != apiState.getPackSkipPixels())
2644 {
2645 cap(CapturePixelStorei(replayState, true, GL_PACK_SKIP_PIXELS,
2646 apiState.getPackSkipPixels()));
2647 currentPackState.skipPixels = apiState.getPackSkipPixels();
2648 }
2649
2650 // We set unpack alignment above, no need to change it here
2651 ASSERT(currentUnpackState.alignment == 1);
2652 if (currentUnpackState.rowLength != apiState.getUnpackRowLength())
2653 {
2654 cap(CapturePixelStorei(replayState, true, GL_UNPACK_ROW_LENGTH,
2655 apiState.getUnpackRowLength()));
2656 currentUnpackState.rowLength = apiState.getUnpackRowLength();
2657 }
2658
2659 if (currentUnpackState.skipRows != apiState.getUnpackSkipRows())
2660 {
2661 cap(CapturePixelStorei(replayState, true, GL_UNPACK_SKIP_ROWS,
2662 apiState.getUnpackSkipRows()));
2663 currentUnpackState.skipRows = apiState.getUnpackSkipRows();
2664 }
2665
2666 if (currentUnpackState.skipPixels != apiState.getUnpackSkipPixels())
2667 {
2668 cap(CapturePixelStorei(replayState, true, GL_UNPACK_SKIP_PIXELS,
2669 apiState.getUnpackSkipPixels()));
2670 currentUnpackState.skipPixels = apiState.getUnpackSkipPixels();
2671 }
2672
2673 if (currentUnpackState.imageHeight != apiState.getUnpackImageHeight())
2674 {
2675 cap(CapturePixelStorei(replayState, true, GL_UNPACK_IMAGE_HEIGHT,
2676 apiState.getUnpackImageHeight()));
2677 currentUnpackState.imageHeight = apiState.getUnpackImageHeight();
2678 }
2679
2680 if (currentUnpackState.skipImages != apiState.getUnpackSkipImages())
2681 {
2682 cap(CapturePixelStorei(replayState, true, GL_UNPACK_SKIP_IMAGES,
2683 apiState.getUnpackSkipImages()));
2684 currentUnpackState.skipImages = apiState.getUnpackSkipImages();
2685 }
2686
2687 // Clear state. Missing ES 3.x features.
2688 // TODO(http://anglebug.com/3662): Complete state capture.
2689 const gl::ColorF ¤tClearColor = apiState.getColorClearValue();
2690 if (currentClearColor != gl::ColorF())
2691 {
2692 cap(CaptureClearColor(replayState, true, currentClearColor.red, currentClearColor.green,
2693 currentClearColor.blue, currentClearColor.alpha));
2694 }
2695
2696 if (apiState.getDepthClearValue() != 1.0f)
2697 {
2698 cap(CaptureClearDepthf(replayState, true, apiState.getDepthClearValue()));
2699 }
2700
2701 if (apiState.getStencilClearValue() != 0)
2702 {
2703 cap(CaptureClearStencil(replayState, true, apiState.getStencilClearValue()));
2704 }
2705
2706 // Viewport / scissor / clipping planes.
2707 const gl::Rectangle ¤tViewport = apiState.getViewport();
2708 if (currentViewport != gl::Rectangle())
2709 {
2710 cap(CaptureViewport(replayState, true, currentViewport.x, currentViewport.y,
2711 currentViewport.width, currentViewport.height));
2712 }
2713
2714 if (apiState.getNearPlane() != 0.0f || apiState.getFarPlane() != 1.0f)
2715 {
2716 cap(CaptureDepthRangef(replayState, true, apiState.getNearPlane(), apiState.getFarPlane()));
2717 }
2718
2719 if (apiState.isScissorTestEnabled())
2720 {
2721 capCap(GL_SCISSOR_TEST, apiState.isScissorTestEnabled());
2722 }
2723
2724 const gl::Rectangle ¤tScissor = apiState.getScissor();
2725 if (currentScissor != gl::Rectangle())
2726 {
2727 cap(CaptureScissor(replayState, true, currentScissor.x, currentScissor.y,
2728 currentScissor.width, currentScissor.height));
2729 }
2730
2731 if (apiState.isDitherEnabled())
2732 {
2733 capCap(GL_DITHER, apiState.isDitherEnabled());
2734 }
2735
2736 const gl::SyncManager &syncs = apiState.getSyncManagerForCapture();
2737 for (const auto &syncIter : syncs)
2738 {
2739 // TODO: Create existing sync objects (http://anglebug.com/3662)
2740 (void)syncIter;
2741 UNIMPLEMENTED();
2742 }
2743
2744 // Allow the replayState object to be destroyed conveniently.
2745 replayState.setBufferBinding(context, gl::BufferBinding::Array, nullptr);
2746 }
2747 } // namespace
2748
ParamCapture()2749 ParamCapture::ParamCapture() : type(ParamType::TGLenum), enumGroup(gl::GLenumGroup::DefaultGroup) {}
2750
ParamCapture(const char * nameIn,ParamType typeIn)2751 ParamCapture::ParamCapture(const char *nameIn, ParamType typeIn)
2752 : name(nameIn), type(typeIn), enumGroup(gl::GLenumGroup::DefaultGroup)
2753 {}
2754
2755 ParamCapture::~ParamCapture() = default;
2756
ParamCapture(ParamCapture && other)2757 ParamCapture::ParamCapture(ParamCapture &&other)
2758 : type(ParamType::TGLenum), enumGroup(gl::GLenumGroup::DefaultGroup)
2759 {
2760 *this = std::move(other);
2761 }
2762
operator =(ParamCapture && other)2763 ParamCapture &ParamCapture::operator=(ParamCapture &&other)
2764 {
2765 std::swap(name, other.name);
2766 std::swap(type, other.type);
2767 std::swap(value, other.value);
2768 std::swap(enumGroup, other.enumGroup);
2769 std::swap(data, other.data);
2770 std::swap(arrayClientPointerIndex, other.arrayClientPointerIndex);
2771 std::swap(readBufferSizeBytes, other.readBufferSizeBytes);
2772 return *this;
2773 }
2774
ParamBuffer()2775 ParamBuffer::ParamBuffer() {}
2776
2777 ParamBuffer::~ParamBuffer() = default;
2778
ParamBuffer(ParamBuffer && other)2779 ParamBuffer::ParamBuffer(ParamBuffer &&other)
2780 {
2781 *this = std::move(other);
2782 }
2783
operator =(ParamBuffer && other)2784 ParamBuffer &ParamBuffer::operator=(ParamBuffer &&other)
2785 {
2786 std::swap(mParamCaptures, other.mParamCaptures);
2787 std::swap(mClientArrayDataParam, other.mClientArrayDataParam);
2788 std::swap(mReadBufferSize, other.mReadBufferSize);
2789 std::swap(mReturnValueCapture, other.mReturnValueCapture);
2790 std::swap(mMappedBufferID, other.mMappedBufferID);
2791 return *this;
2792 }
2793
getParam(const char * paramName,ParamType paramType,int index)2794 ParamCapture &ParamBuffer::getParam(const char *paramName, ParamType paramType, int index)
2795 {
2796 ParamCapture &capture = mParamCaptures[index];
2797 ASSERT(capture.name == paramName);
2798 ASSERT(capture.type == paramType);
2799 return capture;
2800 }
2801
getParam(const char * paramName,ParamType paramType,int index) const2802 const ParamCapture &ParamBuffer::getParam(const char *paramName,
2803 ParamType paramType,
2804 int index) const
2805 {
2806 return const_cast<ParamBuffer *>(this)->getParam(paramName, paramType, index);
2807 }
2808
getParamFlexName(const char * paramName1,const char * paramName2,ParamType paramType,int index)2809 ParamCapture &ParamBuffer::getParamFlexName(const char *paramName1,
2810 const char *paramName2,
2811 ParamType paramType,
2812 int index)
2813 {
2814 ParamCapture &capture = mParamCaptures[index];
2815 ASSERT(capture.name == paramName1 || capture.name == paramName2);
2816 ASSERT(capture.type == paramType);
2817 return capture;
2818 }
2819
getParamFlexName(const char * paramName1,const char * paramName2,ParamType paramType,int index) const2820 const ParamCapture &ParamBuffer::getParamFlexName(const char *paramName1,
2821 const char *paramName2,
2822 ParamType paramType,
2823 int index) const
2824 {
2825 return const_cast<ParamBuffer *>(this)->getParamFlexName(paramName1, paramName2, paramType,
2826 index);
2827 }
2828
addParam(ParamCapture && param)2829 void ParamBuffer::addParam(ParamCapture &¶m)
2830 {
2831 if (param.arrayClientPointerIndex != -1)
2832 {
2833 ASSERT(mClientArrayDataParam == -1);
2834 mClientArrayDataParam = static_cast<int>(mParamCaptures.size());
2835 }
2836
2837 mReadBufferSize = std::max(param.readBufferSizeBytes, mReadBufferSize);
2838 mParamCaptures.emplace_back(std::move(param));
2839 }
2840
addReturnValue(ParamCapture && returnValue)2841 void ParamBuffer::addReturnValue(ParamCapture &&returnValue)
2842 {
2843 mReturnValueCapture = std::move(returnValue);
2844 }
2845
getClientArrayPointerParameter()2846 ParamCapture &ParamBuffer::getClientArrayPointerParameter()
2847 {
2848 ASSERT(hasClientArrayData());
2849 return mParamCaptures[mClientArrayDataParam];
2850 }
2851
CallCapture(gl::EntryPoint entryPointIn,ParamBuffer && paramsIn)2852 CallCapture::CallCapture(gl::EntryPoint entryPointIn, ParamBuffer &¶msIn)
2853 : entryPoint(entryPointIn), params(std::move(paramsIn))
2854 {}
2855
CallCapture(const std::string & customFunctionNameIn,ParamBuffer && paramsIn)2856 CallCapture::CallCapture(const std::string &customFunctionNameIn, ParamBuffer &¶msIn)
2857 : entryPoint(gl::EntryPoint::Invalid),
2858 customFunctionName(customFunctionNameIn),
2859 params(std::move(paramsIn))
2860 {}
2861
2862 CallCapture::~CallCapture() = default;
2863
CallCapture(CallCapture && other)2864 CallCapture::CallCapture(CallCapture &&other)
2865 {
2866 *this = std::move(other);
2867 }
2868
operator =(CallCapture && other)2869 CallCapture &CallCapture::operator=(CallCapture &&other)
2870 {
2871 std::swap(entryPoint, other.entryPoint);
2872 std::swap(customFunctionName, other.customFunctionName);
2873 std::swap(params, other.params);
2874 return *this;
2875 }
2876
name() const2877 const char *CallCapture::name() const
2878 {
2879 if (entryPoint == gl::EntryPoint::Invalid)
2880 {
2881 ASSERT(!customFunctionName.empty());
2882 return customFunctionName.c_str();
2883 }
2884
2885 return gl::GetEntryPointName(entryPoint);
2886 }
2887
ReplayContext(size_t readBufferSizebytes,const gl::AttribArray<size_t> & clientArraysSizebytes)2888 ReplayContext::ReplayContext(size_t readBufferSizebytes,
2889 const gl::AttribArray<size_t> &clientArraysSizebytes)
2890 {
2891 mReadBuffer.resize(readBufferSizebytes);
2892
2893 for (uint32_t i = 0; i < clientArraysSizebytes.size(); i++)
2894 {
2895 mClientArraysBuffer[i].resize(clientArraysSizebytes[i]);
2896 }
2897 }
~ReplayContext()2898 ReplayContext::~ReplayContext() {}
2899
FrameCapture()2900 FrameCapture::FrameCapture()
2901 : mEnabled(true),
2902 mCompression(true),
2903 mClientVertexArrayMap{},
2904 mFrameIndex(0),
2905 mFrameStart(0),
2906 mFrameEnd(10),
2907 mClientArraySizes{},
2908 mReadBufferSize(0),
2909 mHasResourceType{}
2910 {
2911 reset();
2912
2913 #if defined(ANGLE_PLATFORM_ANDROID)
2914 PrimeAndroidEnvironmentVariables();
2915 #endif
2916
2917 std::string enabledFromEnv = angle::GetEnvironmentVar(kEnabledVarName);
2918 if (enabledFromEnv == "0")
2919 {
2920 mEnabled = false;
2921 }
2922
2923 std::string pathFromEnv = angle::GetEnvironmentVar(kOutDirectoryVarName);
2924 if (pathFromEnv.empty())
2925 {
2926 mOutDirectory = GetDefaultOutDirectory();
2927 }
2928 else
2929 {
2930 mOutDirectory = pathFromEnv;
2931 }
2932
2933 // Ensure the capture path ends with a slash.
2934 if (mOutDirectory.back() != '\\' && mOutDirectory.back() != '/')
2935 {
2936 mOutDirectory += '/';
2937 }
2938
2939 std::string startFromEnv = angle::GetEnvironmentVar(kFrameStartVarName);
2940 if (!startFromEnv.empty())
2941 {
2942 mFrameStart = atoi(startFromEnv.c_str());
2943 }
2944
2945 std::string endFromEnv = angle::GetEnvironmentVar(kFrameEndVarName);
2946 if (!endFromEnv.empty())
2947 {
2948 mFrameEnd = atoi(endFromEnv.c_str());
2949 }
2950
2951 std::string labelFromEnv = angle::GetEnvironmentVar(kCaptureLabel);
2952 if (!labelFromEnv.empty())
2953 {
2954 // Optional label to provide unique file names and namespaces
2955 mCaptureLabel = labelFromEnv;
2956 }
2957
2958 std::string compressionFromEnv = angle::GetEnvironmentVar(kCompression);
2959 if (compressionFromEnv == "0")
2960 {
2961 mCompression = false;
2962 }
2963 }
2964
2965 FrameCapture::~FrameCapture() = default;
2966
captureCompressedTextureData(const gl::Context * context,const CallCapture & call)2967 void FrameCapture::captureCompressedTextureData(const gl::Context *context, const CallCapture &call)
2968 {
2969 // For compressed textures, track a shadow copy of the data
2970 // for use during mid-execution capture, rather than reading it back
2971 // with ANGLE_get_image
2972
2973 // Storing the compressed data is handled the same for all entry points,
2974 // they just have slightly different parameter locations
2975 int dataParamOffset = -1;
2976 int xoffsetParamOffset = -1;
2977 int yoffsetParamOffset = -1;
2978 int zoffsetParamOffset = -1;
2979 int widthParamOffset = -1;
2980 int heightParamOffset = -1;
2981 int depthParamOffset = -1;
2982 switch (call.entryPoint)
2983 {
2984 case gl::EntryPoint::CompressedTexSubImage3D:
2985 xoffsetParamOffset = 2;
2986 yoffsetParamOffset = 3;
2987 zoffsetParamOffset = 4;
2988 widthParamOffset = 5;
2989 heightParamOffset = 6;
2990 depthParamOffset = 7;
2991 dataParamOffset = 10;
2992 break;
2993 case gl::EntryPoint::CompressedTexImage3D:
2994 widthParamOffset = 4;
2995 heightParamOffset = 5;
2996 depthParamOffset = 6;
2997 dataParamOffset = 9;
2998 break;
2999 case gl::EntryPoint::CompressedTexSubImage2D:
3000 xoffsetParamOffset = 2;
3001 yoffsetParamOffset = 3;
3002 widthParamOffset = 4;
3003 heightParamOffset = 5;
3004 dataParamOffset = 8;
3005 break;
3006 case gl::EntryPoint::CompressedTexImage2D:
3007 widthParamOffset = 3;
3008 heightParamOffset = 4;
3009 dataParamOffset = 7;
3010 break;
3011 default:
3012 // There should be no other callers of this function
3013 ASSERT(0);
3014 break;
3015 }
3016
3017 gl::Buffer *pixelUnpackBuffer =
3018 context->getState().getTargetBuffer(gl::BufferBinding::PixelUnpack);
3019
3020 const uint8_t *data = static_cast<const uint8_t *>(
3021 call.params.getParam("data", ParamType::TvoidConstPointer, dataParamOffset)
3022 .value.voidConstPointerVal);
3023
3024 GLsizei imageSize = call.params.getParam("imageSize", ParamType::TGLsizei, dataParamOffset - 1)
3025 .value.GLsizeiVal;
3026
3027 const uint8_t *pixelData = nullptr;
3028
3029 if (pixelUnpackBuffer)
3030 {
3031 // If using pixel unpack buffer, map the buffer and track its data
3032 ASSERT(!pixelUnpackBuffer->isMapped());
3033 (void)pixelUnpackBuffer->mapRange(context, reinterpret_cast<GLintptr>(data), imageSize,
3034 GL_MAP_READ_BIT);
3035
3036 pixelData = reinterpret_cast<const uint8_t *>(pixelUnpackBuffer->getMapPointer());
3037 }
3038 else
3039 {
3040 pixelData = data;
3041 }
3042
3043 if (!pixelData)
3044 {
3045 // If no pointer was provided and we weren't able to map the buffer, there is no data to
3046 // capture
3047 return;
3048 }
3049
3050 // Look up the texture type
3051 gl::TextureTarget targetPacked =
3052 call.params.getParam("targetPacked", ParamType::TTextureTarget, 0).value.TextureTargetVal;
3053 gl::TextureType textureType = gl::TextureTargetToType(targetPacked);
3054
3055 // Create a copy of the incoming data
3056 std::vector<uint8_t> compressedData;
3057 compressedData.assign(pixelData, pixelData + imageSize);
3058
3059 // Look up the currently bound texture
3060 gl::Texture *texture = context->getState().getTargetTexture(textureType);
3061 ASSERT(texture);
3062
3063 // Record the data, indexed by textureID and level
3064 GLint level = call.params.getParam("level", ParamType::TGLint, 1).value.GLintVal;
3065 auto foundTextureLevels = mCachedTextureLevelData.find(texture->id());
3066 if (foundTextureLevels == mCachedTextureLevelData.end())
3067 {
3068 // Initialize the texture ID data.
3069 auto emplaceResult = mCachedTextureLevelData.emplace(texture->id(), TextureLevels());
3070 ASSERT(emplaceResult.second);
3071 foundTextureLevels = emplaceResult.first;
3072 }
3073
3074 // Get the format of the texture for use with the compressed block size math.
3075 const gl::InternalFormat &format = *texture->getFormat(targetPacked, level).info;
3076
3077 TextureLevels &foundLevels = foundTextureLevels->second;
3078 auto foundLevel = foundLevels.find(level);
3079
3080 // Divide dimensions according to block size.
3081 const gl::Extents &levelExtents = texture->getExtents(targetPacked, level);
3082
3083 if (foundLevel == foundLevels.end())
3084 {
3085 // Initialize texture rectangle data. Default init to zero for stability.
3086 GLuint sizeInBytes;
3087 bool result = format.computeCompressedImageSize(levelExtents, &sizeInBytes);
3088 ASSERT(result);
3089
3090 std::vector<uint8_t> newPixelData(sizeInBytes, 0);
3091 auto emplaceResult = foundLevels.emplace(level, std::move(newPixelData));
3092 ASSERT(emplaceResult.second);
3093 foundLevel = emplaceResult.first;
3094 }
3095
3096 // Unpack the various pixel rectangle parameters.
3097 ASSERT(widthParamOffset != -1);
3098 ASSERT(heightParamOffset != -1);
3099 GLsizei pixelWidth =
3100 call.params.getParam("width", ParamType::TGLsizei, widthParamOffset).value.GLsizeiVal;
3101 GLsizei pixelHeight =
3102 call.params.getParam("height", ParamType::TGLsizei, heightParamOffset).value.GLsizeiVal;
3103 GLsizei pixelDepth = 1;
3104 if (depthParamOffset != -1)
3105 {
3106 pixelDepth =
3107 call.params.getParam("depth", ParamType::TGLsizei, depthParamOffset).value.GLsizeiVal;
3108 }
3109
3110 GLint xoffset = 0;
3111 GLint yoffset = 0;
3112 GLint zoffset = 0;
3113
3114 if (xoffsetParamOffset != -1)
3115 {
3116 xoffset =
3117 call.params.getParam("xoffset", ParamType::TGLint, xoffsetParamOffset).value.GLintVal;
3118 }
3119
3120 if (yoffsetParamOffset != -1)
3121 {
3122 yoffset =
3123 call.params.getParam("yoffset", ParamType::TGLint, yoffsetParamOffset).value.GLintVal;
3124 }
3125
3126 if (zoffsetParamOffset != -1)
3127 {
3128 zoffset =
3129 call.params.getParam("zoffset", ParamType::TGLint, zoffsetParamOffset).value.GLintVal;
3130 }
3131
3132 // Since we're dealing in 4x4 blocks, scale down the width/height pixel offsets.
3133 ASSERT(format.compressedBlockWidth == 4);
3134 ASSERT(format.compressedBlockHeight == 4);
3135 ASSERT(format.compressedBlockDepth == 1);
3136 pixelWidth >>= 2;
3137 pixelHeight >>= 2;
3138 xoffset >>= 2;
3139 yoffset >>= 2;
3140
3141 // Update pixel data.
3142 std::vector<uint8_t> &levelData = foundLevel->second;
3143
3144 GLint pixelBytes = static_cast<GLint>(format.pixelBytes);
3145
3146 GLint pixelRowPitch = pixelWidth * pixelBytes;
3147 GLint pixelDepthPitch = pixelRowPitch * pixelHeight;
3148 GLint levelRowPitch = (levelExtents.width >> 2) * pixelBytes;
3149 GLint levelDepthPitch = levelRowPitch * (levelExtents.height >> 2);
3150
3151 for (GLint zindex = 0; zindex < pixelDepth; ++zindex)
3152 {
3153 GLint z = zindex + zoffset;
3154 for (GLint yindex = 0; yindex < pixelHeight; ++yindex)
3155 {
3156 GLint y = yindex + yoffset;
3157 GLint pixelOffset = zindex * pixelDepthPitch + yindex * pixelRowPitch;
3158 GLint levelOffset = z * levelDepthPitch + y * levelRowPitch + xoffset * pixelBytes;
3159 memcpy(&levelData[levelOffset], &pixelData[pixelOffset], pixelRowPitch);
3160 }
3161 }
3162
3163 if (pixelUnpackBuffer)
3164 {
3165 GLboolean success;
3166 (void)pixelUnpackBuffer->unmap(context, &success);
3167 ASSERT(success);
3168 }
3169 }
3170
maybeCaptureClientData(const gl::Context * context,CallCapture & call)3171 void FrameCapture::maybeCaptureClientData(const gl::Context *context, CallCapture &call)
3172 {
3173 switch (call.entryPoint)
3174 {
3175 case gl::EntryPoint::VertexAttribPointer:
3176 {
3177 // Get array location
3178 GLuint index = call.params.getParam("index", ParamType::TGLuint, 0).value.GLuintVal;
3179
3180 if (call.params.hasClientArrayData())
3181 {
3182 mClientVertexArrayMap[index] = static_cast<int>(mFrameCalls.size());
3183 }
3184 else
3185 {
3186 mClientVertexArrayMap[index] = -1;
3187 }
3188 break;
3189 }
3190
3191 case gl::EntryPoint::DeleteBuffers:
3192 {
3193 GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
3194 const gl::BufferID *bufferIDs =
3195 call.params.getParam("buffersPacked", ParamType::TBufferIDConstPointer, 1)
3196 .value.BufferIDConstPointerVal;
3197 for (GLsizei i = 0; i < count; i++)
3198 {
3199 // For each buffer being deleted, check our backup of data and remove it
3200 const auto &bufferDataInfo = mBufferDataMap.find(bufferIDs[i]);
3201 if (bufferDataInfo != mBufferDataMap.end())
3202 {
3203 mBufferDataMap.erase(bufferDataInfo);
3204 }
3205 }
3206 break;
3207 }
3208
3209 case gl::EntryPoint::DrawArrays:
3210 {
3211 if (context->getStateCache().hasAnyActiveClientAttrib())
3212 {
3213 // Get counts from paramBuffer.
3214 GLint firstVertex =
3215 call.params.getParam("first", ParamType::TGLint, 1).value.GLintVal;
3216 GLsizei drawCount =
3217 call.params.getParam("count", ParamType::TGLsizei, 2).value.GLsizeiVal;
3218 captureClientArraySnapshot(context, firstVertex + drawCount, 1);
3219 }
3220 break;
3221 }
3222
3223 case gl::EntryPoint::DrawElements:
3224 {
3225 if (context->getStateCache().hasAnyActiveClientAttrib())
3226 {
3227 GLsizei count =
3228 call.params.getParam("count", ParamType::TGLsizei, 1).value.GLsizeiVal;
3229 gl::DrawElementsType drawElementsType =
3230 call.params.getParam("typePacked", ParamType::TDrawElementsType, 2)
3231 .value.DrawElementsTypeVal;
3232 const void *indices =
3233 call.params.getParam("indices", ParamType::TvoidConstPointer, 3)
3234 .value.voidConstPointerVal;
3235
3236 gl::IndexRange indexRange;
3237
3238 bool restart = context->getState().isPrimitiveRestartEnabled();
3239
3240 gl::Buffer *elementArrayBuffer =
3241 context->getState().getVertexArray()->getElementArrayBuffer();
3242 if (elementArrayBuffer)
3243 {
3244 size_t offset = reinterpret_cast<size_t>(indices);
3245 (void)elementArrayBuffer->getIndexRange(context, drawElementsType, offset,
3246 count, restart, &indexRange);
3247 }
3248 else
3249 {
3250 indexRange = gl::ComputeIndexRange(drawElementsType, indices, count, restart);
3251 }
3252
3253 // index starts from 0
3254 captureClientArraySnapshot(context, indexRange.end + 1, 1);
3255 }
3256 break;
3257 }
3258
3259 case gl::EntryPoint::CompileShader:
3260 {
3261 // Refresh the cached shader sources.
3262 gl::ShaderProgramID shaderID =
3263 call.params.getParam("shaderPacked", ParamType::TShaderProgramID, 0)
3264 .value.ShaderProgramIDVal;
3265 const gl::Shader *shader = context->getShader(shaderID);
3266 mCachedShaderSources[shaderID] = shader->getSourceString();
3267 break;
3268 }
3269
3270 case gl::EntryPoint::LinkProgram:
3271 {
3272 // Refresh the cached program sources.
3273 gl::ShaderProgramID programID =
3274 call.params.getParam("programPacked", ParamType::TShaderProgramID, 0)
3275 .value.ShaderProgramIDVal;
3276 const gl::Program *program = context->getProgramResolveLink(programID);
3277 mCachedProgramSources[programID] = GetAttachedProgramSources(program);
3278 break;
3279 }
3280
3281 case gl::EntryPoint::CompressedTexImage1D:
3282 case gl::EntryPoint::CompressedTexSubImage1D:
3283 {
3284 UNIMPLEMENTED();
3285 break;
3286 }
3287
3288 case gl::EntryPoint::CompressedTexImage2D:
3289 case gl::EntryPoint::CompressedTexImage3D:
3290 case gl::EntryPoint::CompressedTexSubImage2D:
3291 case gl::EntryPoint::CompressedTexSubImage3D:
3292 {
3293 captureCompressedTextureData(context, call);
3294 break;
3295 }
3296
3297 case gl::EntryPoint::DeleteTextures:
3298 {
3299 // Free any TextureLevelDataMap entries being tracked for this texture
3300 // This is to cover the scenario where a texture has been created, its
3301 // levels cached, then texture deleted and recreated, receiving the same ID
3302
3303 // Look up how many textures are being deleted
3304 GLsizei n = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
3305
3306 // Look up the pointer to list of textures
3307 const gl::TextureID *textureIDs =
3308 call.params.getParam("texturesPacked", ParamType::TTextureIDConstPointer, 1)
3309 .value.TextureIDConstPointerVal;
3310
3311 // For each texture listed for deletion
3312 for (int32_t i = 0; i < n; ++i)
3313 {
3314 // Look it up in the cache, and delete it if found
3315 const auto &foundTextureLevels = mCachedTextureLevelData.find(textureIDs[i]);
3316 if (foundTextureLevels != mCachedTextureLevelData.end())
3317 {
3318 // Delete all texture levels at once
3319 mCachedTextureLevelData.erase(foundTextureLevels);
3320 }
3321 }
3322 break;
3323 }
3324
3325 case gl::EntryPoint::MapBuffer:
3326 {
3327 UNIMPLEMENTED();
3328 break;
3329 }
3330 case gl::EntryPoint::MapBufferOES:
3331 {
3332 UNIMPLEMENTED();
3333 break;
3334 }
3335 case gl::EntryPoint::UnmapNamedBuffer:
3336 {
3337 UNIMPLEMENTED();
3338 break;
3339 }
3340
3341 case gl::EntryPoint::MapBufferRange:
3342 case gl::EntryPoint::MapBufferRangeEXT:
3343 {
3344 // Use the access bits to see if contents may be modified
3345 GLbitfield access =
3346 call.params.getParam("access", ParamType::TGLbitfield, 3).value.GLbitfieldVal;
3347
3348 if (access & GL_MAP_WRITE_BIT)
3349 {
3350 // If this buffer was mapped writable, we don't have any visibility into what
3351 // happens to it. Therefore, remember the details about it, and we'll read it back
3352 // on Unmap to repopulate it during replay.
3353
3354 gl::BufferBinding target =
3355 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
3356 .value.BufferBindingVal;
3357 GLintptr offset =
3358 call.params.getParam("offset", ParamType::TGLintptr, 1).value.GLintptrVal;
3359 GLsizeiptr length =
3360 call.params.getParam("length", ParamType::TGLsizeiptr, 2).value.GLsizeiptrVal;
3361
3362 gl::Buffer *buffer = context->getState().getTargetBuffer(target);
3363 mBufferDataMap[buffer->id()] = std::make_pair(offset, length);
3364
3365 // Track the bufferID that was just mapped
3366 call.params.setMappedBufferID(buffer->id());
3367 }
3368 break;
3369 }
3370
3371 case gl::EntryPoint::UnmapBuffer:
3372 case gl::EntryPoint::UnmapBufferOES:
3373 {
3374 // See if we need to capture the buffer contents
3375 captureMappedBufferSnapshot(context, call);
3376 break;
3377 }
3378
3379 default:
3380 break;
3381 }
3382 }
3383
captureCall(const gl::Context * context,CallCapture && call)3384 void FrameCapture::captureCall(const gl::Context *context, CallCapture &&call)
3385 {
3386 // Process client data snapshots.
3387 maybeCaptureClientData(context, call);
3388
3389 mReadBufferSize = std::max(mReadBufferSize, call.params.getReadBufferSize());
3390 mFrameCalls.emplace_back(std::move(call));
3391
3392 maybeCapturePostCallUpdates(context);
3393 }
3394
maybeCapturePostCallUpdates(const gl::Context * context)3395 void FrameCapture::maybeCapturePostCallUpdates(const gl::Context *context)
3396 {
3397 // Process resource ID updates.
3398 MaybeCaptureUpdateResourceIDs(&mFrameCalls);
3399
3400 const CallCapture &lastCall = mFrameCalls.back();
3401 switch (lastCall.entryPoint)
3402 {
3403 case gl::EntryPoint::LinkProgram:
3404 {
3405 const ParamCapture ¶m =
3406 lastCall.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
3407 const gl::Program *program =
3408 context->getProgramResolveLink(param.value.ShaderProgramIDVal);
3409 CaptureUpdateUniformLocations(program, &mFrameCalls);
3410 break;
3411 }
3412 case gl::EntryPoint::UseProgram:
3413 CaptureUpdateCurrentProgram(lastCall, &mFrameCalls);
3414 break;
3415 case gl::EntryPoint::DeleteProgram:
3416 {
3417 const ParamCapture ¶m =
3418 lastCall.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
3419 CaptureDeleteUniformLocations(param.value.ShaderProgramIDVal, &mFrameCalls);
3420 break;
3421 }
3422 case gl::EntryPoint::BindFramebuffer:
3423 {
3424 const ParamCapture &target = lastCall.params.getParam("target", ParamType::TGLenum, 0);
3425 const ParamCapture &framebuffer =
3426 lastCall.params.getParam("framebufferPacked", ParamType::TFramebufferID, 1);
3427 CaptureOnFramebufferChange(target.value.GLenumVal, framebuffer.value.FramebufferIDVal,
3428 &mFrameCalls);
3429 break;
3430 }
3431 default:
3432 break;
3433 }
3434 }
3435
captureClientArraySnapshot(const gl::Context * context,size_t vertexCount,size_t instanceCount)3436 void FrameCapture::captureClientArraySnapshot(const gl::Context *context,
3437 size_t vertexCount,
3438 size_t instanceCount)
3439 {
3440 const gl::VertexArray *vao = context->getState().getVertexArray();
3441
3442 // Capture client array data.
3443 for (size_t attribIndex : context->getStateCache().getActiveClientAttribsMask())
3444 {
3445 const gl::VertexAttribute &attrib = vao->getVertexAttribute(attribIndex);
3446 const gl::VertexBinding &binding = vao->getVertexBinding(attrib.bindingIndex);
3447
3448 int callIndex = mClientVertexArrayMap[attribIndex];
3449
3450 if (callIndex != -1)
3451 {
3452 size_t count = vertexCount;
3453
3454 if (binding.getDivisor() > 0)
3455 {
3456 count = rx::UnsignedCeilDivide(static_cast<uint32_t>(instanceCount),
3457 binding.getDivisor());
3458 }
3459
3460 // The last capture element doesn't take up the full stride.
3461 size_t bytesToCapture = (count - 1) * binding.getStride() + attrib.format->pixelBytes;
3462
3463 CallCapture &call = mFrameCalls[callIndex];
3464 ParamCapture ¶m = call.params.getClientArrayPointerParameter();
3465 ASSERT(param.type == ParamType::TvoidConstPointer);
3466
3467 ParamBuffer updateParamBuffer;
3468 updateParamBuffer.addValueParam<GLint>("arrayIndex", ParamType::TGLint,
3469 static_cast<uint32_t>(attribIndex));
3470
3471 ParamCapture updateMemory("pointer", ParamType::TvoidConstPointer);
3472 CaptureMemory(param.value.voidConstPointerVal, bytesToCapture, &updateMemory);
3473 updateParamBuffer.addParam(std::move(updateMemory));
3474
3475 updateParamBuffer.addValueParam<GLuint64>("size", ParamType::TGLuint64, bytesToCapture);
3476
3477 mFrameCalls.emplace_back("UpdateClientArrayPointer", std::move(updateParamBuffer));
3478
3479 mClientArraySizes[attribIndex] =
3480 std::max(mClientArraySizes[attribIndex], bytesToCapture);
3481 }
3482 }
3483 }
3484
captureMappedBufferSnapshot(const gl::Context * context,const CallCapture & call)3485 void FrameCapture::captureMappedBufferSnapshot(const gl::Context *context, const CallCapture &call)
3486 {
3487 // If the buffer was mapped writable, we need to restore its data, since we have no visibility
3488 // into what the client did to the buffer while mapped
3489 // This sequence will result in replay calls like this:
3490 // ...
3491 // gMappedBufferData[gBufferMap[42]] = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, 65536,
3492 // GL_MAP_WRITE_BIT);
3493 // ...
3494 // UpdateClientBufferData(42, &gBinaryData[164631024], 65536);
3495 // glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
3496 // ...
3497
3498 // Re-map the buffer, using the info we tracked about the buffer
3499 gl::BufferBinding target =
3500 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0).value.BufferBindingVal;
3501
3502 gl::Buffer *buffer = context->getState().getTargetBuffer(target);
3503 const auto &bufferDataInfo = mBufferDataMap.find(buffer->id());
3504 if (bufferDataInfo == mBufferDataMap.end())
3505 {
3506 // This buffer was not marked writable, so we did not back it up
3507 return;
3508 }
3509
3510 GLintptr offset = bufferDataInfo->second.first;
3511 GLsizeiptr length = bufferDataInfo->second.second;
3512
3513 // Map the buffer so we can copy its contents out
3514 ASSERT(!buffer->isMapped());
3515 angle::Result result = buffer->mapRange(context, offset, length, GL_MAP_READ_BIT);
3516 if (result != angle::Result::Continue)
3517 {
3518 ERR() << "Failed to mapRange of buffer" << std::endl;
3519 }
3520 const uint8_t *data = reinterpret_cast<const uint8_t *>(buffer->getMapPointer());
3521
3522 // Create the parameters to our helper for use during replay
3523 ParamBuffer dataParamBuffer;
3524
3525 // Pass in the target buffer ID
3526 dataParamBuffer.addValueParam("dest", ParamType::TGLuint, buffer->id().value);
3527
3528 // Capture the current buffer data with a binary param
3529 ParamCapture captureData("source", ParamType::TvoidConstPointer);
3530 CaptureMemory(data, length, &captureData);
3531 dataParamBuffer.addParam(std::move(captureData));
3532
3533 // Also track its size for use with memcpy
3534 dataParamBuffer.addValueParam<GLsizeiptr>("size", ParamType::TGLsizeiptr, length);
3535
3536 // Call the helper that populates the buffer with captured data
3537 mFrameCalls.emplace_back("UpdateClientBufferData", std::move(dataParamBuffer));
3538
3539 // Unmap the buffer and move on
3540 GLboolean dontCare;
3541 (void)buffer->unmap(context, &dontCare);
3542 }
3543
onEndFrame(const gl::Context * context)3544 void FrameCapture::onEndFrame(const gl::Context *context)
3545 {
3546 // Note that we currently capture before the start frame to collect shader and program sources.
3547 if (!mFrameCalls.empty() && mFrameIndex >= mFrameStart)
3548 {
3549 WriteCppReplay(mCompression, mOutDirectory, context->id(), mCaptureLabel, mFrameIndex,
3550 mFrameCalls, mSetupCalls, &mBinaryData);
3551
3552 // Save the index files after the last frame.
3553 if (mFrameIndex == mFrameEnd)
3554 {
3555 WriteCppReplayIndexFiles(mCompression, mOutDirectory, context->id(), mCaptureLabel,
3556 mFrameStart, mFrameEnd, mReadBufferSize, mClientArraySizes,
3557 mHasResourceType);
3558
3559 if (!mBinaryData.empty())
3560 {
3561 SaveBinaryData(mCompression, mOutDirectory, context->id(), mCaptureLabel,
3562 mBinaryData);
3563 mBinaryData.clear();
3564 }
3565 }
3566 }
3567
3568 // Count resource IDs. This is also done on every frame. It could probably be done by checking
3569 // the GL state instead of the calls.
3570 for (const CallCapture &call : mFrameCalls)
3571 {
3572 for (const ParamCapture ¶m : call.params.getParamCaptures())
3573 {
3574 ResourceIDType idType = GetResourceIDTypeFromParamType(param.type);
3575 if (idType != ResourceIDType::InvalidEnum)
3576 {
3577 mHasResourceType.set(idType);
3578 }
3579 }
3580 }
3581
3582 reset();
3583 mFrameIndex++;
3584
3585 if (enabled() && mFrameIndex == mFrameStart)
3586 {
3587 mSetupCalls.clear();
3588 CaptureMidExecutionSetup(context, &mSetupCalls, mCachedShaderSources, mCachedProgramSources,
3589 mCachedTextureLevelData);
3590 }
3591 }
3592
3593 DataCounters::DataCounters() = default;
3594
3595 DataCounters::~DataCounters() = default;
3596
getAndIncrement(gl::EntryPoint entryPoint,const std::string & paramName)3597 int DataCounters::getAndIncrement(gl::EntryPoint entryPoint, const std::string ¶mName)
3598 {
3599 Counter counterKey = {entryPoint, paramName};
3600 return mData[counterKey]++;
3601 }
3602
isCapturing() const3603 bool FrameCapture::isCapturing() const
3604 {
3605 // Currently we will always do a capture up until the last frame. In the future we could improve
3606 // mid execution capture by only capturing between the start and end frames. The only necessary
3607 // reason we need to capture before the start is for attached program and shader sources.
3608 return mEnabled && mFrameIndex <= mFrameEnd;
3609 }
3610
replay(gl::Context * context)3611 void FrameCapture::replay(gl::Context *context)
3612 {
3613 ReplayContext replayContext(mReadBufferSize, mClientArraySizes);
3614 for (const CallCapture &call : mFrameCalls)
3615 {
3616 INFO() << "frame index: " << mFrameIndex << " " << call.name();
3617
3618 if (call.entryPoint == gl::EntryPoint::Invalid)
3619 {
3620 if (call.customFunctionName == "UpdateClientArrayPointer")
3621 {
3622 GLint arrayIndex =
3623 call.params.getParam("arrayIndex", ParamType::TGLint, 0).value.GLintVal;
3624 ASSERT(arrayIndex < gl::MAX_VERTEX_ATTRIBS);
3625
3626 const ParamCapture &pointerParam =
3627 call.params.getParam("pointer", ParamType::TvoidConstPointer, 1);
3628 ASSERT(pointerParam.data.size() == 1);
3629 const void *pointer = pointerParam.data[0].data();
3630
3631 size_t size = static_cast<size_t>(
3632 call.params.getParam("size", ParamType::TGLuint64, 2).value.GLuint64Val);
3633
3634 std::vector<uint8_t> &curClientArrayBuffer =
3635 replayContext.getClientArraysBuffer()[arrayIndex];
3636 ASSERT(curClientArrayBuffer.size() >= size);
3637 memcpy(curClientArrayBuffer.data(), pointer, size);
3638 }
3639 continue;
3640 }
3641
3642 ReplayCall(context, &replayContext, call);
3643 }
3644 }
3645
reset()3646 void FrameCapture::reset()
3647 {
3648 mFrameCalls.clear();
3649 mSetupCalls.clear();
3650 mClientVertexArrayMap.fill(-1);
3651
3652 // Do not reset replay-specific settings like the maximum read buffer size, client array sizes,
3653 // or the 'has seen' type map. We could refine this into per-frame and per-capture maximums if
3654 // necessary.
3655 }
3656
CaptureMemory(const void * source,size_t size,ParamCapture * paramCapture)3657 void CaptureMemory(const void *source, size_t size, ParamCapture *paramCapture)
3658 {
3659 std::vector<uint8_t> data(size);
3660 memcpy(data.data(), source, size);
3661 paramCapture->data.emplace_back(std::move(data));
3662 }
3663
CaptureString(const GLchar * str,ParamCapture * paramCapture)3664 void CaptureString(const GLchar *str, ParamCapture *paramCapture)
3665 {
3666 // include the '\0' suffix
3667 CaptureMemory(str, strlen(str) + 1, paramCapture);
3668 }
3669
CaptureStringLimit(const GLchar * str,uint32_t limit,ParamCapture * paramCapture)3670 void CaptureStringLimit(const GLchar *str, uint32_t limit, ParamCapture *paramCapture)
3671 {
3672 // Write the incoming string up to limit, including null terminator
3673 size_t length = strlen(str) + 1;
3674
3675 if (length > limit)
3676 {
3677 // If too many characters, resize the string to fit in the limit
3678 std::string newStr = str;
3679 newStr.resize(limit - 1);
3680 CaptureString(newStr.c_str(), paramCapture);
3681 }
3682 else
3683 {
3684 CaptureMemory(str, length, paramCapture);
3685 }
3686 }
3687
GetLinkedProgramForCapture(const gl::State & glState,gl::ShaderProgramID handle)3688 gl::Program *GetLinkedProgramForCapture(const gl::State &glState, gl::ShaderProgramID handle)
3689 {
3690 gl::Program *program = glState.getShaderProgramManagerForCapture().getProgram(handle);
3691 ASSERT(program->isLinked());
3692 return program;
3693 }
3694
CaptureGetParameter(const gl::State & glState,GLenum pname,size_t typeSize,ParamCapture * paramCapture)3695 void CaptureGetParameter(const gl::State &glState,
3696 GLenum pname,
3697 size_t typeSize,
3698 ParamCapture *paramCapture)
3699 {
3700 GLenum nativeType;
3701 unsigned int numParams;
3702 if (!gl::GetQueryParameterInfo(glState, pname, &nativeType, &numParams))
3703 {
3704 numParams = 1;
3705 }
3706
3707 paramCapture->readBufferSizeBytes = typeSize * numParams;
3708 }
3709
CaptureGenHandlesImpl(GLsizei n,GLuint * handles,ParamCapture * paramCapture)3710 void CaptureGenHandlesImpl(GLsizei n, GLuint *handles, ParamCapture *paramCapture)
3711 {
3712 paramCapture->readBufferSizeBytes = sizeof(GLuint) * n;
3713 CaptureMemory(handles, paramCapture->readBufferSizeBytes, paramCapture);
3714 }
3715
3716 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLboolean value)3717 void WriteParamValueReplay<ParamType::TGLboolean>(std::ostream &os,
3718 const CallCapture &call,
3719 GLboolean value)
3720 {
3721 switch (value)
3722 {
3723 case GL_TRUE:
3724 os << "GL_TRUE";
3725 break;
3726 case GL_FALSE:
3727 os << "GL_FALSE";
3728 break;
3729 default:
3730 os << "GL_INVALID_ENUM";
3731 }
3732 }
3733
3734 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,const void * value)3735 void WriteParamValueReplay<ParamType::TvoidConstPointer>(std::ostream &os,
3736 const CallCapture &call,
3737 const void *value)
3738 {
3739 if (value == 0)
3740 {
3741 os << "nullptr";
3742 }
3743 else
3744 {
3745 os << "reinterpret_cast<const void *>("
3746 << static_cast<int>(reinterpret_cast<uintptr_t>(value)) << ")";
3747 }
3748 }
3749
3750 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLDEBUGPROCKHR value)3751 void WriteParamValueReplay<ParamType::TGLDEBUGPROCKHR>(std::ostream &os,
3752 const CallCapture &call,
3753 GLDEBUGPROCKHR value)
3754 {}
3755
3756 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLDEBUGPROC value)3757 void WriteParamValueReplay<ParamType::TGLDEBUGPROC>(std::ostream &os,
3758 const CallCapture &call,
3759 GLDEBUGPROC value)
3760 {}
3761
3762 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::BufferID value)3763 void WriteParamValueReplay<ParamType::TBufferID>(std::ostream &os,
3764 const CallCapture &call,
3765 gl::BufferID value)
3766 {
3767 os << "gBufferMap[" << value.value << "]";
3768 }
3769
3770 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::FenceNVID value)3771 void WriteParamValueReplay<ParamType::TFenceNVID>(std::ostream &os,
3772 const CallCapture &call,
3773 gl::FenceNVID value)
3774 {
3775 os << "gFenceMap[" << value.value << "]";
3776 }
3777
3778 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::FramebufferID value)3779 void WriteParamValueReplay<ParamType::TFramebufferID>(std::ostream &os,
3780 const CallCapture &call,
3781 gl::FramebufferID value)
3782 {
3783 os << "gFramebufferMap[" << value.value << "]";
3784 }
3785
3786 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::MemoryObjectID value)3787 void WriteParamValueReplay<ParamType::TMemoryObjectID>(std::ostream &os,
3788 const CallCapture &call,
3789 gl::MemoryObjectID value)
3790 {
3791 os << "gMemoryObjectMap[" << value.value << "]";
3792 }
3793
3794 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::ProgramPipelineID value)3795 void WriteParamValueReplay<ParamType::TProgramPipelineID>(std::ostream &os,
3796 const CallCapture &call,
3797 gl::ProgramPipelineID value)
3798 {
3799 os << "gProgramPipelineMap[" << value.value << "]";
3800 }
3801
3802 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::QueryID value)3803 void WriteParamValueReplay<ParamType::TQueryID>(std::ostream &os,
3804 const CallCapture &call,
3805 gl::QueryID value)
3806 {
3807 os << "gQueryMap[" << value.value << "]";
3808 }
3809
3810 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::RenderbufferID value)3811 void WriteParamValueReplay<ParamType::TRenderbufferID>(std::ostream &os,
3812 const CallCapture &call,
3813 gl::RenderbufferID value)
3814 {
3815 os << "gRenderbufferMap[" << value.value << "]";
3816 }
3817
3818 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::SamplerID value)3819 void WriteParamValueReplay<ParamType::TSamplerID>(std::ostream &os,
3820 const CallCapture &call,
3821 gl::SamplerID value)
3822 {
3823 os << "gSamplerMap[" << value.value << "]";
3824 }
3825
3826 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::SemaphoreID value)3827 void WriteParamValueReplay<ParamType::TSemaphoreID>(std::ostream &os,
3828 const CallCapture &call,
3829 gl::SemaphoreID value)
3830 {
3831 os << "gSempahoreMap[" << value.value << "]";
3832 }
3833
3834 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::ShaderProgramID value)3835 void WriteParamValueReplay<ParamType::TShaderProgramID>(std::ostream &os,
3836 const CallCapture &call,
3837 gl::ShaderProgramID value)
3838 {
3839 os << "gShaderProgramMap[" << value.value << "]";
3840 }
3841
3842 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLsync value)3843 void WriteParamValueReplay<ParamType::TGLsync>(std::ostream &os,
3844 const CallCapture &call,
3845 GLsync value)
3846 {
3847 os << "gSyncMap[" << SyncIndexValue(value) << "]";
3848 }
3849
3850 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::TextureID value)3851 void WriteParamValueReplay<ParamType::TTextureID>(std::ostream &os,
3852 const CallCapture &call,
3853 gl::TextureID value)
3854 {
3855 os << "gTextureMap[" << value.value << "]";
3856 }
3857
3858 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::TransformFeedbackID value)3859 void WriteParamValueReplay<ParamType::TTransformFeedbackID>(std::ostream &os,
3860 const CallCapture &call,
3861 gl::TransformFeedbackID value)
3862 {
3863 os << "gTransformFeedbackMap[" << value.value << "]";
3864 }
3865
3866 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::VertexArrayID value)3867 void WriteParamValueReplay<ParamType::TVertexArrayID>(std::ostream &os,
3868 const CallCapture &call,
3869 gl::VertexArrayID value)
3870 {
3871 os << "gVertexArrayMap[" << value.value << "]";
3872 }
3873
FindShaderProgramIDInCall(const CallCapture & call,gl::ShaderProgramID * idOut)3874 bool FindShaderProgramIDInCall(const CallCapture &call, gl::ShaderProgramID *idOut)
3875 {
3876 for (const ParamCapture ¶m : call.params.getParamCaptures())
3877 {
3878 if (param.type == ParamType::TShaderProgramID && param.name == "programPacked")
3879 {
3880 *idOut = param.value.ShaderProgramIDVal;
3881 return true;
3882 }
3883 }
3884
3885 return false;
3886 }
3887
3888 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::UniformLocation value)3889 void WriteParamValueReplay<ParamType::TUniformLocation>(std::ostream &os,
3890 const CallCapture &call,
3891 gl::UniformLocation value)
3892 {
3893 if (value.value == -1)
3894 {
3895 os << "-1";
3896 return;
3897 }
3898
3899 os << "gUniformLocations[";
3900
3901 // Find the program from the call parameters.
3902 gl::ShaderProgramID programID;
3903 if (FindShaderProgramIDInCall(call, &programID))
3904 {
3905 os << "gShaderProgramMap[" << programID.value << "]";
3906 }
3907 else
3908 {
3909 os << "gCurrentProgram";
3910 }
3911
3912 os << "][" << value.value << "]";
3913 }
3914 } // namespace angle
3915