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/capture/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/angle_version.h"
20 #include "common/mathutil.h"
21 #include "common/string_utils.h"
22 #include "common/system_utils.h"
23 #include "libANGLE/Config.h"
24 #include "libANGLE/Context.h"
25 #include "libANGLE/Display.h"
26 #include "libANGLE/Fence.h"
27 #include "libANGLE/Framebuffer.h"
28 #include "libANGLE/GLES1Renderer.h"
29 #include "libANGLE/Query.h"
30 #include "libANGLE/ResourceMap.h"
31 #include "libANGLE/Shader.h"
32 #include "libANGLE/Surface.h"
33 #include "libANGLE/VertexArray.h"
34 #include "libANGLE/capture/capture_gles_1_0_autogen.h"
35 #include "libANGLE/capture/capture_gles_2_0_autogen.h"
36 #include "libANGLE/capture/capture_gles_3_0_autogen.h"
37 #include "libANGLE/capture/capture_gles_3_1_autogen.h"
38 #include "libANGLE/capture/capture_gles_3_2_autogen.h"
39 #include "libANGLE/capture/capture_gles_ext_autogen.h"
40 #include "libANGLE/capture/frame_capture_utils.h"
41 #include "libANGLE/capture/gl_enum_utils.h"
42 #include "libANGLE/queryconversions.h"
43 #include "libANGLE/queryutils.h"
44
45 #define USE_SYSTEM_ZLIB
46 #include "compression_utils_portable.h"
47
48 #if !ANGLE_CAPTURE_ENABLED
49 # error Frame capture must be enabled to include this file.
50 #endif // !ANGLE_CAPTURE_ENABLED
51
52 namespace angle
53 {
54 namespace
55 {
56
57 constexpr char kEnabledVarName[] = "ANGLE_CAPTURE_ENABLED";
58 constexpr char kOutDirectoryVarName[] = "ANGLE_CAPTURE_OUT_DIR";
59 constexpr char kFrameStartVarName[] = "ANGLE_CAPTURE_FRAME_START";
60 constexpr char kFrameEndVarName[] = "ANGLE_CAPTURE_FRAME_END";
61 constexpr char kCaptureTriggerVarName[] = "ANGLE_CAPTURE_TRIGGER";
62 constexpr char kCaptureLabel[] = "ANGLE_CAPTURE_LABEL";
63 constexpr char kCompression[] = "ANGLE_CAPTURE_COMPRESSION";
64 constexpr char kSerializeStateEnabledVarName[] = "ANGLE_CAPTURE_SERIALIZE_STATE";
65
66 constexpr size_t kBinaryAlignment = 16;
67 constexpr size_t kFunctionSizeLimit = 5000;
68
69 // Limit based on MSVC Compiler Error C2026
70 constexpr size_t kStringLengthLimit = 16380;
71
72 // Android debug properties that correspond to the above environment variables
73 constexpr char kAndroidCaptureEnabled[] = "debug.angle.capture.enabled";
74 constexpr char kAndroidOutDir[] = "debug.angle.capture.out_dir";
75 constexpr char kAndroidFrameStart[] = "debug.angle.capture.frame_start";
76 constexpr char kAndroidFrameEnd[] = "debug.angle.capture.frame_end";
77 constexpr char kAndroidCaptureTrigger[] = "debug.angle.capture.trigger";
78 constexpr char kAndroidCaptureLabel[] = "debug.angle.capture.label";
79 constexpr char kAndroidCompression[] = "debug.angle.capture.compression";
80
GetDefaultOutDirectory()81 std::string GetDefaultOutDirectory()
82 {
83 #if defined(ANGLE_PLATFORM_ANDROID)
84 std::string path = "/sdcard/Android/data/";
85
86 // Linux interface to get application id of the running process
87 FILE *cmdline = fopen("/proc/self/cmdline", "r");
88 char applicationId[512];
89 if (cmdline)
90 {
91 fread(applicationId, 1, sizeof(applicationId), cmdline);
92 fclose(cmdline);
93
94 // Some package may have application id as <app_name>:<cmd_name>
95 char *colonSep = strchr(applicationId, ':');
96 if (colonSep)
97 {
98 *colonSep = '\0';
99 }
100 }
101 else
102 {
103 ERR() << "not able to lookup application id";
104 }
105
106 constexpr char kAndroidOutputSubdir[] = "/angle_capture/";
107 path += std::string(applicationId) + kAndroidOutputSubdir;
108
109 // Check for existance of output path
110 struct stat dir_stat;
111 if (stat(path.c_str(), &dir_stat) == -1)
112 {
113 ERR() << "Output directory '" << path
114 << "' does not exist. Create it over adb using mkdir.";
115 }
116
117 return path;
118 #else
119 return std::string("./");
120 #endif // defined(ANGLE_PLATFORM_ANDROID)
121 }
122
GetCaptureTrigger()123 std::string GetCaptureTrigger()
124 {
125 return GetEnvironmentVarOrUnCachedAndroidProperty(kCaptureTriggerVarName,
126 kAndroidCaptureTrigger);
127 }
128
operator <<(std::ostream & os,gl::ContextID contextId)129 std::ostream &operator<<(std::ostream &os, gl::ContextID contextId)
130 {
131 os << static_cast<int>(contextId.value);
132 return os;
133 }
134
135 constexpr static gl::ContextID kSharedContextId = {0};
136
137 struct FmtCapturePrefix
138 {
FmtCapturePrefixangle::__anond94d34250111::FmtCapturePrefix139 FmtCapturePrefix(gl::ContextID contextIdIn, const std::string &captureLabelIn)
140 : contextId(contextIdIn), captureLabel(captureLabelIn)
141 {}
142 gl::ContextID contextId;
143 const std::string &captureLabel;
144 };
145
operator <<(std::ostream & os,const FmtCapturePrefix & fmt)146 std::ostream &operator<<(std::ostream &os, const FmtCapturePrefix &fmt)
147 {
148 if (fmt.captureLabel.empty())
149 {
150 os << "angle";
151 }
152 else
153 {
154 os << fmt.captureLabel;
155 }
156
157 if (fmt.contextId != kSharedContextId)
158 {
159 os << "_capture_context" << fmt.contextId;
160 }
161
162 return os;
163 }
164
165 enum class ReplayFunc
166 {
167 Replay,
168 Setup,
169 Reset,
170 };
171
172 constexpr uint32_t kNoPartId = std::numeric_limits<uint32_t>::max();
173
174 struct FmtReplayFunction
175 {
FmtReplayFunctionangle::__anond94d34250111::FmtReplayFunction176 FmtReplayFunction(gl::ContextID contextIdIn,
177 uint32_t frameIndexIn,
178 uint32_t partIdIn = kNoPartId)
179 : contextId(contextIdIn), frameIndex(frameIndexIn), partId(partIdIn)
180 {}
181 gl::ContextID contextId;
182 uint32_t frameIndex;
183 uint32_t partId;
184 };
185
operator <<(std::ostream & os,const FmtReplayFunction & fmt)186 std::ostream &operator<<(std::ostream &os, const FmtReplayFunction &fmt)
187 {
188 os << "ReplayContext";
189
190 if (fmt.contextId == kSharedContextId)
191 {
192 os << "Shared";
193 }
194 else
195 {
196 os << fmt.contextId;
197 }
198
199 os << "Frame" << fmt.frameIndex;
200
201 if (fmt.partId != kNoPartId)
202 {
203 os << "Part" << fmt.partId;
204 }
205 os << "()";
206 return os;
207 }
208
209 struct FmtSetupFunction
210 {
FmtSetupFunctionangle::__anond94d34250111::FmtSetupFunction211 FmtSetupFunction(uint32_t partIdIn, gl::ContextID contextIdIn)
212 : partId(partIdIn), contextId(contextIdIn)
213 {}
214
215 uint32_t partId;
216 gl::ContextID contextId;
217 };
218
operator <<(std::ostream & os,const FmtSetupFunction & fmt)219 std::ostream &operator<<(std::ostream &os, const FmtSetupFunction &fmt)
220 {
221 os << "SetupReplayContext";
222
223 if (fmt.contextId == kSharedContextId)
224 {
225 os << "Shared";
226 }
227 else
228 {
229 os << fmt.contextId;
230 }
231
232 if (fmt.partId != kNoPartId)
233 {
234 os << "Part" << fmt.partId;
235 }
236 os << "()";
237 return os;
238 }
239
240 struct FmtResetFunction
241 {
FmtResetFunctionangle::__anond94d34250111::FmtResetFunction242 FmtResetFunction() {}
243 };
244
operator <<(std::ostream & os,const FmtResetFunction & fmt)245 std::ostream &operator<<(std::ostream &os, const FmtResetFunction &fmt)
246 {
247 os << "ResetReplay()";
248 return os;
249 }
250
251 struct FmtFunction
252 {
FmtFunctionangle::__anond94d34250111::FmtFunction253 FmtFunction(ReplayFunc funcTypeIn,
254 gl::ContextID contextIdIn,
255 uint32_t frameIndexIn,
256 uint32_t partIdIn)
257 : funcType(funcTypeIn), contextId(contextIdIn), frameIndex(frameIndexIn), partId(partIdIn)
258 {}
259
260 ReplayFunc funcType;
261 gl::ContextID contextId;
262 uint32_t frameIndex;
263 uint32_t partId;
264 };
265
operator <<(std::ostream & os,const FmtFunction & fmt)266 std::ostream &operator<<(std::ostream &os, const FmtFunction &fmt)
267 {
268 switch (fmt.funcType)
269 {
270 case ReplayFunc::Replay:
271 os << FmtReplayFunction(fmt.contextId, fmt.frameIndex, fmt.partId);
272 break;
273
274 case ReplayFunc::Setup:
275 os << FmtSetupFunction(fmt.partId, fmt.contextId);
276 break;
277
278 case ReplayFunc::Reset:
279 os << FmtResetFunction();
280 break;
281
282 default:
283 UNREACHABLE();
284 break;
285 }
286
287 return os;
288 }
289
290 struct FmtGetSerializedContextStateFunction
291 {
FmtGetSerializedContextStateFunctionangle::__anond94d34250111::FmtGetSerializedContextStateFunction292 FmtGetSerializedContextStateFunction(gl::ContextID contextIdIn, uint32_t frameIndexIn)
293 : contextId(contextIdIn), frameIndex(frameIndexIn)
294 {}
295 gl::ContextID contextId;
296 uint32_t frameIndex;
297 };
298
operator <<(std::ostream & os,const FmtGetSerializedContextStateFunction & fmt)299 std::ostream &operator<<(std::ostream &os, const FmtGetSerializedContextStateFunction &fmt)
300 {
301 os << "GetSerializedContext" << fmt.contextId << "StateFrame" << fmt.frameIndex << "Data()";
302 return os;
303 }
304
GetCaptureFileName(gl::ContextID contextId,const std::string & captureLabel,uint32_t frameIndex,const char * suffix)305 std::string GetCaptureFileName(gl::ContextID contextId,
306 const std::string &captureLabel,
307 uint32_t frameIndex,
308 const char *suffix)
309 {
310 std::stringstream fnameStream;
311 fnameStream << FmtCapturePrefix(contextId, captureLabel) << "_frame" << std::setfill('0')
312 << std::setw(3) << frameIndex << suffix;
313 return fnameStream.str();
314 }
315
GetCaptureFilePath(const std::string & outDir,gl::ContextID contextId,const std::string & captureLabel,uint32_t frameIndex,const char * suffix)316 std::string GetCaptureFilePath(const std::string &outDir,
317 gl::ContextID contextId,
318 const std::string &captureLabel,
319 uint32_t frameIndex,
320 const char *suffix)
321 {
322 return outDir + GetCaptureFileName(contextId, captureLabel, frameIndex, suffix);
323 }
324
WriteParamStaticVarName(const CallCapture & call,const ParamCapture & param,int counter,std::ostream & out)325 void WriteParamStaticVarName(const CallCapture &call,
326 const ParamCapture ¶m,
327 int counter,
328 std::ostream &out)
329 {
330 out << call.name() << "_" << param.name << "_" << counter;
331 }
332
WriteGLFloatValue(std::ostream & out,GLfloat value)333 void WriteGLFloatValue(std::ostream &out, GLfloat value)
334 {
335 // Check for non-representable values
336 ASSERT(std::numeric_limits<float>::has_infinity);
337 ASSERT(std::numeric_limits<float>::has_quiet_NaN);
338
339 if (std::isinf(value))
340 {
341 float negativeInf = -std::numeric_limits<float>::infinity();
342 if (value == negativeInf)
343 {
344 out << "-";
345 }
346 out << "std::numeric_limits<float>::infinity()";
347 }
348 else if (std::isnan(value))
349 {
350 out << "std::numeric_limits<float>::quiet_NaN()";
351 }
352 else
353 {
354 out << std::setprecision(16);
355 out << value;
356 }
357 }
358
359 template <typename T, typename CastT = T>
WriteInlineData(const std::vector<uint8_t> & vec,std::ostream & out)360 void WriteInlineData(const std::vector<uint8_t> &vec, std::ostream &out)
361 {
362 const T *data = reinterpret_cast<const T *>(vec.data());
363 size_t count = vec.size() / sizeof(T);
364
365 if (data == nullptr)
366 {
367 return;
368 }
369
370 out << static_cast<CastT>(data[0]);
371
372 for (size_t dataIndex = 1; dataIndex < count; ++dataIndex)
373 {
374 out << ", " << static_cast<CastT>(data[dataIndex]);
375 }
376 }
377
378 template <>
WriteInlineData(const std::vector<uint8_t> & vec,std::ostream & out)379 void WriteInlineData<GLchar>(const std::vector<uint8_t> &vec, std::ostream &out)
380 {
381 const GLchar *data = reinterpret_cast<const GLchar *>(vec.data());
382 size_t count = vec.size() / sizeof(GLchar);
383
384 if (data == nullptr || data[0] == '\0')
385 {
386 return;
387 }
388
389 out << "\"";
390
391 for (size_t dataIndex = 0; dataIndex < count; ++dataIndex)
392 {
393 if (data[dataIndex] == '\0')
394 break;
395
396 out << static_cast<GLchar>(data[dataIndex]);
397 }
398
399 out << "\"";
400 }
401
WriteStringParamReplay(std::ostream & out,const ParamCapture & param)402 void WriteStringParamReplay(std::ostream &out, const ParamCapture ¶m)
403 {
404 const std::vector<uint8_t> &data = param.data[0];
405 // null terminate C style string
406 ASSERT(data.size() > 0 && data.back() == '\0');
407 std::string str(data.begin(), data.end() - 1);
408 out << "\"" << str << "\"";
409 }
410
WriteStringPointerParamReplay(DataTracker * dataTracker,std::ostream & out,std::ostream & header,const CallCapture & call,const ParamCapture & param)411 void WriteStringPointerParamReplay(DataTracker *dataTracker,
412 std::ostream &out,
413 std::ostream &header,
414 const CallCapture &call,
415 const ParamCapture ¶m)
416 {
417 // Concatenate the strings to ensure we get an accurate counter
418 std::vector<std::string> strings;
419 for (const std::vector<uint8_t> &data : param.data)
420 {
421 // null terminate C style string
422 ASSERT(data.size() > 0 && data.back() == '\0');
423 strings.emplace_back(data.begin(), data.end() - 1);
424 }
425
426 int counter = dataTracker->getStringCounters().getStringCounter(strings);
427 if (counter == kStringsNotFound)
428 {
429 // This is a unique set of strings, so set up their declaration and update the counter
430 counter = dataTracker->getCounters().getAndIncrement(call.entryPoint, param.name);
431 dataTracker->getStringCounters().setStringCounter(strings, counter);
432
433 header << "const char* const ";
434 WriteParamStaticVarName(call, param, counter, header);
435 header << "[] = { \n";
436
437 for (const std::string &str : strings)
438 {
439 // Break up long strings for MSVC
440 size_t copyLength = 0;
441 std::string separator;
442 for (size_t i = 0; i < str.length(); i += kStringLengthLimit)
443 {
444 if ((str.length() - i) <= kStringLengthLimit)
445 {
446 copyLength = str.length() - i;
447 separator = ",";
448 }
449 else
450 {
451 copyLength = kStringLengthLimit;
452 separator = "";
453 }
454
455 header << " R\"(" << str.substr(i, copyLength) << ")\"" << separator << "\n";
456 }
457 }
458
459 header << " };\n";
460 }
461
462 ASSERT(counter >= 0);
463 WriteParamStaticVarName(call, param, counter, out);
464 }
465
466 template <typename ParamT>
WriteResourceIDPointerParamReplay(DataTracker * dataTracker,std::ostream & out,std::ostream & header,const CallCapture & call,const ParamCapture & param)467 void WriteResourceIDPointerParamReplay(DataTracker *dataTracker,
468 std::ostream &out,
469 std::ostream &header,
470 const CallCapture &call,
471 const ParamCapture ¶m)
472 {
473 int counter = dataTracker->getCounters().getAndIncrement(call.entryPoint, param.name);
474
475 header << "const GLuint ";
476 WriteParamStaticVarName(call, param, counter, header);
477 header << "[] = { ";
478
479 const ResourceIDType resourceIDType = GetResourceIDTypeFromParamType(param.type);
480 ASSERT(resourceIDType != ResourceIDType::InvalidEnum);
481 const char *name = GetResourceIDTypeName(resourceIDType);
482
483 ASSERT(param.dataNElements > 0);
484 ASSERT(param.data.size() == 1);
485
486 const ParamT *returnedIDs = reinterpret_cast<const ParamT *>(param.data[0].data());
487 for (GLsizei resIndex = 0; resIndex < param.dataNElements; ++resIndex)
488 {
489 ParamT id = returnedIDs[resIndex];
490 if (resIndex > 0)
491 {
492 header << ", ";
493 }
494 header << "g" << name << "Map[" << id.value << "]";
495 }
496
497 header << " };\n ";
498
499 WriteParamStaticVarName(call, param, counter, out);
500 }
501
WriteBinaryParamReplay(DataTracker * dataTracker,std::ostream & out,std::ostream & header,const CallCapture & call,const ParamCapture & param,std::vector<uint8_t> * binaryData)502 void WriteBinaryParamReplay(DataTracker *dataTracker,
503 std::ostream &out,
504 std::ostream &header,
505 const CallCapture &call,
506 const ParamCapture ¶m,
507 std::vector<uint8_t> *binaryData)
508 {
509 int counter = dataTracker->getCounters().getAndIncrement(call.entryPoint, param.name);
510
511 ASSERT(param.data.size() == 1);
512 const std::vector<uint8_t> &data = param.data[0];
513
514 ParamType overrideType = param.type;
515 if (param.type == ParamType::TGLvoidConstPointer || param.type == ParamType::TvoidConstPointer)
516 {
517 overrideType = ParamType::TGLubyteConstPointer;
518 }
519 if (overrideType == ParamType::TGLenumConstPointer || overrideType == ParamType::TGLcharPointer)
520 {
521 // Inline if data are of type string or enum
522 std::string paramTypeString = ParamTypeToString(param.type);
523 header << paramTypeString.substr(0, paramTypeString.length() - 1);
524 WriteParamStaticVarName(call, param, counter, header);
525 header << "[] = { ";
526 if (overrideType == ParamType::TGLenumConstPointer)
527 {
528 WriteInlineData<GLuint>(data, header);
529 }
530 else
531 {
532 ASSERT(overrideType == ParamType::TGLcharPointer);
533 WriteInlineData<GLchar>(data, header);
534 }
535 header << " };\n";
536 WriteParamStaticVarName(call, param, counter, out);
537 }
538 else
539 {
540 // Store in binary file if data are not of type string or enum
541 // Round up to 16-byte boundary for cross ABI safety
542 size_t offset = rx::roundUpPow2(binaryData->size(), kBinaryAlignment);
543 binaryData->resize(offset + data.size());
544 memcpy(binaryData->data() + offset, data.data(), data.size());
545 out << "reinterpret_cast<" << ParamTypeToString(overrideType) << ">(&gBinaryData[" << offset
546 << "])";
547 }
548 }
549
SyncIndexValue(GLsync sync)550 uintptr_t SyncIndexValue(GLsync sync)
551 {
552 return reinterpret_cast<uintptr_t>(sync);
553 }
554
WriteCppReplayForCall(const CallCapture & call,DataTracker * dataTracker,std::ostream & out,std::ostream & header,std::vector<uint8_t> * binaryData)555 void WriteCppReplayForCall(const CallCapture &call,
556 DataTracker *dataTracker,
557 std::ostream &out,
558 std::ostream &header,
559 std::vector<uint8_t> *binaryData)
560 {
561 std::ostringstream callOut;
562
563 if (call.entryPoint == EntryPoint::GLCreateShader ||
564 call.entryPoint == EntryPoint::GLCreateProgram ||
565 call.entryPoint == EntryPoint::GLCreateShaderProgramv)
566 {
567 GLuint id = call.params.getReturnValue().value.GLuintVal;
568 callOut << "gShaderProgramMap[" << id << "] = ";
569 }
570
571 if (call.entryPoint == EntryPoint::GLFenceSync)
572 {
573 GLsync sync = call.params.getReturnValue().value.GLsyncVal;
574 callOut << "gSyncMap[" << SyncIndexValue(sync) << "] = ";
575 }
576
577 // Depending on how a buffer is mapped, we may need to track its location for readback
578 bool trackBufferPointer = false;
579
580 if (call.entryPoint == EntryPoint::GLMapBufferRange ||
581 call.entryPoint == EntryPoint::GLMapBufferRangeEXT)
582 {
583 GLbitfield access =
584 call.params.getParam("access", ParamType::TGLbitfield, 3).value.GLbitfieldVal;
585
586 trackBufferPointer = access & GL_MAP_WRITE_BIT;
587 }
588
589 if (call.entryPoint == EntryPoint::GLMapBuffer || call.entryPoint == EntryPoint::GLMapBufferOES)
590 {
591 GLenum access = call.params.getParam("access", ParamType::TGLenum, 1).value.GLenumVal;
592
593 trackBufferPointer =
594 access == GL_WRITE_ONLY_OES || access == GL_WRITE_ONLY || access == GL_READ_WRITE;
595 }
596
597 if (trackBufferPointer)
598 {
599 // Track the returned pointer so we update its data when unmapped
600 gl::BufferID bufferID = call.params.getMappedBufferID();
601 callOut << "gMappedBufferData[";
602 WriteParamValueReplay<ParamType::TBufferID>(callOut, call, bufferID);
603 callOut << "] = ";
604 }
605
606 callOut << call.name() << "(";
607
608 bool first = true;
609 for (const ParamCapture ¶m : call.params.getParamCaptures())
610 {
611 if (!first)
612 {
613 callOut << ", ";
614 }
615
616 if (param.arrayClientPointerIndex != -1 && param.value.voidConstPointerVal != nullptr)
617 {
618 callOut << "gClientArrays[" << param.arrayClientPointerIndex << "]";
619 }
620 else if (param.readBufferSizeBytes > 0)
621 {
622 callOut << "reinterpret_cast<" << ParamTypeToString(param.type) << ">(gReadBuffer)";
623 }
624 else if (param.data.empty())
625 {
626 if (param.type == ParamType::TGLenum)
627 {
628 OutputGLenumString(callOut, param.enumGroup, param.value.GLenumVal);
629 }
630 else if (param.type == ParamType::TGLbitfield)
631 {
632 OutputGLbitfieldString(callOut, param.enumGroup, param.value.GLbitfieldVal);
633 }
634 else if (param.type == ParamType::TGLfloat)
635 {
636 WriteGLFloatValue(callOut, param.value.GLfloatVal);
637 }
638 else if (param.type == ParamType::TGLsync)
639 {
640 callOut << "gSyncMap[" << SyncIndexValue(param.value.GLsyncVal) << "]";
641 }
642 else if (param.type == ParamType::TGLuint64 && param.name == "timeout")
643 {
644 if (param.value.GLuint64Val == GL_TIMEOUT_IGNORED)
645 {
646 callOut << "GL_TIMEOUT_IGNORED";
647 }
648 else
649 {
650 WriteParamCaptureReplay(callOut, call, param);
651 }
652 }
653 else
654 {
655 WriteParamCaptureReplay(callOut, call, param);
656 }
657 }
658 else
659 {
660 switch (param.type)
661 {
662 case ParamType::TGLcharConstPointer:
663 WriteStringParamReplay(callOut, param);
664 break;
665 case ParamType::TGLcharConstPointerPointer:
666 WriteStringPointerParamReplay(dataTracker, callOut, header, call, param);
667 break;
668 case ParamType::TBufferIDConstPointer:
669 WriteResourceIDPointerParamReplay<gl::BufferID>(dataTracker, callOut, out, call,
670 param);
671 break;
672 case ParamType::TFenceNVIDConstPointer:
673 WriteResourceIDPointerParamReplay<gl::FenceNVID>(dataTracker, callOut, out,
674 call, param);
675 break;
676 case ParamType::TFramebufferIDConstPointer:
677 WriteResourceIDPointerParamReplay<gl::FramebufferID>(dataTracker, callOut, out,
678 call, param);
679 break;
680 case ParamType::TMemoryObjectIDConstPointer:
681 WriteResourceIDPointerParamReplay<gl::MemoryObjectID>(dataTracker, callOut, out,
682 call, param);
683 break;
684 case ParamType::TProgramPipelineIDConstPointer:
685 WriteResourceIDPointerParamReplay<gl::ProgramPipelineID>(dataTracker, callOut,
686 out, call, param);
687 break;
688 case ParamType::TQueryIDConstPointer:
689 WriteResourceIDPointerParamReplay<gl::QueryID>(dataTracker, callOut, out, call,
690 param);
691 break;
692 case ParamType::TRenderbufferIDConstPointer:
693 WriteResourceIDPointerParamReplay<gl::RenderbufferID>(dataTracker, callOut, out,
694 call, param);
695 break;
696 case ParamType::TSamplerIDConstPointer:
697 WriteResourceIDPointerParamReplay<gl::SamplerID>(dataTracker, callOut, out,
698 call, param);
699 break;
700 case ParamType::TSemaphoreIDConstPointer:
701 WriteResourceIDPointerParamReplay<gl::SemaphoreID>(dataTracker, callOut, out,
702 call, param);
703 break;
704 case ParamType::TTextureIDConstPointer:
705 WriteResourceIDPointerParamReplay<gl::TextureID>(dataTracker, callOut, out,
706 call, param);
707 break;
708 case ParamType::TTransformFeedbackIDConstPointer:
709 WriteResourceIDPointerParamReplay<gl::TransformFeedbackID>(dataTracker, callOut,
710 out, call, param);
711 break;
712 case ParamType::TVertexArrayIDConstPointer:
713 WriteResourceIDPointerParamReplay<gl::VertexArrayID>(dataTracker, callOut, out,
714 call, param);
715 break;
716 default:
717 WriteBinaryParamReplay(dataTracker, callOut, header, call, param, binaryData);
718 break;
719 }
720 }
721
722 first = false;
723 }
724
725 callOut << ")";
726
727 out << callOut.str();
728 }
729
MaxClientArraySize(const gl::AttribArray<size_t> & clientArraySizes)730 size_t MaxClientArraySize(const gl::AttribArray<size_t> &clientArraySizes)
731 {
732 size_t found = 0;
733 for (size_t size : clientArraySizes)
734 {
735 if (size > found)
736 {
737 found = size;
738 }
739 }
740
741 return found;
742 }
743
744 struct SaveFileHelper
745 {
746 public:
747 // We always use ios::binary to avoid inconsistent line endings when captured on Linux vs Win.
SaveFileHelperangle::__anond94d34250111::SaveFileHelper748 SaveFileHelper(const std::string &filePathIn)
749 : mOfs(filePathIn, std::ios::binary | std::ios::out), mFilePath(filePathIn)
750 {
751 if (!mOfs.is_open())
752 {
753 FATAL() << "Could not open " << filePathIn;
754 }
755 }
756
~SaveFileHelperangle::__anond94d34250111::SaveFileHelper757 ~SaveFileHelper() { printf("Saved '%s'.\n", mFilePath.c_str()); }
758
759 template <typename T>
operator <<angle::__anond94d34250111::SaveFileHelper760 SaveFileHelper &operator<<(const T &value)
761 {
762 mOfs << value;
763 if (mOfs.bad())
764 {
765 FATAL() << "Error writing to " << mFilePath;
766 }
767 return *this;
768 }
769
writeangle::__anond94d34250111::SaveFileHelper770 void write(const uint8_t *data, size_t size)
771 {
772 mOfs.write(reinterpret_cast<const char *>(data), size);
773 }
774
775 private:
776 std::ofstream mOfs;
777 std::string mFilePath;
778 };
779
GetBinaryDataFilePath(bool compression,gl::ContextID contextId,const std::string & captureLabel)780 std::string GetBinaryDataFilePath(bool compression,
781 gl::ContextID contextId,
782 const std::string &captureLabel)
783 {
784 std::stringstream fnameStream;
785 fnameStream << FmtCapturePrefix(contextId, captureLabel) << ".angledata";
786 if (compression)
787 {
788 fnameStream << ".gz";
789 }
790 return fnameStream.str();
791 }
792
SaveBinaryData(bool compression,const std::string & outDir,gl::ContextID contextId,const std::string & captureLabel,const std::vector<uint8_t> & binaryData)793 void SaveBinaryData(bool compression,
794 const std::string &outDir,
795 gl::ContextID contextId,
796 const std::string &captureLabel,
797 const std::vector<uint8_t> &binaryData)
798 {
799 std::string binaryDataFileName = GetBinaryDataFilePath(compression, contextId, captureLabel);
800 std::string dataFilepath = outDir + binaryDataFileName;
801
802 SaveFileHelper saveData(dataFilepath);
803
804 if (compression)
805 {
806 // Save compressed data.
807 uLong uncompressedSize = static_cast<uLong>(binaryData.size());
808 uLong expectedCompressedSize = zlib_internal::GzipExpectedCompressedSize(uncompressedSize);
809
810 std::vector<uint8_t> compressedData(expectedCompressedSize, 0);
811
812 uLong compressedSize = expectedCompressedSize;
813 int zResult = zlib_internal::GzipCompressHelper(compressedData.data(), &compressedSize,
814 binaryData.data(), uncompressedSize,
815 nullptr, nullptr);
816
817 if (zResult != Z_OK)
818 {
819 FATAL() << "Error compressing binary data: " << zResult;
820 }
821
822 saveData.write(compressedData.data(), compressedSize);
823 }
824 else
825 {
826 saveData.write(binaryData.data(), binaryData.size());
827 }
828 }
829
WriteInitReplayCall(bool compression,std::ostream & out,gl::ContextID contextId,const std::string & captureLabel,size_t maxClientArraySize,size_t readBufferSize)830 void WriteInitReplayCall(bool compression,
831 std::ostream &out,
832 gl::ContextID contextId,
833 const std::string &captureLabel,
834 size_t maxClientArraySize,
835 size_t readBufferSize)
836 {
837 std::string binaryDataFileName = GetBinaryDataFilePath(compression, contextId, captureLabel);
838 out << " InitializeReplay(\"" << binaryDataFileName << "\", " << maxClientArraySize << ", "
839 << readBufferSize << ");\n";
840 }
841
842 // TODO (http://anglebug.com/4599): Reset more state on frame loop
MaybeResetResources(std::stringstream & out,ResourceIDType resourceIDType,DataTracker * dataTracker,std::stringstream & header,ResourceTracker * resourceTracker,std::vector<uint8_t> * binaryData)843 void MaybeResetResources(std::stringstream &out,
844 ResourceIDType resourceIDType,
845 DataTracker *dataTracker,
846 std::stringstream &header,
847 ResourceTracker *resourceTracker,
848 std::vector<uint8_t> *binaryData)
849 {
850 switch (resourceIDType)
851 {
852 case ResourceIDType::Buffer:
853 {
854 BufferSet &newBuffers = resourceTracker->getNewBuffers();
855 BufferCalls &bufferRegenCalls = resourceTracker->getBufferRegenCalls();
856 BufferCalls &bufferRestoreCalls = resourceTracker->getBufferRestoreCalls();
857 BufferCalls &bufferMapCalls = resourceTracker->getBufferMapCalls();
858 BufferCalls &bufferUnmapCalls = resourceTracker->getBufferUnmapCalls();
859
860 // If we have any new buffers generated and not deleted during the run, delete them now
861 if (!newBuffers.empty())
862 {
863 out << " const GLuint deleteBuffers[] = {";
864 BufferSet::iterator bufferIter = newBuffers.begin();
865 for (size_t i = 0; bufferIter != newBuffers.end(); ++i, ++bufferIter)
866 {
867 if (i > 0)
868 {
869 out << ", ";
870 }
871 if ((i % 4) == 0)
872 {
873 out << "\n ";
874 }
875 out << "gBufferMap[" << (*bufferIter).value << "]";
876 }
877 out << "};\n";
878 out << " glDeleteBuffers(" << newBuffers.size() << ", deleteBuffers);\n";
879 }
880
881 // If any of our starting buffers were deleted during the run, recreate them
882 BufferSet &buffersToRegen = resourceTracker->getBuffersToRegen();
883 for (const gl::BufferID id : buffersToRegen)
884 {
885 // Emit their regen calls
886 for (CallCapture &call : bufferRegenCalls[id])
887 {
888 out << " ";
889 WriteCppReplayForCall(call, dataTracker, out, header, binaryData);
890 out << ";\n";
891 }
892 }
893
894 // If any of our starting buffers were modified during the run, restore their contents
895 BufferSet &buffersToRestore = resourceTracker->getBuffersToRestore();
896 for (const gl::BufferID id : buffersToRestore)
897 {
898 if (resourceTracker->getStartingBuffersMappedCurrent(id))
899 {
900 // Some drivers require the buffer to be unmapped before you can update data,
901 // which violates the spec. See gl::Buffer::bufferDataImpl().
902 for (CallCapture &call : bufferUnmapCalls[id])
903 {
904 out << " ";
905 WriteCppReplayForCall(call, dataTracker, out, header, binaryData);
906 out << ";\n";
907 }
908 }
909
910 // Emit their restore calls
911 for (CallCapture &call : bufferRestoreCalls[id])
912 {
913 out << " ";
914 WriteCppReplayForCall(call, dataTracker, out, header, binaryData);
915 out << ";\n";
916
917 // Also note that this buffer has been implicitly unmapped by this call
918 resourceTracker->setBufferUnmapped(id);
919 }
920 }
921
922 // Update the map/unmap of buffers to match the starting state
923 BufferSet startingBuffers = resourceTracker->getStartingBuffers();
924 for (const gl::BufferID id : startingBuffers)
925 {
926 // If the buffer was mapped at the start, but is not mapped now, we need to map
927 if (resourceTracker->getStartingBuffersMappedInitial(id) &&
928 !resourceTracker->getStartingBuffersMappedCurrent(id))
929 {
930 // Emit their map calls
931 for (CallCapture &call : bufferMapCalls[id])
932 {
933 out << " ";
934 WriteCppReplayForCall(call, dataTracker, out, header, binaryData);
935 out << ";\n";
936 }
937 }
938 // If the buffer was unmapped at the start, but is mapped now, we need to unmap
939 if (!resourceTracker->getStartingBuffersMappedInitial(id) &&
940 resourceTracker->getStartingBuffersMappedCurrent(id))
941 {
942 // Emit their unmap calls
943 for (CallCapture &call : bufferUnmapCalls[id])
944 {
945 out << " ";
946 WriteCppReplayForCall(call, dataTracker, out, header, binaryData);
947 out << ";\n";
948 }
949 }
950 }
951
952 // Restore buffer bindings as seen during MEC
953 std::vector<CallCapture> &bufferBindingCalls = resourceTracker->getBufferBindingCalls();
954 for (CallCapture &call : bufferBindingCalls)
955 {
956 out << " ";
957 WriteCppReplayForCall(call, dataTracker, out, header, binaryData);
958 out << ";\n";
959 }
960
961 break;
962 }
963 case ResourceIDType::ShaderProgram:
964 {
965 ProgramSet &newPrograms = resourceTracker->getNewPrograms();
966
967 // If we have any new programs created and not deleted during the run, delete them now
968 for (const auto &newProgram : newPrograms)
969 {
970 out << " glDeleteProgram(gShaderProgramMap[" << newProgram.value << "]);\n";
971 }
972
973 // TODO (http://anglebug.com/5968): Handle programs that need regen
974 // This would only happen if a starting program was deleted during the run
975 ASSERT(resourceTracker->getProgramsToRegen().empty());
976 break;
977 }
978 default:
979 // TODO (http://anglebug.com/4599): Reset more than just buffers
980 break;
981 }
982 }
983
MaybeResetFenceSyncObjects(std::stringstream & out,DataTracker * dataTracker,std::stringstream & header,ResourceTracker * resourceTracker,std::vector<uint8_t> * binaryData)984 void MaybeResetFenceSyncObjects(std::stringstream &out,
985 DataTracker *dataTracker,
986 std::stringstream &header,
987 ResourceTracker *resourceTracker,
988 std::vector<uint8_t> *binaryData)
989 {
990 FenceSyncCalls &fenceSyncRegenCalls = resourceTracker->getFenceSyncRegenCalls();
991
992 // If any of our starting fence sync objects were deleted during the run, recreate them
993 FenceSyncSet &fenceSyncsToRegen = resourceTracker->getFenceSyncsToRegen();
994 for (const GLsync sync : fenceSyncsToRegen)
995 {
996 // Emit their regen calls
997 for (CallCapture &call : fenceSyncRegenCalls[sync])
998 {
999 out << " ";
1000 WriteCppReplayForCall(call, dataTracker, out, header, binaryData);
1001 out << ";\n";
1002 }
1003 }
1004 }
1005
MaybeResetOpaqueTypeObjects(std::stringstream & out,DataTracker * dataTracker,std::stringstream & header,ResourceTracker * resourceTracker,std::vector<uint8_t> * binaryData)1006 void MaybeResetOpaqueTypeObjects(std::stringstream &out,
1007 DataTracker *dataTracker,
1008 std::stringstream &header,
1009 ResourceTracker *resourceTracker,
1010 std::vector<uint8_t> *binaryData)
1011 {
1012 MaybeResetFenceSyncObjects(out, dataTracker, header, resourceTracker, binaryData);
1013 }
1014
WriteCppReplayFunctionWithParts(const gl::ContextID contextID,ReplayFunc replayFunc,DataTracker * dataTracker,uint32_t frameIndex,std::vector<uint8_t> * binaryData,const std::vector<CallCapture> & calls,std::stringstream & header,std::stringstream & callStream,std::stringstream & out)1015 void WriteCppReplayFunctionWithParts(const gl::ContextID contextID,
1016 ReplayFunc replayFunc,
1017 DataTracker *dataTracker,
1018 uint32_t frameIndex,
1019 std::vector<uint8_t> *binaryData,
1020 const std::vector<CallCapture> &calls,
1021 std::stringstream &header,
1022 std::stringstream &callStream,
1023 std::stringstream &out)
1024 {
1025 std::stringstream callStreamParts;
1026
1027 int callCount = 0;
1028 int partCount = 0;
1029
1030 // Setup can get quite large. If over a certain size, break up the function to avoid
1031 // overflowing the stack
1032 if (calls.size() > kFunctionSizeLimit)
1033 {
1034 callStreamParts << "void " << FmtFunction(replayFunc, contextID, frameIndex, ++partCount)
1035 << "\n";
1036 callStreamParts << "{\n";
1037 }
1038
1039 for (const CallCapture &call : calls)
1040 {
1041 callStreamParts << " ";
1042 WriteCppReplayForCall(call, dataTracker, callStreamParts, header, binaryData);
1043 callStreamParts << ";\n";
1044
1045 if (partCount > 0 && ++callCount % kFunctionSizeLimit == 0)
1046 {
1047 callStreamParts << "}\n";
1048 callStreamParts << "\n";
1049 callStreamParts << "void "
1050 << FmtFunction(replayFunc, contextID, frameIndex, ++partCount) << "\n";
1051 callStreamParts << "{\n";
1052 }
1053 }
1054
1055 if (partCount > 0)
1056 {
1057 callStreamParts << "}\n";
1058 callStreamParts << "\n";
1059
1060 // Write out the parts
1061 out << callStreamParts.str();
1062
1063 // Write out the calls to the parts
1064 for (int i = 1; i <= partCount; i++)
1065 {
1066 callStream << " " << FmtFunction(replayFunc, contextID, frameIndex, i) << ";\n";
1067 }
1068 }
1069 else
1070 {
1071 // If we didn't chunk it up, write all the calls directly to SetupContext
1072 callStream << callStreamParts.str();
1073 }
1074 }
1075
1076 // Auxiliary contexts are other contexts in the share group that aren't the context calling
1077 // eglSwapBuffers().
WriteAuxiliaryContextCppSetupReplay(bool compression,const std::string & outDir,const gl::Context * context,const std::string & captureLabel,uint32_t frameIndex,const std::vector<CallCapture> & setupCalls,std::vector<uint8_t> * binaryData,bool serializeStateEnabled,const FrameCaptureShared & frameCaptureShared)1078 void WriteAuxiliaryContextCppSetupReplay(bool compression,
1079 const std::string &outDir,
1080 const gl::Context *context,
1081 const std::string &captureLabel,
1082 uint32_t frameIndex,
1083 const std::vector<CallCapture> &setupCalls,
1084 std::vector<uint8_t> *binaryData,
1085 bool serializeStateEnabled,
1086 const FrameCaptureShared &frameCaptureShared)
1087 {
1088 ASSERT(frameCaptureShared.getWindowSurfaceContextID() != context->id());
1089
1090 DataTracker dataTracker;
1091
1092 std::stringstream out;
1093 std::stringstream include;
1094 std::stringstream header;
1095
1096 include << "#include \"" << FmtCapturePrefix(context->id(), captureLabel) << ".h\"\n";
1097 include << "#include \"angle_trace_gl.h\"\n";
1098 include << "";
1099 include << "\n";
1100 include << "namespace\n";
1101 include << "{\n";
1102
1103 if (!captureLabel.empty())
1104 {
1105 header << "namespace " << captureLabel << "\n";
1106 header << "{\n";
1107 out << "namespace " << captureLabel << "\n";
1108 out << "{\n";
1109 }
1110
1111 std::stringstream setupCallStream;
1112
1113 header << "void " << FmtSetupFunction(kNoPartId, context->id()) << ";\n";
1114 setupCallStream << "void " << FmtSetupFunction(kNoPartId, context->id()) << "\n";
1115 setupCallStream << "{\n";
1116
1117 WriteCppReplayFunctionWithParts(context->id(), ReplayFunc::Setup, &dataTracker, frameIndex,
1118 binaryData, setupCalls, include, setupCallStream, out);
1119
1120 out << setupCallStream.str();
1121 out << "}\n";
1122 out << "\n";
1123
1124 if (!captureLabel.empty())
1125 {
1126 header << "} // namespace " << captureLabel << "\n";
1127 out << "} // namespace " << captureLabel << "\n";
1128 }
1129
1130 include << "} // namespace\n";
1131
1132 // Write out the source file.
1133 {
1134 std::string outString = out.str();
1135 std::string headerString = include.str();
1136
1137 std::string cppFilePath =
1138 GetCaptureFilePath(outDir, context->id(), captureLabel, frameIndex, ".cpp");
1139
1140 SaveFileHelper saveCpp(cppFilePath);
1141 saveCpp << headerString << "\n" << outString;
1142 }
1143
1144 // Write out the header file.
1145 {
1146 std::string headerContents = header.str();
1147
1148 std::stringstream headerPathStream;
1149 headerPathStream << outDir << FmtCapturePrefix(context->id(), captureLabel) << ".h";
1150 std::string headerPath = headerPathStream.str();
1151
1152 SaveFileHelper saveHeader(headerPath);
1153 saveHeader << headerContents;
1154 }
1155 }
1156
WriteWindowSurfaceContextCppReplay(bool compression,const std::string & outDir,const gl::Context * context,const std::string & captureLabel,uint32_t frameIndex,uint32_t frameCount,const std::vector<CallCapture> & frameCalls,const std::vector<CallCapture> & setupCalls,ResourceTracker * resourceTracker,std::vector<uint8_t> * binaryData,bool serializeStateEnabled,const FrameCaptureShared & frameCaptureShared)1157 void WriteWindowSurfaceContextCppReplay(bool compression,
1158 const std::string &outDir,
1159 const gl::Context *context,
1160 const std::string &captureLabel,
1161 uint32_t frameIndex,
1162 uint32_t frameCount,
1163 const std::vector<CallCapture> &frameCalls,
1164 const std::vector<CallCapture> &setupCalls,
1165 ResourceTracker *resourceTracker,
1166 std::vector<uint8_t> *binaryData,
1167 bool serializeStateEnabled,
1168 const FrameCaptureShared &frameCaptureShared)
1169 {
1170 ASSERT(frameCaptureShared.getWindowSurfaceContextID() == context->id());
1171
1172 DataTracker dataTracker;
1173
1174 std::stringstream out;
1175 std::stringstream header;
1176
1177 egl::ShareGroup *shareGroup = context->getShareGroup();
1178 egl::ContextSet *shareContextSet = shareGroup->getContexts();
1179
1180 header << "#include \"" << FmtCapturePrefix(kSharedContextId, captureLabel) << ".h\"\n";
1181 for (gl::Context *shareContext : *shareContextSet)
1182 {
1183 header << "#include \"" << FmtCapturePrefix(shareContext->id(), captureLabel) << ".h\"\n";
1184 }
1185
1186 header << "#include \"angle_trace_gl.h\"\n";
1187 header << "";
1188 header << "\n";
1189 header << "namespace\n";
1190 header << "{\n";
1191
1192 if (frameIndex == 1 || frameIndex == frameCount)
1193 {
1194 out << "extern \"C\" {\n";
1195 }
1196
1197 if (frameIndex == 1)
1198 {
1199 std::stringstream setupCallStream;
1200
1201 setupCallStream << "void " << FmtSetupFunction(kNoPartId, context->id()) << "\n";
1202 setupCallStream << "{\n";
1203
1204 WriteCppReplayFunctionWithParts(context->id(), ReplayFunc::Setup, &dataTracker, frameIndex,
1205 binaryData, setupCalls, header, setupCallStream, out);
1206
1207 out << setupCallStream.str();
1208 out << "}\n";
1209 out << "\n";
1210 out << "void SetupReplay()\n";
1211 out << "{\n";
1212 out << " " << captureLabel << "::InitReplay();\n";
1213
1214 // Setup all of the shared objects.
1215 out << " " << captureLabel << "::" << FmtSetupFunction(kNoPartId, kSharedContextId)
1216 << ";\n";
1217
1218 // Setup the presentation (this) context before any other contexts in the share group.
1219 out << " " << FmtSetupFunction(kNoPartId, context->id()) << ";\n";
1220 out << "}\n";
1221 out << "\n";
1222 }
1223
1224 if (frameIndex == frameCount)
1225 {
1226 // Emit code to reset back to starting state
1227 out << "void " << FmtResetFunction() << "\n";
1228 out << "{\n";
1229
1230 // TODO(http://anglebug.com/5878): Look at moving this into the shared context file since
1231 // it's resetting shared objects.
1232 std::stringstream restoreCallStream;
1233 for (ResourceIDType resourceType : AllEnums<ResourceIDType>())
1234 {
1235 MaybeResetResources(restoreCallStream, resourceType, &dataTracker, header,
1236 resourceTracker, binaryData);
1237 }
1238
1239 // Reset opaque type objects that don't have IDs, so are not ResourceIDTypes.
1240 MaybeResetOpaqueTypeObjects(restoreCallStream, &dataTracker, header, resourceTracker,
1241 binaryData);
1242
1243 out << restoreCallStream.str();
1244 out << "}\n";
1245 }
1246
1247 if (frameIndex == 1 || frameIndex == frameCount)
1248 {
1249 out << "} // extern \"C\"\n";
1250 out << "\n";
1251 }
1252
1253 if (!captureLabel.empty())
1254 {
1255 out << "namespace " << captureLabel << "\n";
1256 out << "{\n";
1257 }
1258
1259 if (!frameCalls.empty())
1260 {
1261 std::stringstream callStream;
1262
1263 callStream << "void " << FmtReplayFunction(context->id(), frameIndex) << "\n";
1264 callStream << "{\n";
1265
1266 WriteCppReplayFunctionWithParts(context->id(), ReplayFunc::Replay, &dataTracker, frameIndex,
1267 binaryData, frameCalls, header, callStream, out);
1268
1269 out << callStream.str();
1270 out << "}\n";
1271 }
1272
1273 if (serializeStateEnabled)
1274 {
1275 std::string serializedContextString;
1276 if (SerializeContextToString(const_cast<gl::Context *>(context),
1277 &serializedContextString) == Result::Continue)
1278 {
1279 out << "const char *" << FmtGetSerializedContextStateFunction(context->id(), frameIndex)
1280 << "\n";
1281 out << "{\n";
1282 out << " return R\"(" << serializedContextString << ")\";\n";
1283 out << "}\n";
1284 out << "\n";
1285 }
1286 }
1287
1288 if (!captureLabel.empty())
1289 {
1290 out << "} // namespace " << captureLabel << "\n";
1291 }
1292
1293 header << "} // namespace\n";
1294
1295 {
1296 std::string outString = out.str();
1297 std::string headerString = header.str();
1298
1299 std::string cppFilePath =
1300 GetCaptureFilePath(outDir, context->id(), captureLabel, frameIndex, ".cpp");
1301
1302 SaveFileHelper saveCpp(cppFilePath);
1303 saveCpp << headerString << "\n" << outString;
1304 }
1305 }
1306
WriteSharedContextCppReplay(bool compression,const std::string & outDir,const std::string & captureLabel,uint32_t frameIndex,uint32_t frameCount,const std::vector<CallCapture> & setupCalls,ResourceTracker * resourceTracker,std::vector<uint8_t> * binaryData,bool serializeStateEnabled,const FrameCaptureShared & frameCaptureShared)1307 void WriteSharedContextCppReplay(bool compression,
1308 const std::string &outDir,
1309 const std::string &captureLabel,
1310 uint32_t frameIndex,
1311 uint32_t frameCount,
1312 const std::vector<CallCapture> &setupCalls,
1313 ResourceTracker *resourceTracker,
1314 std::vector<uint8_t> *binaryData,
1315 bool serializeStateEnabled,
1316 const FrameCaptureShared &frameCaptureShared)
1317 {
1318 DataTracker dataTracker;
1319
1320 std::stringstream out;
1321 std::stringstream include;
1322 std::stringstream header;
1323
1324 include << "#include \"" << FmtCapturePrefix(kSharedContextId, captureLabel) << ".h\"\n";
1325 include << "#include \"angle_trace_gl.h\"\n";
1326 include << "";
1327 include << "\n";
1328 include << "namespace\n";
1329 include << "{\n";
1330
1331 if (!captureLabel.empty())
1332 {
1333 header << "namespace " << captureLabel << "\n";
1334 header << "{\n";
1335 out << "namespace " << captureLabel << "\n";
1336 out << "{\n";
1337 }
1338
1339 std::stringstream setupCallStream;
1340
1341 header << "void " << FmtSetupFunction(kNoPartId, kSharedContextId) << ";\n";
1342 setupCallStream << "void " << FmtSetupFunction(kNoPartId, kSharedContextId) << "\n";
1343 setupCallStream << "{\n";
1344
1345 WriteCppReplayFunctionWithParts(kSharedContextId, ReplayFunc::Setup, &dataTracker, frameIndex,
1346 binaryData, setupCalls, include, setupCallStream, out);
1347
1348 out << setupCallStream.str();
1349 out << "}\n";
1350 out << "\n";
1351
1352 if (!captureLabel.empty())
1353 {
1354 header << "} // namespace " << captureLabel << "\n";
1355 out << "} // namespace " << captureLabel << "\n";
1356 }
1357
1358 include << "} // namespace\n";
1359
1360 // Write out the source file.
1361 {
1362 std::string outString = out.str();
1363 std::string headerString = include.str();
1364
1365 std::string cppFilePath =
1366 GetCaptureFilePath(outDir, kSharedContextId, captureLabel, frameIndex, ".cpp");
1367
1368 SaveFileHelper saveCpp(cppFilePath);
1369 saveCpp << headerString << "\n" << outString;
1370 }
1371
1372 // Write out the header file.
1373 {
1374 std::string headerContents = header.str();
1375
1376 std::stringstream headerPathStream;
1377 headerPathStream << outDir << FmtCapturePrefix(kSharedContextId, captureLabel) << ".h";
1378 std::string headerPath = headerPathStream.str();
1379
1380 SaveFileHelper saveHeader(headerPath);
1381 saveHeader << headerContents;
1382 }
1383 }
1384
GetAttachedProgramSources(const gl::Program * program)1385 ProgramSources GetAttachedProgramSources(const gl::Program *program)
1386 {
1387 ProgramSources sources;
1388 for (gl::ShaderType shaderType : gl::AllShaderTypes())
1389 {
1390 const gl::Shader *shader = program->getAttachedShader(shaderType);
1391 if (shader)
1392 {
1393 sources[shaderType] = shader->getSourceString();
1394 }
1395 }
1396 return sources;
1397 }
1398
1399 template <typename IDType>
CaptureUpdateResourceIDs(const CallCapture & call,const ParamCapture & param,std::vector<CallCapture> * callsOut)1400 void CaptureUpdateResourceIDs(const CallCapture &call,
1401 const ParamCapture ¶m,
1402 std::vector<CallCapture> *callsOut)
1403 {
1404 GLsizei n = call.params.getParamFlexName("n", "count", ParamType::TGLsizei, 0).value.GLsizeiVal;
1405 ASSERT(param.data.size() == 1);
1406 ResourceIDType resourceIDType = GetResourceIDTypeFromParamType(param.type);
1407 ASSERT(resourceIDType != ResourceIDType::InvalidEnum);
1408 const char *resourceName = GetResourceIDTypeName(resourceIDType);
1409
1410 std::stringstream updateFuncNameStr;
1411 updateFuncNameStr << "Update" << resourceName << "ID";
1412 std::string updateFuncName = updateFuncNameStr.str();
1413
1414 const IDType *returnedIDs = reinterpret_cast<const IDType *>(param.data[0].data());
1415
1416 for (GLsizei idIndex = 0; idIndex < n; ++idIndex)
1417 {
1418 IDType id = returnedIDs[idIndex];
1419 GLsizei readBufferOffset = idIndex * sizeof(gl::RenderbufferID);
1420 ParamBuffer params;
1421 params.addValueParam("id", ParamType::TGLuint, id.value);
1422 params.addValueParam("readBufferOffset", ParamType::TGLsizei, readBufferOffset);
1423 callsOut->emplace_back(updateFuncName, std::move(params));
1424 }
1425 }
1426
CaptureUpdateUniformLocations(const gl::Program * program,std::vector<CallCapture> * callsOut)1427 void CaptureUpdateUniformLocations(const gl::Program *program, std::vector<CallCapture> *callsOut)
1428 {
1429 const std::vector<gl::LinkedUniform> &uniforms = program->getState().getUniforms();
1430 const std::vector<gl::VariableLocation> &locations = program->getUniformLocations();
1431
1432 for (GLint location = 0; location < static_cast<GLint>(locations.size()); ++location)
1433 {
1434 const gl::VariableLocation &locationVar = locations[location];
1435
1436 // This handles the case where the application calls glBindUniformLocationCHROMIUM
1437 // on an unused uniform. We must still store a -1 into gUniformLocations in case the
1438 // application attempts to call a glUniform* call. To do this we'll pass in a blank name to
1439 // force glGetUniformLocation to return -1.
1440 std::string name;
1441 ParamBuffer params;
1442 params.addValueParam("program", ParamType::TShaderProgramID, program->id());
1443
1444 if (locationVar.index >= uniforms.size())
1445 {
1446 name = "";
1447 }
1448 else
1449 {
1450 const gl::LinkedUniform &uniform = uniforms[locationVar.index];
1451
1452 name = uniform.name;
1453
1454 if (uniform.isArray())
1455 {
1456 if (locationVar.arrayIndex > 0)
1457 {
1458 // Non-sequential array uniform locations are not currently handled.
1459 // In practice array locations shouldn't ever be non-sequential.
1460 ASSERT(uniform.location == -1 ||
1461 location == uniform.location + static_cast<int>(locationVar.arrayIndex));
1462 continue;
1463 }
1464
1465 if (uniform.isArrayOfArrays())
1466 {
1467 UNIMPLEMENTED();
1468 }
1469
1470 name = gl::StripLastArrayIndex(name);
1471 }
1472 }
1473
1474 ParamCapture nameParam("name", ParamType::TGLcharConstPointer);
1475 CaptureString(name.c_str(), &nameParam);
1476 params.addParam(std::move(nameParam));
1477
1478 params.addValueParam("location", ParamType::TGLint, location);
1479 callsOut->emplace_back("UpdateUniformLocation", std::move(params));
1480 }
1481 }
1482
CaptureUpdateUniformBlockIndexes(const gl::Program * program,std::vector<CallCapture> * callsOut)1483 void CaptureUpdateUniformBlockIndexes(const gl::Program *program,
1484 std::vector<CallCapture> *callsOut)
1485 {
1486 const std::vector<gl::InterfaceBlock> &uniformBlocks = program->getState().getUniformBlocks();
1487
1488 for (GLuint index = 0; index < uniformBlocks.size(); ++index)
1489 {
1490 ParamBuffer params;
1491
1492 std::string name;
1493 params.addValueParam("program", ParamType::TShaderProgramID, program->id());
1494
1495 ParamCapture nameParam("name", ParamType::TGLcharConstPointer);
1496 CaptureString(uniformBlocks[index].name.c_str(), &nameParam);
1497 params.addParam(std::move(nameParam));
1498
1499 params.addValueParam("index", ParamType::TGLuint, index);
1500 callsOut->emplace_back("UpdateUniformBlockIndex", std::move(params));
1501 }
1502 }
1503
CaptureDeleteUniformLocations(gl::ShaderProgramID program,std::vector<CallCapture> * callsOut)1504 void CaptureDeleteUniformLocations(gl::ShaderProgramID program, std::vector<CallCapture> *callsOut)
1505 {
1506 ParamBuffer params;
1507 params.addValueParam("program", ParamType::TShaderProgramID, program);
1508 callsOut->emplace_back("DeleteUniformLocations", std::move(params));
1509 }
1510
MaybeCaptureUpdateResourceIDs(std::vector<CallCapture> * callsOut)1511 void MaybeCaptureUpdateResourceIDs(std::vector<CallCapture> *callsOut)
1512 {
1513 const CallCapture &call = callsOut->back();
1514
1515 switch (call.entryPoint)
1516 {
1517 case EntryPoint::GLGenBuffers:
1518 {
1519 const ParamCapture &buffers =
1520 call.params.getParam("buffersPacked", ParamType::TBufferIDPointer, 1);
1521 CaptureUpdateResourceIDs<gl::BufferID>(call, buffers, callsOut);
1522 break;
1523 }
1524
1525 case EntryPoint::GLGenFencesNV:
1526 {
1527 const ParamCapture &fences =
1528 call.params.getParam("fencesPacked", ParamType::TFenceNVIDPointer, 1);
1529 CaptureUpdateResourceIDs<gl::FenceNVID>(call, fences, callsOut);
1530 break;
1531 }
1532
1533 case EntryPoint::GLGenFramebuffers:
1534 case EntryPoint::GLGenFramebuffersOES:
1535 {
1536 const ParamCapture &framebuffers =
1537 call.params.getParam("framebuffersPacked", ParamType::TFramebufferIDPointer, 1);
1538 CaptureUpdateResourceIDs<gl::FramebufferID>(call, framebuffers, callsOut);
1539 break;
1540 }
1541
1542 case EntryPoint::GLGenProgramPipelines:
1543 {
1544 const ParamCapture &pipelines =
1545 call.params.getParam("pipelinesPacked", ParamType::TProgramPipelineIDPointer, 1);
1546 CaptureUpdateResourceIDs<gl::ProgramPipelineID>(call, pipelines, callsOut);
1547 break;
1548 }
1549
1550 case EntryPoint::GLGenQueries:
1551 case EntryPoint::GLGenQueriesEXT:
1552 {
1553 const ParamCapture &queries =
1554 call.params.getParam("idsPacked", ParamType::TQueryIDPointer, 1);
1555 CaptureUpdateResourceIDs<gl::QueryID>(call, queries, callsOut);
1556 break;
1557 }
1558
1559 case EntryPoint::GLGenRenderbuffers:
1560 case EntryPoint::GLGenRenderbuffersOES:
1561 {
1562 const ParamCapture &renderbuffers =
1563 call.params.getParam("renderbuffersPacked", ParamType::TRenderbufferIDPointer, 1);
1564 CaptureUpdateResourceIDs<gl::RenderbufferID>(call, renderbuffers, callsOut);
1565 break;
1566 }
1567
1568 case EntryPoint::GLGenSamplers:
1569 {
1570 const ParamCapture &samplers =
1571 call.params.getParam("samplersPacked", ParamType::TSamplerIDPointer, 1);
1572 CaptureUpdateResourceIDs<gl::SamplerID>(call, samplers, callsOut);
1573 break;
1574 }
1575
1576 case EntryPoint::GLGenSemaphoresEXT:
1577 {
1578 const ParamCapture &semaphores =
1579 call.params.getParam("semaphoresPacked", ParamType::TSemaphoreIDPointer, 1);
1580 CaptureUpdateResourceIDs<gl::SemaphoreID>(call, semaphores, callsOut);
1581 break;
1582 }
1583
1584 case EntryPoint::GLGenTextures:
1585 {
1586 const ParamCapture &textures =
1587 call.params.getParam("texturesPacked", ParamType::TTextureIDPointer, 1);
1588 CaptureUpdateResourceIDs<gl::TextureID>(call, textures, callsOut);
1589 break;
1590 }
1591
1592 case EntryPoint::GLGenTransformFeedbacks:
1593 {
1594 const ParamCapture &xfbs =
1595 call.params.getParam("idsPacked", ParamType::TTransformFeedbackIDPointer, 1);
1596 CaptureUpdateResourceIDs<gl::TransformFeedbackID>(call, xfbs, callsOut);
1597 break;
1598 }
1599
1600 case EntryPoint::GLGenVertexArrays:
1601 case EntryPoint::GLGenVertexArraysOES:
1602 {
1603 const ParamCapture &vertexArrays =
1604 call.params.getParam("arraysPacked", ParamType::TVertexArrayIDPointer, 1);
1605 CaptureUpdateResourceIDs<gl::VertexArrayID>(call, vertexArrays, callsOut);
1606 break;
1607 }
1608
1609 case EntryPoint::GLCreateMemoryObjectsEXT:
1610 {
1611 const ParamCapture &memoryObjects =
1612 call.params.getParam("memoryObjectsPacked", ParamType::TMemoryObjectIDPointer, 1);
1613 CaptureUpdateResourceIDs<gl::MemoryObjectID>(call, memoryObjects, callsOut);
1614 break;
1615 }
1616
1617 default:
1618 break;
1619 }
1620 }
1621
CaptureUpdateCurrentProgram(const CallCapture & call,std::vector<CallCapture> * callsOut)1622 void CaptureUpdateCurrentProgram(const CallCapture &call, std::vector<CallCapture> *callsOut)
1623 {
1624 const ParamCapture ¶m =
1625 call.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
1626 gl::ShaderProgramID programID = param.value.ShaderProgramIDVal;
1627
1628 ParamBuffer paramBuffer;
1629 paramBuffer.addValueParam("program", ParamType::TShaderProgramID, programID);
1630
1631 callsOut->emplace_back("UpdateCurrentProgram", std::move(paramBuffer));
1632 }
1633
IsDefaultCurrentValue(const gl::VertexAttribCurrentValueData & currentValue)1634 bool IsDefaultCurrentValue(const gl::VertexAttribCurrentValueData ¤tValue)
1635 {
1636 if (currentValue.Type != gl::VertexAttribType::Float)
1637 return false;
1638
1639 return currentValue.Values.FloatValues[0] == 0.0f &&
1640 currentValue.Values.FloatValues[1] == 0.0f &&
1641 currentValue.Values.FloatValues[2] == 0.0f && currentValue.Values.FloatValues[3] == 1.0f;
1642 }
1643
IsQueryActive(const gl::State & glState,gl::QueryID & queryID)1644 bool IsQueryActive(const gl::State &glState, gl::QueryID &queryID)
1645 {
1646 const gl::ActiveQueryMap &activeQueries = glState.getActiveQueriesForCapture();
1647 for (const auto &activeQueryIter : activeQueries)
1648 {
1649 const gl::Query *activeQuery = activeQueryIter.get();
1650 if (activeQuery && activeQuery->id() == queryID)
1651 {
1652 return true;
1653 }
1654 }
1655
1656 return false;
1657 }
1658
Capture(std::vector<CallCapture> * setupCalls,CallCapture && call)1659 void Capture(std::vector<CallCapture> *setupCalls, CallCapture &&call)
1660 {
1661 setupCalls->emplace_back(std::move(call));
1662 }
1663
CaptureFramebufferAttachment(std::vector<CallCapture> * setupCalls,const gl::State & replayState,const gl::FramebufferAttachment & attachment)1664 void CaptureFramebufferAttachment(std::vector<CallCapture> *setupCalls,
1665 const gl::State &replayState,
1666 const gl::FramebufferAttachment &attachment)
1667 {
1668 GLuint resourceID = attachment.getResource()->getId();
1669
1670 // TODO(jmadill): Layer attachments. http://anglebug.com/3662
1671 if (attachment.type() == GL_TEXTURE)
1672 {
1673 gl::ImageIndex index = attachment.getTextureImageIndex();
1674
1675 Capture(setupCalls, CaptureFramebufferTexture2D(replayState, true, GL_FRAMEBUFFER,
1676 attachment.getBinding(), index.getTarget(),
1677 {resourceID}, index.getLevelIndex()));
1678 }
1679 else
1680 {
1681 ASSERT(attachment.type() == GL_RENDERBUFFER);
1682 Capture(setupCalls, CaptureFramebufferRenderbuffer(replayState, true, GL_FRAMEBUFFER,
1683 attachment.getBinding(), GL_RENDERBUFFER,
1684 {resourceID}));
1685 }
1686 }
1687
CaptureUpdateUniformValues(const gl::State & replayState,const gl::Context * context,const gl::Program * program,std::vector<CallCapture> * callsOut)1688 void CaptureUpdateUniformValues(const gl::State &replayState,
1689 const gl::Context *context,
1690 const gl::Program *program,
1691 std::vector<CallCapture> *callsOut)
1692 {
1693 if (!program->isLinked())
1694 {
1695 // We can't populate uniforms if the program hasn't been linked
1696 return;
1697 }
1698
1699 // We need to bind the program and update its uniforms
1700 // TODO (http://anglebug.com/3662): Only bind if different from currently bound
1701 Capture(callsOut, CaptureUseProgram(replayState, true, program->id()));
1702 CaptureUpdateCurrentProgram(callsOut->back(), callsOut);
1703
1704 const std::vector<gl::LinkedUniform> &uniforms = program->getState().getUniforms();
1705
1706 for (const gl::LinkedUniform &uniform : uniforms)
1707 {
1708 std::string uniformName = uniform.name;
1709
1710 int uniformCount = 1;
1711 if (uniform.isArray())
1712 {
1713 if (uniform.isArrayOfArrays())
1714 {
1715 UNIMPLEMENTED();
1716 continue;
1717 }
1718
1719 uniformCount = uniform.arraySizes[0];
1720 uniformName = gl::StripLastArrayIndex(uniformName);
1721 }
1722
1723 gl::UniformLocation uniformLoc = program->getUniformLocation(uniformName);
1724 const gl::UniformTypeInfo *typeInfo = uniform.typeInfo;
1725 int componentCount = typeInfo->componentCount;
1726 int uniformSize = uniformCount * componentCount;
1727
1728 // For arrayed uniforms, we'll need to increment a read location
1729 gl::UniformLocation readLoc = uniformLoc;
1730
1731 // If the uniform is unused, just continue
1732 if (readLoc.value == -1)
1733 {
1734 continue;
1735 }
1736
1737 // Image uniforms are special and cannot be set this way
1738 if (typeInfo->isImageType)
1739 {
1740 continue;
1741 }
1742
1743 // Samplers should be populated with GL_INT, regardless of return type
1744 if (typeInfo->isSampler)
1745 {
1746 std::vector<GLint> uniformBuffer(uniformSize);
1747 for (int index = 0; index < uniformCount; index++, readLoc.value++)
1748 {
1749 program->getUniformiv(context, readLoc,
1750 uniformBuffer.data() + index * componentCount);
1751 }
1752
1753 Capture(callsOut, CaptureUniform1iv(replayState, true, uniformLoc, uniformCount,
1754 uniformBuffer.data()));
1755
1756 continue;
1757 }
1758
1759 switch (typeInfo->componentType)
1760 {
1761 case GL_FLOAT:
1762 {
1763 std::vector<GLfloat> uniformBuffer(uniformSize);
1764 for (int index = 0; index < uniformCount; index++, readLoc.value++)
1765 {
1766 program->getUniformfv(context, readLoc,
1767 uniformBuffer.data() + index * componentCount);
1768 }
1769 switch (typeInfo->type)
1770 {
1771 // Note: All matrix uniforms are populated without transpose
1772 case GL_FLOAT_MAT4x3:
1773 Capture(callsOut, CaptureUniformMatrix4x3fv(replayState, true, uniformLoc,
1774 uniformCount, false,
1775 uniformBuffer.data()));
1776 break;
1777 case GL_FLOAT_MAT4x2:
1778 Capture(callsOut, CaptureUniformMatrix4x2fv(replayState, true, uniformLoc,
1779 uniformCount, false,
1780 uniformBuffer.data()));
1781 break;
1782 case GL_FLOAT_MAT4:
1783 Capture(callsOut,
1784 CaptureUniformMatrix4fv(replayState, true, uniformLoc, uniformCount,
1785 false, uniformBuffer.data()));
1786 break;
1787 case GL_FLOAT_MAT3x4:
1788 Capture(callsOut, CaptureUniformMatrix3x4fv(replayState, true, uniformLoc,
1789 uniformCount, false,
1790 uniformBuffer.data()));
1791 break;
1792 case GL_FLOAT_MAT3x2:
1793 Capture(callsOut, CaptureUniformMatrix3x2fv(replayState, true, uniformLoc,
1794 uniformCount, false,
1795 uniformBuffer.data()));
1796 break;
1797 case GL_FLOAT_MAT3:
1798 Capture(callsOut,
1799 CaptureUniformMatrix3fv(replayState, true, uniformLoc, uniformCount,
1800 false, uniformBuffer.data()));
1801 break;
1802 case GL_FLOAT_MAT2x4:
1803 Capture(callsOut, CaptureUniformMatrix2x4fv(replayState, true, uniformLoc,
1804 uniformCount, false,
1805 uniformBuffer.data()));
1806 break;
1807 case GL_FLOAT_MAT2x3:
1808 Capture(callsOut, CaptureUniformMatrix2x3fv(replayState, true, uniformLoc,
1809 uniformCount, false,
1810 uniformBuffer.data()));
1811 break;
1812 case GL_FLOAT_MAT2:
1813 Capture(callsOut,
1814 CaptureUniformMatrix2fv(replayState, true, uniformLoc, uniformCount,
1815 false, uniformBuffer.data()));
1816 break;
1817 case GL_FLOAT_VEC4:
1818 Capture(callsOut, CaptureUniform4fv(replayState, true, uniformLoc,
1819 uniformCount, uniformBuffer.data()));
1820 break;
1821 case GL_FLOAT_VEC3:
1822 Capture(callsOut, CaptureUniform3fv(replayState, true, uniformLoc,
1823 uniformCount, uniformBuffer.data()));
1824 break;
1825 case GL_FLOAT_VEC2:
1826 Capture(callsOut, CaptureUniform2fv(replayState, true, uniformLoc,
1827 uniformCount, uniformBuffer.data()));
1828 break;
1829 case GL_FLOAT:
1830 Capture(callsOut, CaptureUniform1fv(replayState, true, uniformLoc,
1831 uniformCount, uniformBuffer.data()));
1832 break;
1833 default:
1834 UNIMPLEMENTED();
1835 break;
1836 }
1837 break;
1838 }
1839 case GL_INT:
1840 {
1841 std::vector<GLint> uniformBuffer(uniformSize);
1842 for (int index = 0; index < uniformCount; index++, readLoc.value++)
1843 {
1844 program->getUniformiv(context, readLoc,
1845 uniformBuffer.data() + index * componentCount);
1846 }
1847 switch (componentCount)
1848 {
1849 case 4:
1850 Capture(callsOut, CaptureUniform4iv(replayState, true, uniformLoc,
1851 uniformCount, uniformBuffer.data()));
1852 break;
1853 case 3:
1854 Capture(callsOut, CaptureUniform3iv(replayState, true, uniformLoc,
1855 uniformCount, uniformBuffer.data()));
1856 break;
1857 case 2:
1858 Capture(callsOut, CaptureUniform2iv(replayState, true, uniformLoc,
1859 uniformCount, uniformBuffer.data()));
1860 break;
1861 case 1:
1862 Capture(callsOut, CaptureUniform1iv(replayState, true, uniformLoc,
1863 uniformCount, uniformBuffer.data()));
1864 break;
1865 default:
1866 UNIMPLEMENTED();
1867 break;
1868 }
1869 break;
1870 }
1871 case GL_BOOL:
1872 case GL_UNSIGNED_INT:
1873 {
1874 std::vector<GLuint> uniformBuffer(uniformSize);
1875 for (int index = 0; index < uniformCount; index++, readLoc.value++)
1876 {
1877 program->getUniformuiv(context, readLoc,
1878 uniformBuffer.data() + index * componentCount);
1879 }
1880 switch (componentCount)
1881 {
1882 case 4:
1883 Capture(callsOut, CaptureUniform4uiv(replayState, true, uniformLoc,
1884 uniformCount, uniformBuffer.data()));
1885 break;
1886 case 3:
1887 Capture(callsOut, CaptureUniform3uiv(replayState, true, uniformLoc,
1888 uniformCount, uniformBuffer.data()));
1889 break;
1890 case 2:
1891 Capture(callsOut, CaptureUniform2uiv(replayState, true, uniformLoc,
1892 uniformCount, uniformBuffer.data()));
1893 break;
1894 case 1:
1895 Capture(callsOut, CaptureUniform1uiv(replayState, true, uniformLoc,
1896 uniformCount, uniformBuffer.data()));
1897 break;
1898 default:
1899 UNIMPLEMENTED();
1900 break;
1901 }
1902 break;
1903 }
1904 default:
1905 UNIMPLEMENTED();
1906 break;
1907 }
1908 }
1909 }
1910
CaptureVertexPointerES1(std::vector<CallCapture> * setupCalls,gl::State * replayState,GLuint attribIndex,const gl::VertexAttribute & attrib,const gl::VertexBinding & binding)1911 void CaptureVertexPointerES1(std::vector<CallCapture> *setupCalls,
1912 gl::State *replayState,
1913 GLuint attribIndex,
1914 const gl::VertexAttribute &attrib,
1915 const gl::VertexBinding &binding)
1916 {
1917 switch (gl::GLES1Renderer::VertexArrayType(attribIndex))
1918 {
1919 case gl::ClientVertexArrayType::Vertex:
1920 Capture(setupCalls,
1921 CaptureVertexPointer(*replayState, true, attrib.format->channelCount,
1922 attrib.format->vertexAttribType, binding.getStride(),
1923 attrib.pointer));
1924 break;
1925 case gl::ClientVertexArrayType::Normal:
1926 Capture(setupCalls,
1927 CaptureNormalPointer(*replayState, true, attrib.format->vertexAttribType,
1928 binding.getStride(), attrib.pointer));
1929 break;
1930 case gl::ClientVertexArrayType::Color:
1931 Capture(setupCalls, CaptureColorPointer(*replayState, true, attrib.format->channelCount,
1932 attrib.format->vertexAttribType,
1933 binding.getStride(), attrib.pointer));
1934 break;
1935 case gl::ClientVertexArrayType::PointSize:
1936 Capture(setupCalls,
1937 CapturePointSizePointerOES(*replayState, true, attrib.format->vertexAttribType,
1938 binding.getStride(), attrib.pointer));
1939 break;
1940 case gl::ClientVertexArrayType::TextureCoord:
1941 Capture(setupCalls,
1942 CaptureTexCoordPointer(*replayState, true, attrib.format->channelCount,
1943 attrib.format->vertexAttribType, binding.getStride(),
1944 attrib.pointer));
1945 break;
1946 default:
1947 UNREACHABLE();
1948 }
1949 }
1950
CaptureVertexArrayData(std::vector<CallCapture> * setupCalls,const gl::Context * context,const gl::VertexArray * vertexArray,gl::State * replayState)1951 void CaptureVertexArrayData(std::vector<CallCapture> *setupCalls,
1952 const gl::Context *context,
1953 const gl::VertexArray *vertexArray,
1954 gl::State *replayState)
1955 {
1956 const std::vector<gl::VertexAttribute> &vertexAttribs = vertexArray->getVertexAttributes();
1957 const std::vector<gl::VertexBinding> &vertexBindings = vertexArray->getVertexBindings();
1958
1959 for (GLuint attribIndex = 0; attribIndex < gl::MAX_VERTEX_ATTRIBS; ++attribIndex)
1960 {
1961 const gl::VertexAttribute defaultAttrib(attribIndex);
1962 const gl::VertexBinding defaultBinding;
1963
1964 const gl::VertexAttribute &attrib = vertexAttribs[attribIndex];
1965 const gl::VertexBinding &binding = vertexBindings[attrib.bindingIndex];
1966
1967 if (attrib.enabled != defaultAttrib.enabled)
1968 {
1969 if (context->isGLES1())
1970 {
1971 Capture(setupCalls,
1972 CaptureEnableClientState(*replayState, false,
1973 gl::GLES1Renderer::VertexArrayType(attribIndex)));
1974 }
1975 else
1976 {
1977 Capture(setupCalls,
1978 CaptureEnableVertexAttribArray(*replayState, false, attribIndex));
1979 }
1980 }
1981
1982 if (attrib.format != defaultAttrib.format || attrib.pointer != defaultAttrib.pointer ||
1983 binding.getStride() != defaultBinding.getStride() ||
1984 binding.getBuffer().get() != nullptr)
1985 {
1986 // Each attribute can pull from a separate buffer, so check the binding
1987 gl::Buffer *buffer = binding.getBuffer().get();
1988 if (buffer && buffer != replayState->getArrayBuffer())
1989 {
1990 replayState->setBufferBinding(context, gl::BufferBinding::Array, buffer);
1991
1992 Capture(setupCalls, CaptureBindBuffer(*replayState, true, gl::BufferBinding::Array,
1993 buffer->id()));
1994 }
1995
1996 // Establish the relationship between currently bound buffer and the VAO
1997 if (context->isGLES1())
1998 {
1999 CaptureVertexPointerES1(setupCalls, replayState, attribIndex, attrib, binding);
2000 }
2001 else
2002 {
2003 Capture(setupCalls,
2004 CaptureVertexAttribPointer(
2005 *replayState, true, attribIndex, attrib.format->channelCount,
2006 attrib.format->vertexAttribType, attrib.format->isNorm(),
2007 binding.getStride(), attrib.pointer));
2008 }
2009 }
2010
2011 if (binding.getDivisor() != 0)
2012 {
2013 Capture(setupCalls, CaptureVertexAttribDivisor(*replayState, true, attribIndex,
2014 binding.getDivisor()));
2015 }
2016 }
2017
2018 // The element array buffer is not per attribute, but per VAO
2019 gl::Buffer *elementArrayBuffer = vertexArray->getElementArrayBuffer();
2020 if (elementArrayBuffer)
2021 {
2022 Capture(setupCalls, CaptureBindBuffer(*replayState, true, gl::BufferBinding::ElementArray,
2023 elementArrayBuffer->id()));
2024 }
2025 }
2026
CaptureTextureStorage(std::vector<CallCapture> * setupCalls,gl::State * replayState,const gl::Texture * texture)2027 void CaptureTextureStorage(std::vector<CallCapture> *setupCalls,
2028 gl::State *replayState,
2029 const gl::Texture *texture)
2030 {
2031 // Use mip-level 0 for the base dimensions
2032 gl::ImageIndex imageIndex = gl::ImageIndex::MakeFromType(texture->getType(), 0);
2033 const gl::ImageDesc &desc = texture->getTextureState().getImageDesc(imageIndex);
2034
2035 switch (texture->getType())
2036 {
2037 case gl::TextureType::_2D:
2038 case gl::TextureType::CubeMap:
2039 {
2040 Capture(setupCalls, CaptureTexStorage2D(*replayState, true, texture->getType(),
2041 texture->getImmutableLevels(),
2042 desc.format.info->internalFormat,
2043 desc.size.width, desc.size.height));
2044 break;
2045 }
2046 case gl::TextureType::_3D:
2047 case gl::TextureType::_2DArray:
2048 case gl::TextureType::CubeMapArray:
2049 {
2050 Capture(setupCalls, CaptureTexStorage3D(
2051 *replayState, true, texture->getType(),
2052 texture->getImmutableLevels(), desc.format.info->internalFormat,
2053 desc.size.width, desc.size.height, desc.size.depth));
2054 break;
2055 }
2056 case gl::TextureType::Buffer:
2057 {
2058 // Do nothing. This will already be captured as a buffer.
2059 break;
2060 }
2061 default:
2062 UNIMPLEMENTED();
2063 break;
2064 }
2065 }
2066
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)2067 void CaptureTextureContents(std::vector<CallCapture> *setupCalls,
2068 gl::State *replayState,
2069 const gl::Texture *texture,
2070 const gl::ImageIndex &index,
2071 const gl::ImageDesc &desc,
2072 GLuint size,
2073 const void *data)
2074 {
2075 const gl::InternalFormat &format = *desc.format.info;
2076
2077 if (index.getType() == gl::TextureType::Buffer)
2078 {
2079 // Zero binding size indicates full buffer bound
2080 if (texture->getBuffer().getSize() == 0)
2081 {
2082 Capture(setupCalls,
2083 CaptureTexBufferEXT(*replayState, true, index.getType(), format.internalFormat,
2084 texture->getBuffer().get()->id()));
2085 }
2086 else
2087 {
2088 Capture(setupCalls, CaptureTexBufferRangeEXT(*replayState, true, index.getType(),
2089 format.internalFormat,
2090 texture->getBuffer().get()->id(),
2091 texture->getBuffer().getOffset(),
2092 texture->getBuffer().getSize()));
2093 }
2094
2095 // For buffers, we're done
2096 return;
2097 }
2098
2099 bool is3D =
2100 (index.getType() == gl::TextureType::_3D || index.getType() == gl::TextureType::_2DArray ||
2101 index.getType() == gl::TextureType::CubeMapArray);
2102
2103 if (format.compressed)
2104 {
2105 if (is3D)
2106 {
2107 if (texture->getImmutableFormat())
2108 {
2109 Capture(setupCalls,
2110 CaptureCompressedTexSubImage3D(
2111 *replayState, true, index.getTarget(), index.getLevelIndex(), 0, 0, 0,
2112 desc.size.width, desc.size.height, desc.size.depth,
2113 format.internalFormat, size, data));
2114 }
2115 else
2116 {
2117 Capture(setupCalls,
2118 CaptureCompressedTexImage3D(*replayState, true, index.getTarget(),
2119 index.getLevelIndex(), format.internalFormat,
2120 desc.size.width, desc.size.height,
2121 desc.size.depth, 0, size, data));
2122 }
2123 }
2124 else
2125 {
2126 if (texture->getImmutableFormat())
2127 {
2128 Capture(setupCalls,
2129 CaptureCompressedTexSubImage2D(
2130 *replayState, true, index.getTarget(), index.getLevelIndex(), 0, 0,
2131 desc.size.width, desc.size.height, format.internalFormat, size, data));
2132 }
2133 else
2134 {
2135 Capture(setupCalls, CaptureCompressedTexImage2D(
2136 *replayState, true, index.getTarget(),
2137 index.getLevelIndex(), format.internalFormat,
2138 desc.size.width, desc.size.height, 0, size, data));
2139 }
2140 }
2141 }
2142 else
2143 {
2144 if (is3D)
2145 {
2146 if (texture->getImmutableFormat())
2147 {
2148 Capture(setupCalls,
2149 CaptureTexSubImage3D(*replayState, true, index.getTarget(),
2150 index.getLevelIndex(), 0, 0, 0, desc.size.width,
2151 desc.size.height, desc.size.depth, format.format,
2152 format.type, data));
2153 }
2154 else
2155 {
2156 Capture(
2157 setupCalls,
2158 CaptureTexImage3D(*replayState, true, index.getTarget(), index.getLevelIndex(),
2159 format.internalFormat, desc.size.width, desc.size.height,
2160 desc.size.depth, 0, format.format, format.type, data));
2161 }
2162 }
2163 else
2164 {
2165 if (texture->getImmutableFormat())
2166 {
2167 Capture(setupCalls,
2168 CaptureTexSubImage2D(*replayState, true, index.getTarget(),
2169 index.getLevelIndex(), 0, 0, desc.size.width,
2170 desc.size.height, format.format, format.type, data));
2171 }
2172 else
2173 {
2174 Capture(setupCalls, CaptureTexImage2D(*replayState, true, index.getTarget(),
2175 index.getLevelIndex(), format.internalFormat,
2176 desc.size.width, desc.size.height, 0,
2177 format.format, format.type, data));
2178 }
2179 }
2180 }
2181 }
2182
2183 // TODO(http://anglebug.com/4599): Improve reset/restore call generation
2184 // There are multiple ways to track reset calls for individual resources. For now, we are tracking
2185 // separate lists of instructions that mirror the calls created during mid-execution setup. Other
2186 // methods could involve passing the original CallCaptures to this function, or tracking the
2187 // indices of original setup calls.
CaptureBufferResetCalls(const gl::State & replayState,ResourceTracker * resourceTracker,gl::BufferID * id,const gl::Buffer * buffer)2188 void CaptureBufferResetCalls(const gl::State &replayState,
2189 ResourceTracker *resourceTracker,
2190 gl::BufferID *id,
2191 const gl::Buffer *buffer)
2192 {
2193 // Track this as a starting resource that may need to be restored.
2194 BufferSet &startingBuffers = resourceTracker->getStartingBuffers();
2195 startingBuffers.insert(*id);
2196
2197 // Track calls to regenerate a given buffer
2198 BufferCalls &bufferRegenCalls = resourceTracker->getBufferRegenCalls();
2199 Capture(&bufferRegenCalls[*id], CaptureDeleteBuffers(replayState, true, 1, id));
2200 Capture(&bufferRegenCalls[*id], CaptureGenBuffers(replayState, true, 1, id));
2201 MaybeCaptureUpdateResourceIDs(&bufferRegenCalls[*id]);
2202
2203 // Track calls to restore a given buffer's contents
2204 BufferCalls &bufferRestoreCalls = resourceTracker->getBufferRestoreCalls();
2205 Capture(&bufferRestoreCalls[*id],
2206 CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, *id));
2207 Capture(&bufferRestoreCalls[*id],
2208 CaptureBufferData(replayState, true, gl::BufferBinding::Array,
2209 static_cast<GLsizeiptr>(buffer->getSize()), buffer->getMapPointer(),
2210 buffer->getUsage()));
2211
2212 if (buffer->isMapped())
2213 {
2214 // Track calls to remap a buffer that started as mapped
2215 BufferCalls &bufferMapCalls = resourceTracker->getBufferMapCalls();
2216
2217 Capture(&bufferMapCalls[*id],
2218 CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, *id));
2219
2220 void *dontCare = nullptr;
2221 Capture(&bufferMapCalls[*id],
2222 CaptureMapBufferRange(replayState, true, gl::BufferBinding::Array,
2223 static_cast<GLsizeiptr>(buffer->getMapOffset()),
2224 static_cast<GLsizeiptr>(buffer->getMapLength()),
2225 buffer->getAccessFlags(), dontCare));
2226
2227 // Track the bufferID that was just mapped
2228 bufferMapCalls[*id].back().params.setMappedBufferID(buffer->id());
2229 }
2230
2231 // Track calls unmap a buffer that started as unmapped
2232 BufferCalls &bufferUnmapCalls = resourceTracker->getBufferUnmapCalls();
2233 Capture(&bufferUnmapCalls[*id],
2234 CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, *id));
2235 Capture(&bufferUnmapCalls[*id],
2236 CaptureUnmapBuffer(replayState, true, gl::BufferBinding::Array, GL_TRUE));
2237 }
2238
CaptureFenceSyncResetCalls(const gl::State & replayState,ResourceTracker * resourceTracker,GLsync syncID,const gl::Sync * sync)2239 void CaptureFenceSyncResetCalls(const gl::State &replayState,
2240 ResourceTracker *resourceTracker,
2241 GLsync syncID,
2242 const gl::Sync *sync)
2243 {
2244 // Track calls to regenerate a given fence sync
2245 FenceSyncCalls &fenceSyncRegenCalls = resourceTracker->getFenceSyncRegenCalls();
2246 Capture(&fenceSyncRegenCalls[syncID],
2247 CaptureFenceSync(replayState, true, sync->getCondition(), sync->getFlags(), syncID));
2248 MaybeCaptureUpdateResourceIDs(&fenceSyncRegenCalls[syncID]);
2249 }
2250
CaptureBufferBindingResetCalls(const gl::State & replayState,ResourceTracker * resourceTracker,gl::BufferBinding binding,gl::BufferID id)2251 void CaptureBufferBindingResetCalls(const gl::State &replayState,
2252 ResourceTracker *resourceTracker,
2253 gl::BufferBinding binding,
2254 gl::BufferID id)
2255 {
2256 std::vector<CallCapture> &bufferBindingCalls = resourceTracker->getBufferBindingCalls();
2257 Capture(&bufferBindingCalls, CaptureBindBuffer(replayState, true, binding, id));
2258 }
2259
CaptureIndexedBuffers(const gl::State & glState,const gl::BufferVector & indexedBuffers,gl::BufferBinding binding,std::vector<CallCapture> * setupCalls)2260 void CaptureIndexedBuffers(const gl::State &glState,
2261 const gl::BufferVector &indexedBuffers,
2262 gl::BufferBinding binding,
2263 std::vector<CallCapture> *setupCalls)
2264 {
2265 for (unsigned int index = 0; index < indexedBuffers.size(); ++index)
2266 {
2267 const gl::OffsetBindingPointer<gl::Buffer> &buffer = indexedBuffers[index];
2268
2269 if (buffer.get() == nullptr)
2270 {
2271 continue;
2272 }
2273
2274 GLintptr offset = buffer.getOffset();
2275 GLsizeiptr size = buffer.getSize();
2276 gl::BufferID bufferID = buffer.get()->id();
2277
2278 // Context::bindBufferBase() calls Context::bindBufferRange() with size and offset = 0.
2279 if ((offset == 0) && (size == 0))
2280 {
2281 Capture(setupCalls, CaptureBindBufferBase(glState, true, binding, index, bufferID));
2282 }
2283 else
2284 {
2285 Capture(setupCalls,
2286 CaptureBindBufferRange(glState, true, binding, index, bufferID, offset, size));
2287 }
2288 }
2289 }
2290
CaptureDefaultVertexAttribs(const gl::State & replayState,const gl::State & apiState,std::vector<CallCapture> * setupCalls)2291 void CaptureDefaultVertexAttribs(const gl::State &replayState,
2292 const gl::State &apiState,
2293 std::vector<CallCapture> *setupCalls)
2294 {
2295 const std::vector<gl::VertexAttribCurrentValueData> ¤tValues =
2296 apiState.getVertexAttribCurrentValues();
2297
2298 for (GLuint attribIndex = 0; attribIndex < gl::MAX_VERTEX_ATTRIBS; ++attribIndex)
2299 {
2300 const gl::VertexAttribCurrentValueData &defaultValue = currentValues[attribIndex];
2301 if (!IsDefaultCurrentValue(defaultValue))
2302 {
2303 Capture(setupCalls, CaptureVertexAttrib4fv(replayState, true, attribIndex,
2304 defaultValue.Values.FloatValues));
2305 }
2306 }
2307 }
2308
2309 // Capture the setup of the state that's shared by all of the contexts in the share group:
2310 // OpenGL ES Version 3.2 (October 22, 2019)
2311 // Chapter 5 Shared Objects and Multiple Contexts
2312 // Objects that can be shared between contexts include buffer objects, program
2313 // and shader objects, renderbuffer objects, sampler objects, sync objects, and texture
2314 // objects (except for the texture objects named zero).
2315 // Objects which contain references to other objects include framebuffer, program
2316 // pipeline, transform feedback, and vertex array objects. Such objects are called
2317 // container objects and are not shared.
CaptureSharedContextMidExecutionSetup(const gl::Context * context,std::vector<CallCapture> * setupCalls,ResourceTracker * resourceTracker)2318 void CaptureSharedContextMidExecutionSetup(const gl::Context *context,
2319 std::vector<CallCapture> *setupCalls,
2320 ResourceTracker *resourceTracker)
2321 {
2322
2323 FrameCaptureShared *frameCaptureShared = context->getShareGroup()->getFrameCaptureShared();
2324 const gl::State &apiState = context->getState();
2325 gl::State replayState(nullptr, nullptr, nullptr, nullptr, nullptr, EGL_OPENGL_ES_API,
2326 apiState.getClientVersion(), false, true, true, true, false,
2327 EGL_CONTEXT_PRIORITY_MEDIUM_IMG, apiState.hasProtectedContent());
2328
2329 // Small helper function to make the code more readable.
2330 auto cap = [frameCaptureShared, setupCalls](CallCapture &&call) {
2331 frameCaptureShared->updateReadBufferSize(call.params.getReadBufferSize());
2332 setupCalls->emplace_back(std::move(call));
2333 };
2334
2335 // Capture Buffer data.
2336 const gl::BufferManager &buffers = apiState.getBufferManagerForCapture();
2337 for (const auto &bufferIter : buffers)
2338 {
2339 gl::BufferID id = {bufferIter.first};
2340 gl::Buffer *buffer = bufferIter.second;
2341
2342 if (id.value == 0)
2343 {
2344 continue;
2345 }
2346
2347 // glBufferData. Would possibly be better implemented using a getData impl method.
2348 // Saving buffers that are mapped during a swap is not yet handled.
2349 if (buffer->getSize() == 0)
2350 {
2351 continue;
2352 }
2353
2354 // Remember if the buffer was already mapped
2355 GLboolean bufferMapped = buffer->isMapped();
2356
2357 // If needed, map the buffer so we can capture its contents
2358 if (!bufferMapped)
2359 {
2360 (void)buffer->mapRange(context, 0, static_cast<GLsizeiptr>(buffer->getSize()),
2361 GL_MAP_READ_BIT);
2362 }
2363
2364 // Generate binding.
2365 cap(CaptureGenBuffers(replayState, true, 1, &id));
2366 MaybeCaptureUpdateResourceIDs(setupCalls);
2367
2368 // Always use the array buffer binding point to upload data to keep things simple.
2369 if (buffer != replayState.getArrayBuffer())
2370 {
2371 replayState.setBufferBinding(context, gl::BufferBinding::Array, buffer);
2372 cap(CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, id));
2373 }
2374
2375 if (buffer->isImmutable())
2376 {
2377 cap(CaptureBufferStorageEXT(replayState, true, gl::BufferBinding::Array,
2378 static_cast<GLsizeiptr>(buffer->getSize()),
2379 buffer->getMapPointer(),
2380 buffer->getStorageExtUsageFlags()));
2381 }
2382 else
2383 {
2384 cap(CaptureBufferData(replayState, true, gl::BufferBinding::Array,
2385 static_cast<GLsizeiptr>(buffer->getSize()),
2386 buffer->getMapPointer(), buffer->getUsage()));
2387 }
2388
2389 if (bufferMapped)
2390 {
2391 void *dontCare = nullptr;
2392 Capture(setupCalls,
2393 CaptureMapBufferRange(replayState, true, gl::BufferBinding::Array,
2394 static_cast<GLsizeiptr>(buffer->getMapOffset()),
2395 static_cast<GLsizeiptr>(buffer->getMapLength()),
2396 buffer->getAccessFlags(), dontCare));
2397
2398 resourceTracker->setStartingBufferMapped(buffer->id(), true);
2399
2400 frameCaptureShared->trackBufferMapping(
2401 &setupCalls->back(), buffer->id(), static_cast<GLsizeiptr>(buffer->getMapOffset()),
2402 static_cast<GLsizeiptr>(buffer->getMapLength()),
2403 (buffer->getAccessFlags() & GL_MAP_WRITE_BIT) != 0);
2404 }
2405 else
2406 {
2407 resourceTracker->setStartingBufferMapped(buffer->id(), false);
2408 }
2409
2410 // Generate the calls needed to restore this buffer to original state for frame looping
2411 CaptureBufferResetCalls(replayState, resourceTracker, &id, buffer);
2412
2413 // Unmap the buffer if it wasn't already mapped
2414 if (!bufferMapped)
2415 {
2416 GLboolean dontCare;
2417 (void)buffer->unmap(context, &dontCare);
2418 }
2419 }
2420
2421 // Capture Texture setup and data.
2422 const gl::TextureManager &textures = apiState.getTextureManagerForCapture();
2423
2424 for (const auto &textureIter : textures)
2425 {
2426 gl::TextureID id = {textureIter.first};
2427 gl::Texture *texture = textureIter.second;
2428
2429 if (id.value == 0)
2430 {
2431 continue;
2432 }
2433
2434 // Gen the Texture.
2435 cap(CaptureGenTextures(replayState, true, 1, &id));
2436 MaybeCaptureUpdateResourceIDs(setupCalls);
2437
2438 cap(CaptureBindTexture(replayState, true, texture->getType(), id));
2439
2440 // Capture sampler parameter states.
2441 // TODO(jmadill): More sampler / texture states. http://anglebug.com/3662
2442 gl::SamplerState defaultSamplerState =
2443 gl::SamplerState::CreateDefaultForTarget(texture->getType());
2444 const gl::SamplerState &textureSamplerState = texture->getSamplerState();
2445
2446 auto capTexParam = [cap, &replayState, texture](GLenum pname, GLint param) {
2447 cap(CaptureTexParameteri(replayState, true, texture->getType(), pname, param));
2448 };
2449
2450 auto capTexParamf = [cap, &replayState, texture](GLenum pname, GLfloat param) {
2451 cap(CaptureTexParameterf(replayState, true, texture->getType(), pname, param));
2452 };
2453
2454 if (textureSamplerState.getMinFilter() != defaultSamplerState.getMinFilter())
2455 {
2456 capTexParam(GL_TEXTURE_MIN_FILTER, textureSamplerState.getMinFilter());
2457 }
2458
2459 if (textureSamplerState.getMagFilter() != defaultSamplerState.getMagFilter())
2460 {
2461 capTexParam(GL_TEXTURE_MAG_FILTER, textureSamplerState.getMagFilter());
2462 }
2463
2464 if (textureSamplerState.getWrapR() != defaultSamplerState.getWrapR())
2465 {
2466 capTexParam(GL_TEXTURE_WRAP_R, textureSamplerState.getWrapR());
2467 }
2468
2469 if (textureSamplerState.getWrapS() != defaultSamplerState.getWrapS())
2470 {
2471 capTexParam(GL_TEXTURE_WRAP_S, textureSamplerState.getWrapS());
2472 }
2473
2474 if (textureSamplerState.getWrapT() != defaultSamplerState.getWrapT())
2475 {
2476 capTexParam(GL_TEXTURE_WRAP_T, textureSamplerState.getWrapT());
2477 }
2478
2479 if (textureSamplerState.getMinLod() != defaultSamplerState.getMinLod())
2480 {
2481 capTexParamf(GL_TEXTURE_MIN_LOD, textureSamplerState.getMinLod());
2482 }
2483
2484 if (textureSamplerState.getMaxLod() != defaultSamplerState.getMaxLod())
2485 {
2486 capTexParamf(GL_TEXTURE_MAX_LOD, textureSamplerState.getMaxLod());
2487 }
2488
2489 if (textureSamplerState.getCompareMode() != defaultSamplerState.getCompareMode())
2490 {
2491 capTexParam(GL_TEXTURE_COMPARE_MODE, textureSamplerState.getCompareMode());
2492 }
2493
2494 if (textureSamplerState.getCompareFunc() != defaultSamplerState.getCompareFunc())
2495 {
2496 capTexParam(GL_TEXTURE_COMPARE_FUNC, textureSamplerState.getCompareFunc());
2497 }
2498
2499 // Texture parameters
2500 if (texture->getSwizzleRed() != GL_RED)
2501 {
2502 capTexParam(GL_TEXTURE_SWIZZLE_R, texture->getSwizzleRed());
2503 }
2504
2505 if (texture->getSwizzleGreen() != GL_GREEN)
2506 {
2507 capTexParam(GL_TEXTURE_SWIZZLE_G, texture->getSwizzleGreen());
2508 }
2509
2510 if (texture->getSwizzleBlue() != GL_BLUE)
2511 {
2512 capTexParam(GL_TEXTURE_SWIZZLE_B, texture->getSwizzleBlue());
2513 }
2514
2515 if (texture->getSwizzleAlpha() != GL_ALPHA)
2516 {
2517 capTexParam(GL_TEXTURE_SWIZZLE_A, texture->getSwizzleAlpha());
2518 }
2519
2520 if (texture->getBaseLevel() != 0)
2521 {
2522 capTexParam(GL_TEXTURE_BASE_LEVEL, texture->getBaseLevel());
2523 }
2524
2525 if (texture->getMaxLevel() != 1000)
2526 {
2527 capTexParam(GL_TEXTURE_MAX_LEVEL, texture->getMaxLevel());
2528 }
2529
2530 // If the texture is immutable, initialize it with TexStorage
2531 if (texture->getImmutableFormat())
2532 {
2533 CaptureTextureStorage(setupCalls, &replayState, texture);
2534 }
2535
2536 // Iterate texture levels and layers.
2537 gl::ImageIndexIterator imageIter = gl::ImageIndexIterator::MakeGeneric(
2538 texture->getType(), 0, texture->getMipmapMaxLevel() + 1, gl::ImageIndex::kEntireLevel,
2539 gl::ImageIndex::kEntireLevel);
2540 while (imageIter.hasNext())
2541 {
2542 gl::ImageIndex index = imageIter.next();
2543
2544 const gl::ImageDesc &desc = texture->getTextureState().getImageDesc(index);
2545
2546 if (desc.size.empty())
2547 {
2548 continue;
2549 }
2550
2551 const gl::InternalFormat &format = *desc.format.info;
2552
2553 // Check for supported textures
2554 ASSERT(index.getType() == gl::TextureType::_2D ||
2555 index.getType() == gl::TextureType::_3D ||
2556 index.getType() == gl::TextureType::_2DArray ||
2557 index.getType() == gl::TextureType::Buffer ||
2558 index.getType() == gl::TextureType::CubeMap ||
2559 index.getType() == gl::TextureType::CubeMapArray);
2560
2561 if (index.getType() == gl::TextureType::Buffer)
2562 {
2563 // The buffer contents are already backed up, but we need to emit the TexBuffer
2564 // binding calls
2565 CaptureTextureContents(setupCalls, &replayState, texture, index, desc, 0, 0);
2566
2567 continue;
2568 }
2569
2570 if (format.compressed)
2571 {
2572 // For compressed images, we've tracked a copy of the incoming data, so we can
2573 // use that rather than try to read data back that may have been converted.
2574 const std::vector<uint8_t> &capturedTextureLevel =
2575 context->getShareGroup()->getFrameCaptureShared()->retrieveCachedTextureLevel(
2576 texture->id(), index.getTarget(), index.getLevelIndex());
2577
2578 // Use the shadow copy of the data to populate the call
2579 CaptureTextureContents(setupCalls, &replayState, texture, index, desc,
2580 static_cast<GLuint>(capturedTextureLevel.size()),
2581 capturedTextureLevel.data());
2582 }
2583 else
2584 {
2585 // Use ANGLE_get_image to read back pixel data.
2586 if (context->getExtensions().getImageANGLE)
2587 {
2588 GLenum getFormat = format.format;
2589 GLenum getType = format.type;
2590
2591 angle::MemoryBuffer data;
2592
2593 const gl::Extents size(desc.size.width, desc.size.height, desc.size.depth);
2594 const gl::PixelUnpackState &unpack = apiState.getUnpackState();
2595
2596 GLuint endByte = 0;
2597 bool unpackSize =
2598 format.computePackUnpackEndByte(getType, size, unpack, true, &endByte);
2599 ASSERT(unpackSize);
2600
2601 bool result = data.resize(endByte);
2602 ASSERT(result);
2603
2604 gl::PixelPackState packState;
2605 packState.alignment = 1;
2606
2607 (void)texture->getTexImage(context, packState, nullptr, index.getTarget(),
2608 index.getLevelIndex(), getFormat, getType,
2609 data.data());
2610
2611 CaptureTextureContents(setupCalls, &replayState, texture, index, desc,
2612 static_cast<GLuint>(data.size()), data.data());
2613 }
2614 else
2615 {
2616 CaptureTextureContents(setupCalls, &replayState, texture, index, desc, 0,
2617 nullptr);
2618 }
2619 }
2620 }
2621 }
2622
2623 // Capture Renderbuffers.
2624 const gl::RenderbufferManager &renderbuffers = apiState.getRenderbufferManagerForCapture();
2625
2626 for (const auto &renderbufIter : renderbuffers)
2627 {
2628 gl::RenderbufferID id = {renderbufIter.first};
2629 const gl::Renderbuffer *renderbuffer = renderbufIter.second;
2630
2631 // Generate renderbuffer id.
2632 cap(CaptureGenRenderbuffers(replayState, true, 1, &id));
2633 MaybeCaptureUpdateResourceIDs(setupCalls);
2634 cap(CaptureBindRenderbuffer(replayState, true, GL_RENDERBUFFER, id));
2635
2636 GLenum internalformat = renderbuffer->getFormat().info->internalFormat;
2637
2638 if (renderbuffer->getSamples() > 0)
2639 {
2640 // Note: We could also use extensions if available.
2641 cap(CaptureRenderbufferStorageMultisample(
2642 replayState, true, GL_RENDERBUFFER, renderbuffer->getSamples(), internalformat,
2643 renderbuffer->getWidth(), renderbuffer->getHeight()));
2644 }
2645 else
2646 {
2647 cap(CaptureRenderbufferStorage(replayState, true, GL_RENDERBUFFER, internalformat,
2648 renderbuffer->getWidth(), renderbuffer->getHeight()));
2649 }
2650
2651 // TODO(jmadill): Capture renderbuffer contents. http://anglebug.com/3662
2652 }
2653
2654 // Capture Shaders and Programs.
2655 const gl::ShaderProgramManager &shadersAndPrograms =
2656 apiState.getShaderProgramManagerForCapture();
2657 const gl::ResourceMap<gl::Shader, gl::ShaderProgramID> &shaders =
2658 shadersAndPrograms.getShadersForCapture();
2659 const gl::ResourceMap<gl::Program, gl::ShaderProgramID> &programs =
2660 shadersAndPrograms.getProgramsForCaptureAndPerf();
2661
2662 // Capture Program binary state. Use max ID as a temporary shader ID.
2663 gl::ShaderProgramID tempShaderID = {resourceTracker->getMaxShaderPrograms()};
2664 for (const auto &programIter : programs)
2665 {
2666 gl::ShaderProgramID id = {programIter.first};
2667 const gl::Program *program = programIter.second;
2668
2669 // Unlinked programs don't have an executable. Thus they don't need to be captured.
2670 // Programs are shared by contexts in the share group and only need to be captured once.
2671 if (!program->isLinked())
2672 {
2673 continue;
2674 }
2675
2676 // Get last linked shader source.
2677 const ProgramSources &linkedSources =
2678 context->getShareGroup()->getFrameCaptureShared()->getProgramSources(id);
2679
2680 cap(CaptureCreateProgram(replayState, true, id.value));
2681
2682 // Compile with last linked sources.
2683 for (gl::ShaderType shaderType : program->getExecutable().getLinkedShaderStages())
2684 {
2685 const std::string &sourceString = linkedSources[shaderType];
2686 const char *sourcePointer = sourceString.c_str();
2687
2688 // Compile and attach the temporary shader. Then free it immediately.
2689 cap(CaptureCreateShader(replayState, true, shaderType, tempShaderID.value));
2690 cap(CaptureShaderSource(replayState, true, tempShaderID, 1, &sourcePointer, nullptr));
2691 cap(CaptureCompileShader(replayState, true, tempShaderID));
2692 cap(CaptureAttachShader(replayState, true, id, tempShaderID));
2693 cap(CaptureDeleteShader(replayState, true, tempShaderID));
2694 }
2695
2696 // Gather XFB varyings
2697 std::vector<std::string> xfbVaryings;
2698 for (const gl::TransformFeedbackVarying &xfbVarying :
2699 program->getState().getLinkedTransformFeedbackVaryings())
2700 {
2701 xfbVaryings.push_back(xfbVarying.nameWithArrayIndex());
2702 }
2703
2704 if (!xfbVaryings.empty())
2705 {
2706 std::vector<const char *> varyingsStrings;
2707 for (const std::string &varyingString : xfbVaryings)
2708 {
2709 varyingsStrings.push_back(varyingString.data());
2710 }
2711
2712 GLenum xfbMode = program->getState().getTransformFeedbackBufferMode();
2713 cap(CaptureTransformFeedbackVaryings(replayState, true, id,
2714 static_cast<GLint>(xfbVaryings.size()),
2715 varyingsStrings.data(), xfbMode));
2716 }
2717
2718 // Force the attributes to be bound the same way as in the existing program.
2719 // This can affect attributes that are optimized out in some implementations.
2720 for (const sh::ShaderVariable &attrib : program->getState().getProgramInputs())
2721 {
2722 if (gl::IsBuiltInName(attrib.name))
2723 {
2724 // Don't try to bind built-in attributes
2725 continue;
2726 }
2727
2728 // Separable programs may not have a VS, meaning it may not have attributes.
2729 if (program->getExecutable().hasLinkedShaderStage(gl::ShaderType::Vertex))
2730 {
2731 ASSERT(attrib.location != -1);
2732 cap(CaptureBindAttribLocation(replayState, true, id,
2733 static_cast<GLuint>(attrib.location),
2734 attrib.name.c_str()));
2735 }
2736 }
2737
2738 if (program->isSeparable())
2739 {
2740 // MEC manually recreates separable programs, rather than attempting to recreate a call
2741 // to glCreateShaderProgramv(), so insert a call to mark it separable.
2742 cap(CaptureProgramParameteri(replayState, true, id, GL_PROGRAM_SEPARABLE, GL_TRUE));
2743 }
2744
2745 cap(CaptureLinkProgram(replayState, true, id));
2746 CaptureUpdateUniformLocations(program, setupCalls);
2747 CaptureUpdateUniformValues(replayState, context, program, setupCalls);
2748 CaptureUpdateUniformBlockIndexes(program, setupCalls);
2749
2750 // Capture uniform block bindings for each program
2751 for (unsigned int uniformBlockIndex = 0;
2752 uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
2753 {
2754 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
2755 cap(CaptureUniformBlockBinding(replayState, true, id, {uniformBlockIndex},
2756 blockBinding));
2757 }
2758
2759 resourceTracker->onShaderProgramAccess(id);
2760 resourceTracker->getStartingPrograms().insert(id);
2761 }
2762
2763 // Handle shaders.
2764 for (const auto &shaderIter : shaders)
2765 {
2766 gl::ShaderProgramID id = {shaderIter.first};
2767 gl::Shader *shader = shaderIter.second;
2768
2769 // Skip shaders scheduled for deletion.
2770 // Shaders are shared by contexts in the share group and only need to be captured once.
2771 if (shader->hasBeenDeleted())
2772 {
2773 continue;
2774 }
2775
2776 cap(CaptureCreateShader(replayState, true, shader->getType(), id.value));
2777
2778 std::string shaderSource = shader->getSourceString();
2779 const char *sourcePointer = shaderSource.empty() ? nullptr : shaderSource.c_str();
2780
2781 // This does not handle some more tricky situations like attaching shaders to a non-linked
2782 // program. Or attaching uncompiled shaders. Or attaching and then deleting a shader.
2783 // TODO(jmadill): Handle trickier program uses. http://anglebug.com/3662
2784 if (shader->isCompiled())
2785 {
2786 const std::string &capturedSource =
2787 context->getShareGroup()->getFrameCaptureShared()->getShaderSource(id);
2788 if (capturedSource != shaderSource)
2789 {
2790 ASSERT(!capturedSource.empty());
2791 sourcePointer = capturedSource.c_str();
2792 }
2793
2794 cap(CaptureShaderSource(replayState, true, id, 1, &sourcePointer, nullptr));
2795 cap(CaptureCompileShader(replayState, true, id));
2796 }
2797
2798 if (sourcePointer && (!shader->isCompiled() || sourcePointer != shaderSource.c_str()))
2799 {
2800 cap(CaptureShaderSource(replayState, true, id, 1, &sourcePointer, nullptr));
2801 }
2802 }
2803
2804 // Capture Sampler Objects
2805 const gl::SamplerManager &samplers = apiState.getSamplerManagerForCapture();
2806 for (const auto &samplerIter : samplers)
2807 {
2808 gl::SamplerID samplerID = {samplerIter.first};
2809
2810 // Don't gen the sampler if we've seen it before, since they are shared across the context
2811 // share group.
2812 cap(CaptureGenSamplers(replayState, true, 1, &samplerID));
2813 MaybeCaptureUpdateResourceIDs(setupCalls);
2814
2815 gl::Sampler *sampler = samplerIter.second;
2816 if (!sampler)
2817 {
2818 continue;
2819 }
2820
2821 gl::SamplerState defaultSamplerState;
2822 if (sampler->getMinFilter() != defaultSamplerState.getMinFilter())
2823 {
2824 cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_MIN_FILTER,
2825 sampler->getMinFilter()));
2826 }
2827 if (sampler->getMagFilter() != defaultSamplerState.getMagFilter())
2828 {
2829 cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_MAG_FILTER,
2830 sampler->getMagFilter()));
2831 }
2832 if (sampler->getWrapS() != defaultSamplerState.getWrapS())
2833 {
2834 cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_WRAP_S,
2835 sampler->getWrapS()));
2836 }
2837 if (sampler->getWrapR() != defaultSamplerState.getWrapR())
2838 {
2839 cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_WRAP_R,
2840 sampler->getWrapR()));
2841 }
2842 if (sampler->getWrapT() != defaultSamplerState.getWrapT())
2843 {
2844 cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_WRAP_T,
2845 sampler->getWrapT()));
2846 }
2847 if (sampler->getMinLod() != defaultSamplerState.getMinLod())
2848 {
2849 cap(CaptureSamplerParameterf(replayState, true, samplerID, GL_TEXTURE_MIN_LOD,
2850 sampler->getMinLod()));
2851 }
2852 if (sampler->getMaxLod() != defaultSamplerState.getMaxLod())
2853 {
2854 cap(CaptureSamplerParameterf(replayState, true, samplerID, GL_TEXTURE_MAX_LOD,
2855 sampler->getMaxLod()));
2856 }
2857 if (sampler->getCompareMode() != defaultSamplerState.getCompareMode())
2858 {
2859 cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_COMPARE_MODE,
2860 sampler->getCompareMode()));
2861 }
2862 if (sampler->getCompareFunc() != defaultSamplerState.getCompareFunc())
2863 {
2864 cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_COMPARE_FUNC,
2865 sampler->getCompareFunc()));
2866 }
2867 }
2868
2869 // Capture Sync Objects
2870 const gl::SyncManager &syncs = apiState.getSyncManagerForCapture();
2871 for (const auto &syncIter : syncs)
2872 {
2873 GLsync syncID = gl::bitCast<GLsync>(static_cast<size_t>(syncIter.first));
2874 const gl::Sync *sync = syncIter.second;
2875
2876 if (!sync)
2877 {
2878 continue;
2879 }
2880 cap(CaptureFenceSync(replayState, true, sync->getCondition(), sync->getFlags(), syncID));
2881 CaptureFenceSyncResetCalls(replayState, resourceTracker, syncID, sync);
2882 resourceTracker->getStartingFenceSyncs().insert(syncID);
2883 }
2884
2885 // Allow the replayState object to be destroyed conveniently.
2886 replayState.setBufferBinding(context, gl::BufferBinding::Array, nullptr);
2887 }
2888
CaptureMidExecutionSetup(const gl::Context * context,std::vector<CallCapture> * setupCalls,ResourceTracker * resourceTracker)2889 void CaptureMidExecutionSetup(const gl::Context *context,
2890 std::vector<CallCapture> *setupCalls,
2891 ResourceTracker *resourceTracker)
2892 {
2893 const gl::State &apiState = context->getState();
2894 gl::State replayState(nullptr, nullptr, nullptr, nullptr, nullptr, EGL_OPENGL_ES_API,
2895 context->getState().getClientVersion(), false, true, true, true, false,
2896 EGL_CONTEXT_PRIORITY_MEDIUM_IMG, apiState.hasProtectedContent());
2897
2898 // Small helper function to make the code more readable.
2899 auto cap = [setupCalls](CallCapture &&call) { setupCalls->emplace_back(std::move(call)); };
2900
2901 // Currently this code assumes we can use create-on-bind. It does not support 'Gen' usage.
2902 // TODO(jmadill): Use handle mapping for captured objects. http://anglebug.com/3662
2903
2904 // Vertex input states. Only handles GLES 2.0 states right now.
2905 // Must happen after buffer data initialization.
2906 // TODO(http://anglebug.com/3662): Complete state capture.
2907
2908 // Capture default vertex attribs. Do not capture on GLES1.
2909 if (!context->isGLES1())
2910 {
2911 CaptureDefaultVertexAttribs(replayState, apiState, setupCalls);
2912 }
2913
2914 // Capture vertex array objects
2915 const gl::VertexArrayMap &vertexArrayMap = context->getVertexArraysForCapture();
2916 gl::VertexArrayID boundVertexArrayID = {0};
2917 for (const auto &vertexArrayIter : vertexArrayMap)
2918 {
2919 gl::VertexArrayID vertexArrayID = {vertexArrayIter.first};
2920 if (vertexArrayID.value != 0)
2921 {
2922 cap(CaptureGenVertexArrays(replayState, true, 1, &vertexArrayID));
2923 MaybeCaptureUpdateResourceIDs(setupCalls);
2924 }
2925
2926 if (vertexArrayIter.second)
2927 {
2928 const gl::VertexArray *vertexArray = vertexArrayIter.second;
2929
2930 // Bind the vertexArray (unless default) and populate it
2931 if (vertexArrayID.value != 0)
2932 {
2933 cap(CaptureBindVertexArray(replayState, true, vertexArrayID));
2934 boundVertexArrayID = vertexArrayID;
2935 }
2936 CaptureVertexArrayData(setupCalls, context, vertexArray, &replayState);
2937 }
2938 }
2939
2940 // Bind the current vertex array
2941 const gl::VertexArray *currentVertexArray = apiState.getVertexArray();
2942 if (currentVertexArray->id() != boundVertexArrayID)
2943 {
2944 cap(CaptureBindVertexArray(replayState, true, currentVertexArray->id()));
2945 }
2946
2947 // Capture indexed buffer bindings.
2948 const gl::BufferVector &uniformIndexedBuffers =
2949 apiState.getOffsetBindingPointerUniformBuffers();
2950 const gl::BufferVector &atomicCounterIndexedBuffers =
2951 apiState.getOffsetBindingPointerAtomicCounterBuffers();
2952 const gl::BufferVector &shaderStorageIndexedBuffers =
2953 apiState.getOffsetBindingPointerShaderStorageBuffers();
2954 CaptureIndexedBuffers(replayState, uniformIndexedBuffers, gl::BufferBinding::Uniform,
2955 setupCalls);
2956 CaptureIndexedBuffers(replayState, atomicCounterIndexedBuffers,
2957 gl::BufferBinding::AtomicCounter, setupCalls);
2958 CaptureIndexedBuffers(replayState, shaderStorageIndexedBuffers,
2959 gl::BufferBinding::ShaderStorage, setupCalls);
2960
2961 // Capture Buffer bindings.
2962 const gl::BoundBufferMap &boundBuffers = apiState.getBoundBuffersForCapture();
2963 for (gl::BufferBinding binding : angle::AllEnums<gl::BufferBinding>())
2964 {
2965 gl::BufferID bufferID = boundBuffers[binding].id();
2966
2967 // Filter out redundant buffer binding commands. Note that the code in the previous section
2968 // only binds to ARRAY_BUFFER. Therefore we only check the array binding against the binding
2969 // we set earlier.
2970 bool isArray = binding == gl::BufferBinding::Array;
2971 const gl::Buffer *arrayBuffer = replayState.getArrayBuffer();
2972 if ((isArray && arrayBuffer && arrayBuffer->id() != bufferID) ||
2973 (!isArray && bufferID.value != 0))
2974 {
2975 cap(CaptureBindBuffer(replayState, true, binding, bufferID));
2976 }
2977
2978 // Restore all buffer bindings for Reset
2979 if (bufferID.value != 0)
2980 {
2981 CaptureBufferBindingResetCalls(replayState, resourceTracker, binding, bufferID);
2982 }
2983 }
2984
2985 // Set a unpack alignment of 1.
2986 gl::PixelUnpackState ¤tUnpackState = replayState.getUnpackState();
2987 if (currentUnpackState.alignment != 1)
2988 {
2989 cap(CapturePixelStorei(replayState, true, GL_UNPACK_ALIGNMENT, 1));
2990 currentUnpackState.alignment = 1;
2991 }
2992
2993 // Capture Texture setup and data.
2994 const gl::TextureBindingMap &boundTextures = apiState.getBoundTexturesForCapture();
2995
2996 // Set Texture bindings.
2997 size_t currentActiveTexture = 0;
2998 gl::TextureTypeMap<gl::TextureID> currentTextureBindings;
2999 for (gl::TextureType textureType : angle::AllEnums<gl::TextureType>())
3000 {
3001 const gl::TextureBindingVector &bindings = boundTextures[textureType];
3002 for (size_t bindingIndex = 0; bindingIndex < bindings.size(); ++bindingIndex)
3003 {
3004 gl::TextureID textureID = bindings[bindingIndex].id();
3005
3006 if (textureID.value != 0)
3007 {
3008 if (currentActiveTexture != bindingIndex)
3009 {
3010 cap(CaptureActiveTexture(replayState, true,
3011 GL_TEXTURE0 + static_cast<GLenum>(bindingIndex)));
3012 currentActiveTexture = bindingIndex;
3013 }
3014
3015 if (currentTextureBindings[textureType] != textureID)
3016 {
3017 cap(CaptureBindTexture(replayState, true, textureType, textureID));
3018 currentTextureBindings[textureType] = textureID;
3019 }
3020 }
3021 }
3022 }
3023
3024 // Set active Texture.
3025 size_t stateActiveTexture = apiState.getActiveSampler();
3026 if (currentActiveTexture != stateActiveTexture)
3027 {
3028 cap(CaptureActiveTexture(replayState, true,
3029 GL_TEXTURE0 + static_cast<GLenum>(stateActiveTexture)));
3030 }
3031
3032 // Set Renderbuffer binding.
3033 const gl::RenderbufferManager &renderbuffers = apiState.getRenderbufferManagerForCapture();
3034 gl::RenderbufferID currentRenderbuffer = {0};
3035 for (const auto &renderbufIter : renderbuffers)
3036 {
3037 currentRenderbuffer = renderbufIter.second->id();
3038 }
3039
3040 if (currentRenderbuffer != apiState.getRenderbufferId())
3041 {
3042 cap(CaptureBindRenderbuffer(replayState, true, GL_RENDERBUFFER,
3043 apiState.getRenderbufferId()));
3044 }
3045
3046 // Capture Framebuffers.
3047 const gl::FramebufferManager &framebuffers = apiState.getFramebufferManagerForCapture();
3048
3049 gl::FramebufferID currentDrawFramebuffer = {0};
3050 gl::FramebufferID currentReadFramebuffer = {0};
3051
3052 for (const auto &framebufferIter : framebuffers)
3053 {
3054 gl::FramebufferID id = {framebufferIter.first};
3055 const gl::Framebuffer *framebuffer = framebufferIter.second;
3056
3057 // The default Framebuffer exists (by default).
3058 if (framebuffer->isDefault())
3059 {
3060 continue;
3061 }
3062
3063 cap(CaptureGenFramebuffers(replayState, true, 1, &id));
3064 MaybeCaptureUpdateResourceIDs(setupCalls);
3065 cap(CaptureBindFramebuffer(replayState, true, GL_FRAMEBUFFER, id));
3066 currentDrawFramebuffer = currentReadFramebuffer = id;
3067
3068 // Color Attachments.
3069 for (const gl::FramebufferAttachment &colorAttachment : framebuffer->getColorAttachments())
3070 {
3071 if (!colorAttachment.isAttached())
3072 {
3073 continue;
3074 }
3075
3076 CaptureFramebufferAttachment(setupCalls, replayState, colorAttachment);
3077 }
3078
3079 const gl::FramebufferAttachment *depthAttachment = framebuffer->getDepthAttachment();
3080 if (depthAttachment)
3081 {
3082 ASSERT(depthAttachment->getBinding() == GL_DEPTH_ATTACHMENT ||
3083 depthAttachment->getBinding() == GL_DEPTH_STENCIL_ATTACHMENT);
3084 CaptureFramebufferAttachment(setupCalls, replayState, *depthAttachment);
3085 }
3086
3087 const gl::FramebufferAttachment *stencilAttachment = framebuffer->getStencilAttachment();
3088 if (stencilAttachment)
3089 {
3090 ASSERT(stencilAttachment->getBinding() == GL_STENCIL_ATTACHMENT ||
3091 depthAttachment->getBinding() == GL_DEPTH_STENCIL_ATTACHMENT);
3092 CaptureFramebufferAttachment(setupCalls, replayState, *stencilAttachment);
3093 }
3094
3095 const std::vector<GLenum> &drawBufferStates = framebuffer->getDrawBufferStates();
3096 cap(CaptureDrawBuffers(replayState, true, static_cast<GLsizei>(drawBufferStates.size()),
3097 drawBufferStates.data()));
3098 }
3099
3100 // Capture framebuffer bindings.
3101 gl::FramebufferID stateReadFramebuffer = apiState.getReadFramebuffer()->id();
3102 gl::FramebufferID stateDrawFramebuffer = apiState.getDrawFramebuffer()->id();
3103 if (stateDrawFramebuffer == stateReadFramebuffer)
3104 {
3105 if (currentDrawFramebuffer != stateDrawFramebuffer ||
3106 currentReadFramebuffer != stateReadFramebuffer)
3107 {
3108 cap(CaptureBindFramebuffer(replayState, true, GL_FRAMEBUFFER, stateDrawFramebuffer));
3109 currentDrawFramebuffer = currentReadFramebuffer = stateDrawFramebuffer;
3110 }
3111 }
3112 else
3113 {
3114 if (currentDrawFramebuffer != stateDrawFramebuffer)
3115 {
3116 cap(CaptureBindFramebuffer(replayState, true, GL_DRAW_FRAMEBUFFER,
3117 currentDrawFramebuffer));
3118 currentDrawFramebuffer = stateDrawFramebuffer;
3119 }
3120
3121 if (currentReadFramebuffer != stateReadFramebuffer)
3122 {
3123 cap(CaptureBindFramebuffer(replayState, true, GL_READ_FRAMEBUFFER,
3124 replayState.getReadFramebuffer()->id()));
3125 currentReadFramebuffer = stateReadFramebuffer;
3126 }
3127 }
3128
3129 // Capture Program Pipelines
3130 const gl::ProgramPipelineManager *programPipelineManager =
3131 apiState.getProgramPipelineManagerForCapture();
3132
3133 for (const auto &ppoIterator : *programPipelineManager)
3134 {
3135 gl::ProgramPipeline *pipeline = ppoIterator.second;
3136 gl::ProgramPipelineID id = {ppoIterator.first};
3137 cap(CaptureGenProgramPipelines(replayState, true, 1, &id));
3138 MaybeCaptureUpdateResourceIDs(setupCalls);
3139
3140 // PPOs can contain graphics and compute programs, so loop through all shader types rather
3141 // than just the linked ones since getLinkedShaderStages() will return either only graphics
3142 // or compute stages.
3143 for (gl::ShaderType shaderType : gl::AllShaderTypes())
3144 {
3145 gl::Program *program = pipeline->getShaderProgram(shaderType);
3146 if (!program)
3147 {
3148 continue;
3149 }
3150 ASSERT(program->isLinked());
3151 GLbitfield gLbitfield = GetBitfieldFromShaderType(shaderType);
3152 cap(CaptureUseProgramStages(replayState, true, pipeline->id(), gLbitfield,
3153 program->id()));
3154 }
3155
3156 gl::Program *program = pipeline->getActiveShaderProgram();
3157 if (program)
3158 {
3159 cap(CaptureActiveShaderProgram(replayState, true, id, program->id()));
3160 }
3161 }
3162
3163 // For now we assume the installed program executable is the same as the current program.
3164 // TODO(jmadill): Handle installed program executable. http://anglebug.com/3662
3165 if (apiState.getProgram() && !context->isGLES1())
3166 {
3167 cap(CaptureUseProgram(replayState, true, apiState.getProgram()->id()));
3168 CaptureUpdateCurrentProgram(setupCalls->back(), setupCalls);
3169 }
3170 else if (apiState.getProgramPipeline())
3171 {
3172 // glUseProgram() is called above to update the necessary uniform values for each program
3173 // that's being recreated. If there is no program currently bound, then we need to unbind
3174 // the last bound program so the PPO will be used instead:
3175 // 7.4 Program Pipeline Objects
3176 // If no current program object has been established by UseProgram, the program objects used
3177 // for each shader stage and for uniform updates are taken from the bound program pipeline
3178 // object, if any. If there is a current program object established by UseProgram, the bound
3179 // program pipeline object has no effect on rendering or uniform updates.
3180 cap(CaptureUseProgram(replayState, true, {0}));
3181 CaptureUpdateCurrentProgram(setupCalls->back(), setupCalls);
3182 cap(CaptureBindProgramPipeline(replayState, true, apiState.getProgramPipeline()->id()));
3183 }
3184
3185 // TODO(http://anglebug.com/3662): ES 3.x objects.
3186
3187 // Create existing queries. Note that queries may be genned and not yet started. In that
3188 // case the queries will exist in the query map as nullptr entries.
3189 const gl::QueryMap &queryMap = context->getQueriesForCapture();
3190 for (gl::QueryMap::Iterator queryIter = queryMap.beginWithNull();
3191 queryIter != queryMap.endWithNull(); ++queryIter)
3192 {
3193 ASSERT(queryIter->first);
3194 gl::QueryID queryID = {queryIter->first};
3195
3196 cap(CaptureGenQueries(replayState, true, 1, &queryID));
3197 MaybeCaptureUpdateResourceIDs(setupCalls);
3198
3199 gl::Query *query = queryIter->second;
3200 if (query)
3201 {
3202 gl::QueryType queryType = query->getType();
3203
3204 // Begin the query to generate the object
3205 cap(CaptureBeginQuery(replayState, true, queryType, queryID));
3206
3207 // End the query if it was not active
3208 if (!IsQueryActive(apiState, queryID))
3209 {
3210 cap(CaptureEndQuery(replayState, true, queryType));
3211 }
3212 }
3213 }
3214
3215 // Transform Feedback
3216 const gl::TransformFeedbackMap &xfbMap = context->getTransformFeedbacksForCapture();
3217 for (const auto &xfbIter : xfbMap)
3218 {
3219 gl::TransformFeedbackID xfbID = {xfbIter.first};
3220
3221 // Do not capture the default XFB object.
3222 if (xfbID.value == 0)
3223 {
3224 continue;
3225 }
3226
3227 cap(CaptureGenTransformFeedbacks(replayState, true, 1, &xfbID));
3228 MaybeCaptureUpdateResourceIDs(setupCalls);
3229
3230 gl::TransformFeedback *xfb = xfbIter.second;
3231 if (!xfb)
3232 {
3233 // The object was never created
3234 continue;
3235 }
3236
3237 // Bind XFB to create the object
3238 cap(CaptureBindTransformFeedback(replayState, true, GL_TRANSFORM_FEEDBACK, xfbID));
3239
3240 // Bind the buffers associated with this XFB object
3241 for (size_t i = 0; i < xfb->getIndexedBufferCount(); ++i)
3242 {
3243 const gl::OffsetBindingPointer<gl::Buffer> &xfbBuffer = xfb->getIndexedBuffer(i);
3244
3245 // Note: Buffers bound with BindBufferBase can be used with BindBuffer
3246 cap(CaptureBindBufferRange(replayState, true, gl::BufferBinding::TransformFeedback, 0,
3247 xfbBuffer.id(), xfbBuffer.getOffset(), xfbBuffer.getSize()));
3248 }
3249
3250 if (xfb->isActive() || xfb->isPaused())
3251 {
3252 // We don't support active XFB in MEC yet
3253 UNIMPLEMENTED();
3254 }
3255 }
3256
3257 // Bind the current XFB buffer after populating XFB objects
3258 gl::TransformFeedback *currentXFB = apiState.getCurrentTransformFeedback();
3259 if (currentXFB)
3260 {
3261 cap(CaptureBindTransformFeedback(replayState, true, GL_TRANSFORM_FEEDBACK,
3262 currentXFB->id()));
3263 }
3264
3265 // Bind samplers
3266 const gl::SamplerBindingVector &samplerBindings = apiState.getSamplers();
3267 for (GLuint bindingIndex = 0; bindingIndex < static_cast<GLuint>(samplerBindings.size());
3268 ++bindingIndex)
3269 {
3270 gl::SamplerID samplerID = samplerBindings[bindingIndex].id();
3271 if (samplerID.value != 0)
3272 {
3273 cap(CaptureBindSampler(replayState, true, bindingIndex, samplerID));
3274 }
3275 }
3276
3277 // Capture Image Texture bindings
3278 const std::vector<gl::ImageUnit> &imageUnits = apiState.getImageUnits();
3279 for (GLuint bindingIndex = 0; bindingIndex < static_cast<GLuint>(imageUnits.size());
3280 ++bindingIndex)
3281 {
3282 const gl::ImageUnit &imageUnit = imageUnits[bindingIndex];
3283
3284 if (imageUnit.texture == 0)
3285 {
3286 continue;
3287 }
3288
3289 cap(CaptureBindImageTexture(replayState, true, bindingIndex, imageUnit.texture.id(),
3290 imageUnit.level, imageUnit.layered, imageUnit.layer,
3291 imageUnit.access, imageUnit.format));
3292 }
3293
3294 // Capture GL Context states.
3295 // TODO(http://anglebug.com/3662): Complete state capture.
3296 auto capCap = [cap, &replayState](GLenum capEnum, bool capValue) {
3297 if (capValue)
3298 {
3299 cap(CaptureEnable(replayState, true, capEnum));
3300 }
3301 else
3302 {
3303 cap(CaptureDisable(replayState, true, capEnum));
3304 }
3305 };
3306
3307 // Capture GLES1 context states.
3308 if (context->isGLES1())
3309 {
3310 const bool currentTextureState = apiState.getEnableFeature(GL_TEXTURE_2D);
3311 const bool defaultTextureState = replayState.getEnableFeature(GL_TEXTURE_2D);
3312 if (currentTextureState != defaultTextureState)
3313 {
3314 capCap(GL_TEXTURE_2D, currentTextureState);
3315 }
3316 }
3317
3318 // Rasterizer state. Missing ES 3.x features.
3319 const gl::RasterizerState &defaultRasterState = replayState.getRasterizerState();
3320 const gl::RasterizerState ¤tRasterState = apiState.getRasterizerState();
3321 if (currentRasterState.cullFace != defaultRasterState.cullFace)
3322 {
3323 capCap(GL_CULL_FACE, currentRasterState.cullFace);
3324 }
3325
3326 if (currentRasterState.cullMode != defaultRasterState.cullMode)
3327 {
3328 cap(CaptureCullFace(replayState, true, currentRasterState.cullMode));
3329 }
3330
3331 if (currentRasterState.frontFace != defaultRasterState.frontFace)
3332 {
3333 cap(CaptureFrontFace(replayState, true, currentRasterState.frontFace));
3334 }
3335
3336 if (currentRasterState.polygonOffsetFill != defaultRasterState.polygonOffsetFill)
3337 {
3338 capCap(GL_POLYGON_OFFSET_FILL, currentRasterState.polygonOffsetFill);
3339 }
3340
3341 if (currentRasterState.polygonOffsetFactor != defaultRasterState.polygonOffsetFactor ||
3342 currentRasterState.polygonOffsetUnits != defaultRasterState.polygonOffsetUnits)
3343 {
3344 cap(CapturePolygonOffset(replayState, true, currentRasterState.polygonOffsetFactor,
3345 currentRasterState.polygonOffsetUnits));
3346 }
3347
3348 // pointDrawMode/multiSample are only used in the D3D back-end right now.
3349
3350 if (currentRasterState.rasterizerDiscard != defaultRasterState.rasterizerDiscard)
3351 {
3352 capCap(GL_RASTERIZER_DISCARD, currentRasterState.rasterizerDiscard);
3353 }
3354
3355 if (currentRasterState.dither != defaultRasterState.dither)
3356 {
3357 capCap(GL_DITHER, currentRasterState.dither);
3358 }
3359
3360 // Depth/stencil state.
3361 const gl::DepthStencilState &defaultDSState = replayState.getDepthStencilState();
3362 const gl::DepthStencilState ¤tDSState = apiState.getDepthStencilState();
3363 if (defaultDSState.depthFunc != currentDSState.depthFunc)
3364 {
3365 cap(CaptureDepthFunc(replayState, true, currentDSState.depthFunc));
3366 }
3367
3368 if (defaultDSState.depthMask != currentDSState.depthMask)
3369 {
3370 cap(CaptureDepthMask(replayState, true, gl::ConvertToGLBoolean(currentDSState.depthMask)));
3371 }
3372
3373 if (defaultDSState.depthTest != currentDSState.depthTest)
3374 {
3375 capCap(GL_DEPTH_TEST, currentDSState.depthTest);
3376 }
3377
3378 if (defaultDSState.stencilTest != currentDSState.stencilTest)
3379 {
3380 capCap(GL_STENCIL_TEST, currentDSState.stencilTest);
3381 }
3382
3383 if (currentDSState.stencilFunc == currentDSState.stencilBackFunc &&
3384 currentDSState.stencilMask == currentDSState.stencilBackMask)
3385 {
3386 // Front and back are equal
3387 if (defaultDSState.stencilFunc != currentDSState.stencilFunc ||
3388 defaultDSState.stencilMask != currentDSState.stencilMask ||
3389 apiState.getStencilRef() != 0)
3390 {
3391 cap(CaptureStencilFunc(replayState, true, currentDSState.stencilFunc,
3392 apiState.getStencilRef(), currentDSState.stencilMask));
3393 }
3394 }
3395 else
3396 {
3397 // Front and back are separate
3398 if (defaultDSState.stencilFunc != currentDSState.stencilFunc ||
3399 defaultDSState.stencilMask != currentDSState.stencilMask ||
3400 apiState.getStencilRef() != 0)
3401 {
3402 cap(CaptureStencilFuncSeparate(replayState, true, GL_FRONT, currentDSState.stencilFunc,
3403 apiState.getStencilRef(), currentDSState.stencilMask));
3404 }
3405
3406 if (defaultDSState.stencilBackFunc != currentDSState.stencilBackFunc ||
3407 defaultDSState.stencilBackMask != currentDSState.stencilBackMask ||
3408 apiState.getStencilBackRef() != 0)
3409 {
3410 cap(CaptureStencilFuncSeparate(
3411 replayState, true, GL_BACK, currentDSState.stencilBackFunc,
3412 apiState.getStencilBackRef(), currentDSState.stencilBackMask));
3413 }
3414 }
3415
3416 if (currentDSState.stencilFail == currentDSState.stencilBackFail &&
3417 currentDSState.stencilPassDepthFail == currentDSState.stencilBackPassDepthFail &&
3418 currentDSState.stencilPassDepthPass == currentDSState.stencilBackPassDepthPass)
3419 {
3420 // Front and back are equal
3421 if (defaultDSState.stencilFail != currentDSState.stencilFail ||
3422 defaultDSState.stencilPassDepthFail != currentDSState.stencilPassDepthFail ||
3423 defaultDSState.stencilPassDepthPass != currentDSState.stencilPassDepthPass)
3424 {
3425 cap(CaptureStencilOp(replayState, true, currentDSState.stencilFail,
3426 currentDSState.stencilPassDepthFail,
3427 currentDSState.stencilPassDepthPass));
3428 }
3429 }
3430 else
3431 {
3432 // Front and back are separate
3433 if (defaultDSState.stencilFail != currentDSState.stencilFail ||
3434 defaultDSState.stencilPassDepthFail != currentDSState.stencilPassDepthFail ||
3435 defaultDSState.stencilPassDepthPass != currentDSState.stencilPassDepthPass)
3436 {
3437 cap(CaptureStencilOpSeparate(replayState, true, GL_FRONT, currentDSState.stencilFail,
3438 currentDSState.stencilPassDepthFail,
3439 currentDSState.stencilPassDepthPass));
3440 }
3441
3442 if (defaultDSState.stencilBackFail != currentDSState.stencilBackFail ||
3443 defaultDSState.stencilBackPassDepthFail != currentDSState.stencilBackPassDepthFail ||
3444 defaultDSState.stencilBackPassDepthPass != currentDSState.stencilBackPassDepthPass)
3445 {
3446 cap(CaptureStencilOpSeparate(replayState, true, GL_BACK, currentDSState.stencilBackFail,
3447 currentDSState.stencilBackPassDepthFail,
3448 currentDSState.stencilBackPassDepthPass));
3449 }
3450 }
3451
3452 if (currentDSState.stencilWritemask == currentDSState.stencilBackWritemask)
3453 {
3454 // Front and back are equal
3455 if (defaultDSState.stencilWritemask != currentDSState.stencilWritemask)
3456 {
3457 cap(CaptureStencilMask(replayState, true, currentDSState.stencilWritemask));
3458 }
3459 }
3460 else
3461 {
3462 // Front and back are separate
3463 if (defaultDSState.stencilWritemask != currentDSState.stencilWritemask)
3464 {
3465 cap(CaptureStencilMaskSeparate(replayState, true, GL_FRONT,
3466 currentDSState.stencilWritemask));
3467 }
3468
3469 if (defaultDSState.stencilBackWritemask != currentDSState.stencilBackWritemask)
3470 {
3471 cap(CaptureStencilMaskSeparate(replayState, true, GL_BACK,
3472 currentDSState.stencilBackWritemask));
3473 }
3474 }
3475
3476 // Blend state.
3477 const gl::BlendState &defaultBlendState = replayState.getBlendState();
3478 const gl::BlendState ¤tBlendState = apiState.getBlendState();
3479
3480 if (currentBlendState.blend != defaultBlendState.blend)
3481 {
3482 capCap(GL_BLEND, currentBlendState.blend);
3483 }
3484
3485 if (currentBlendState.sourceBlendRGB != defaultBlendState.sourceBlendRGB ||
3486 currentBlendState.destBlendRGB != defaultBlendState.destBlendRGB ||
3487 currentBlendState.sourceBlendAlpha != defaultBlendState.sourceBlendAlpha ||
3488 currentBlendState.destBlendAlpha != defaultBlendState.destBlendAlpha)
3489 {
3490 if (currentBlendState.sourceBlendRGB == currentBlendState.sourceBlendAlpha &&
3491 currentBlendState.destBlendRGB == currentBlendState.destBlendAlpha)
3492 {
3493 // Color and alpha are equal
3494 cap(CaptureBlendFunc(replayState, true, currentBlendState.sourceBlendRGB,
3495 currentBlendState.destBlendRGB));
3496 }
3497 else
3498 {
3499 // Color and alpha are separate
3500 cap(CaptureBlendFuncSeparate(
3501 replayState, true, currentBlendState.sourceBlendRGB, currentBlendState.destBlendRGB,
3502 currentBlendState.sourceBlendAlpha, currentBlendState.destBlendAlpha));
3503 }
3504 }
3505
3506 if (currentBlendState.blendEquationRGB != defaultBlendState.blendEquationRGB ||
3507 currentBlendState.blendEquationAlpha != defaultBlendState.blendEquationAlpha)
3508 {
3509 cap(CaptureBlendEquationSeparate(replayState, true, currentBlendState.blendEquationRGB,
3510 currentBlendState.blendEquationAlpha));
3511 }
3512
3513 if (currentBlendState.colorMaskRed != defaultBlendState.colorMaskRed ||
3514 currentBlendState.colorMaskGreen != defaultBlendState.colorMaskGreen ||
3515 currentBlendState.colorMaskBlue != defaultBlendState.colorMaskBlue ||
3516 currentBlendState.colorMaskAlpha != defaultBlendState.colorMaskAlpha)
3517 {
3518 cap(CaptureColorMask(replayState, true,
3519 gl::ConvertToGLBoolean(currentBlendState.colorMaskRed),
3520 gl::ConvertToGLBoolean(currentBlendState.colorMaskGreen),
3521 gl::ConvertToGLBoolean(currentBlendState.colorMaskBlue),
3522 gl::ConvertToGLBoolean(currentBlendState.colorMaskAlpha)));
3523 }
3524
3525 const gl::ColorF ¤tBlendColor = apiState.getBlendColor();
3526 if (currentBlendColor != gl::ColorF())
3527 {
3528 cap(CaptureBlendColor(replayState, true, currentBlendColor.red, currentBlendColor.green,
3529 currentBlendColor.blue, currentBlendColor.alpha));
3530 }
3531
3532 // Pixel storage states.
3533 gl::PixelPackState ¤tPackState = replayState.getPackState();
3534 if (currentPackState.alignment != apiState.getPackAlignment())
3535 {
3536 cap(CapturePixelStorei(replayState, true, GL_PACK_ALIGNMENT, apiState.getPackAlignment()));
3537 currentPackState.alignment = apiState.getPackAlignment();
3538 }
3539
3540 if (currentPackState.rowLength != apiState.getPackRowLength())
3541 {
3542 cap(CapturePixelStorei(replayState, true, GL_PACK_ROW_LENGTH, apiState.getPackRowLength()));
3543 currentPackState.rowLength = apiState.getPackRowLength();
3544 }
3545
3546 if (currentPackState.skipRows != apiState.getPackSkipRows())
3547 {
3548 cap(CapturePixelStorei(replayState, true, GL_PACK_SKIP_ROWS, apiState.getPackSkipRows()));
3549 currentPackState.skipRows = apiState.getPackSkipRows();
3550 }
3551
3552 if (currentPackState.skipPixels != apiState.getPackSkipPixels())
3553 {
3554 cap(CapturePixelStorei(replayState, true, GL_PACK_SKIP_PIXELS,
3555 apiState.getPackSkipPixels()));
3556 currentPackState.skipPixels = apiState.getPackSkipPixels();
3557 }
3558
3559 // We set unpack alignment above, no need to change it here
3560 ASSERT(currentUnpackState.alignment == 1);
3561 if (currentUnpackState.rowLength != apiState.getUnpackRowLength())
3562 {
3563 cap(CapturePixelStorei(replayState, true, GL_UNPACK_ROW_LENGTH,
3564 apiState.getUnpackRowLength()));
3565 currentUnpackState.rowLength = apiState.getUnpackRowLength();
3566 }
3567
3568 if (currentUnpackState.skipRows != apiState.getUnpackSkipRows())
3569 {
3570 cap(CapturePixelStorei(replayState, true, GL_UNPACK_SKIP_ROWS,
3571 apiState.getUnpackSkipRows()));
3572 currentUnpackState.skipRows = apiState.getUnpackSkipRows();
3573 }
3574
3575 if (currentUnpackState.skipPixels != apiState.getUnpackSkipPixels())
3576 {
3577 cap(CapturePixelStorei(replayState, true, GL_UNPACK_SKIP_PIXELS,
3578 apiState.getUnpackSkipPixels()));
3579 currentUnpackState.skipPixels = apiState.getUnpackSkipPixels();
3580 }
3581
3582 if (currentUnpackState.imageHeight != apiState.getUnpackImageHeight())
3583 {
3584 cap(CapturePixelStorei(replayState, true, GL_UNPACK_IMAGE_HEIGHT,
3585 apiState.getUnpackImageHeight()));
3586 currentUnpackState.imageHeight = apiState.getUnpackImageHeight();
3587 }
3588
3589 if (currentUnpackState.skipImages != apiState.getUnpackSkipImages())
3590 {
3591 cap(CapturePixelStorei(replayState, true, GL_UNPACK_SKIP_IMAGES,
3592 apiState.getUnpackSkipImages()));
3593 currentUnpackState.skipImages = apiState.getUnpackSkipImages();
3594 }
3595
3596 // Clear state. Missing ES 3.x features.
3597 // TODO(http://anglebug.com/3662): Complete state capture.
3598 const gl::ColorF ¤tClearColor = apiState.getColorClearValue();
3599 if (currentClearColor != gl::ColorF())
3600 {
3601 cap(CaptureClearColor(replayState, true, currentClearColor.red, currentClearColor.green,
3602 currentClearColor.blue, currentClearColor.alpha));
3603 }
3604
3605 if (apiState.getDepthClearValue() != 1.0f)
3606 {
3607 cap(CaptureClearDepthf(replayState, true, apiState.getDepthClearValue()));
3608 }
3609
3610 if (apiState.getStencilClearValue() != 0)
3611 {
3612 cap(CaptureClearStencil(replayState, true, apiState.getStencilClearValue()));
3613 }
3614
3615 // Viewport / scissor / clipping planes.
3616 const gl::Rectangle ¤tViewport = apiState.getViewport();
3617 if (currentViewport != gl::Rectangle())
3618 {
3619 cap(CaptureViewport(replayState, true, currentViewport.x, currentViewport.y,
3620 currentViewport.width, currentViewport.height));
3621 }
3622
3623 if (apiState.getNearPlane() != 0.0f || apiState.getFarPlane() != 1.0f)
3624 {
3625 cap(CaptureDepthRangef(replayState, true, apiState.getNearPlane(), apiState.getFarPlane()));
3626 }
3627
3628 if (apiState.isScissorTestEnabled())
3629 {
3630 capCap(GL_SCISSOR_TEST, apiState.isScissorTestEnabled());
3631 }
3632
3633 const gl::Rectangle ¤tScissor = apiState.getScissor();
3634 if (currentScissor != gl::Rectangle())
3635 {
3636 cap(CaptureScissor(replayState, true, currentScissor.x, currentScissor.y,
3637 currentScissor.width, currentScissor.height));
3638 }
3639
3640 // Allow the replayState object to be destroyed conveniently.
3641 replayState.setBufferBinding(context, gl::BufferBinding::Array, nullptr);
3642 }
3643
SkipCall(EntryPoint entryPoint)3644 bool SkipCall(EntryPoint entryPoint)
3645 {
3646 switch (entryPoint)
3647 {
3648 case EntryPoint::GLDebugMessageCallback:
3649 case EntryPoint::GLDebugMessageCallbackKHR:
3650 case EntryPoint::GLDebugMessageControl:
3651 case EntryPoint::GLDebugMessageControlKHR:
3652 case EntryPoint::GLDebugMessageInsert:
3653 case EntryPoint::GLDebugMessageInsertKHR:
3654 case EntryPoint::GLGetDebugMessageLog:
3655 case EntryPoint::GLGetDebugMessageLogKHR:
3656 case EntryPoint::GLGetObjectLabelEXT:
3657 case EntryPoint::GLGetObjectLabelKHR:
3658 case EntryPoint::GLGetObjectPtrLabelKHR:
3659 case EntryPoint::GLGetPointervKHR:
3660 case EntryPoint::GLInsertEventMarkerEXT:
3661 case EntryPoint::GLLabelObjectEXT:
3662 case EntryPoint::GLObjectLabelKHR:
3663 case EntryPoint::GLObjectPtrLabelKHR:
3664 case EntryPoint::GLPopDebugGroupKHR:
3665 case EntryPoint::GLPopGroupMarkerEXT:
3666 case EntryPoint::GLPushDebugGroupKHR:
3667 case EntryPoint::GLPushGroupMarkerEXT:
3668 // Purposefully skip entry points from:
3669 // - KHR_debug
3670 // - EXT_debug_label
3671 // - EXT_debug_marker
3672 // There is no need to capture these for replaying a trace in our harness
3673 return true;
3674
3675 case EntryPoint::GLGetActiveUniform:
3676 case EntryPoint::GLGetActiveUniformsiv:
3677 // Skip these calls because:
3678 // - We don't use the return values.
3679 // - Active uniform counts can vary between platforms due to cross stage optimizations
3680 // and asking about uniforms above GL_ACTIVE_UNIFORMS triggers errors.
3681 return true;
3682
3683 default:
3684 break;
3685 }
3686
3687 return false;
3688 }
3689
FindShaderProgramIDInCall(const CallCapture & call,gl::ShaderProgramID * idOut)3690 bool FindShaderProgramIDInCall(const CallCapture &call, gl::ShaderProgramID *idOut)
3691 {
3692 for (const ParamCapture ¶m : call.params.getParamCaptures())
3693 {
3694 if (param.type == ParamType::TShaderProgramID && param.name == "programPacked")
3695 {
3696 *idOut = param.value.ShaderProgramIDVal;
3697 return true;
3698 }
3699 }
3700
3701 return false;
3702 }
3703
GetAdjustedTextureCacheLevel(gl::TextureTarget target,GLint level)3704 GLint GetAdjustedTextureCacheLevel(gl::TextureTarget target, GLint level)
3705 {
3706 GLint adjustedLevel = level;
3707
3708 // If target is a cube, we need to maintain 6 images per level
3709 if (IsCubeMapFaceTarget(target))
3710 {
3711 adjustedLevel *= 6;
3712 adjustedLevel += CubeMapTextureTargetToFaceIndex(target);
3713 }
3714
3715 return adjustedLevel;
3716 }
3717 } // namespace
3718
ParamCapture()3719 ParamCapture::ParamCapture() : type(ParamType::TGLenum), enumGroup(gl::GLenumGroup::DefaultGroup) {}
3720
ParamCapture(const char * nameIn,ParamType typeIn)3721 ParamCapture::ParamCapture(const char *nameIn, ParamType typeIn)
3722 : name(nameIn), type(typeIn), enumGroup(gl::GLenumGroup::DefaultGroup)
3723 {}
3724
3725 ParamCapture::~ParamCapture() = default;
3726
ParamCapture(ParamCapture && other)3727 ParamCapture::ParamCapture(ParamCapture &&other)
3728 : type(ParamType::TGLenum), enumGroup(gl::GLenumGroup::DefaultGroup)
3729 {
3730 *this = std::move(other);
3731 }
3732
operator =(ParamCapture && other)3733 ParamCapture &ParamCapture::operator=(ParamCapture &&other)
3734 {
3735 std::swap(name, other.name);
3736 std::swap(type, other.type);
3737 std::swap(value, other.value);
3738 std::swap(enumGroup, other.enumGroup);
3739 std::swap(data, other.data);
3740 std::swap(arrayClientPointerIndex, other.arrayClientPointerIndex);
3741 std::swap(readBufferSizeBytes, other.readBufferSizeBytes);
3742 std::swap(dataNElements, other.dataNElements);
3743 return *this;
3744 }
3745
ParamBuffer()3746 ParamBuffer::ParamBuffer() {}
3747
3748 ParamBuffer::~ParamBuffer() = default;
3749
ParamBuffer(ParamBuffer && other)3750 ParamBuffer::ParamBuffer(ParamBuffer &&other)
3751 {
3752 *this = std::move(other);
3753 }
3754
operator =(ParamBuffer && other)3755 ParamBuffer &ParamBuffer::operator=(ParamBuffer &&other)
3756 {
3757 std::swap(mParamCaptures, other.mParamCaptures);
3758 std::swap(mClientArrayDataParam, other.mClientArrayDataParam);
3759 std::swap(mReadBufferSize, other.mReadBufferSize);
3760 std::swap(mReturnValueCapture, other.mReturnValueCapture);
3761 std::swap(mMappedBufferID, other.mMappedBufferID);
3762 return *this;
3763 }
3764
getParam(const char * paramName,ParamType paramType,int index)3765 ParamCapture &ParamBuffer::getParam(const char *paramName, ParamType paramType, int index)
3766 {
3767 ParamCapture &capture = mParamCaptures[index];
3768 ASSERT(capture.name == paramName);
3769 ASSERT(capture.type == paramType);
3770 return capture;
3771 }
3772
getParam(const char * paramName,ParamType paramType,int index) const3773 const ParamCapture &ParamBuffer::getParam(const char *paramName,
3774 ParamType paramType,
3775 int index) const
3776 {
3777 return const_cast<ParamBuffer *>(this)->getParam(paramName, paramType, index);
3778 }
3779
getParamFlexName(const char * paramName1,const char * paramName2,ParamType paramType,int index)3780 ParamCapture &ParamBuffer::getParamFlexName(const char *paramName1,
3781 const char *paramName2,
3782 ParamType paramType,
3783 int index)
3784 {
3785 ParamCapture &capture = mParamCaptures[index];
3786 ASSERT(capture.name == paramName1 || capture.name == paramName2);
3787 ASSERT(capture.type == paramType);
3788 return capture;
3789 }
3790
getParamFlexName(const char * paramName1,const char * paramName2,ParamType paramType,int index) const3791 const ParamCapture &ParamBuffer::getParamFlexName(const char *paramName1,
3792 const char *paramName2,
3793 ParamType paramType,
3794 int index) const
3795 {
3796 return const_cast<ParamBuffer *>(this)->getParamFlexName(paramName1, paramName2, paramType,
3797 index);
3798 }
3799
addParam(ParamCapture && param)3800 void ParamBuffer::addParam(ParamCapture &¶m)
3801 {
3802 if (param.arrayClientPointerIndex != -1)
3803 {
3804 ASSERT(mClientArrayDataParam == -1);
3805 mClientArrayDataParam = static_cast<int>(mParamCaptures.size());
3806 }
3807
3808 mReadBufferSize = std::max(param.readBufferSizeBytes, mReadBufferSize);
3809 mParamCaptures.emplace_back(std::move(param));
3810 }
3811
addReturnValue(ParamCapture && returnValue)3812 void ParamBuffer::addReturnValue(ParamCapture &&returnValue)
3813 {
3814 mReturnValueCapture = std::move(returnValue);
3815 }
3816
getClientArrayPointerParameter()3817 ParamCapture &ParamBuffer::getClientArrayPointerParameter()
3818 {
3819 ASSERT(hasClientArrayData());
3820 return mParamCaptures[mClientArrayDataParam];
3821 }
3822
CallCapture(EntryPoint entryPointIn,ParamBuffer && paramsIn)3823 CallCapture::CallCapture(EntryPoint entryPointIn, ParamBuffer &¶msIn)
3824 : entryPoint(entryPointIn), params(std::move(paramsIn))
3825 {}
3826
CallCapture(const std::string & customFunctionNameIn,ParamBuffer && paramsIn)3827 CallCapture::CallCapture(const std::string &customFunctionNameIn, ParamBuffer &¶msIn)
3828 : entryPoint(EntryPoint::GLInvalid),
3829 customFunctionName(customFunctionNameIn),
3830 params(std::move(paramsIn))
3831 {}
3832
3833 CallCapture::~CallCapture() = default;
3834
CallCapture(CallCapture && other)3835 CallCapture::CallCapture(CallCapture &&other)
3836 {
3837 *this = std::move(other);
3838 }
3839
operator =(CallCapture && other)3840 CallCapture &CallCapture::operator=(CallCapture &&other)
3841 {
3842 std::swap(entryPoint, other.entryPoint);
3843 std::swap(customFunctionName, other.customFunctionName);
3844 std::swap(params, other.params);
3845 return *this;
3846 }
3847
name() const3848 const char *CallCapture::name() const
3849 {
3850 if (entryPoint == EntryPoint::GLInvalid)
3851 {
3852 ASSERT(!customFunctionName.empty());
3853 return customFunctionName.c_str();
3854 }
3855
3856 return angle::GetEntryPointName(entryPoint);
3857 }
3858
ReplayContext(size_t readBufferSizebytes,const gl::AttribArray<size_t> & clientArraysSizebytes)3859 ReplayContext::ReplayContext(size_t readBufferSizebytes,
3860 const gl::AttribArray<size_t> &clientArraysSizebytes)
3861 {
3862 mReadBuffer.resize(readBufferSizebytes);
3863
3864 for (uint32_t i = 0; i < clientArraysSizebytes.size(); i++)
3865 {
3866 mClientArraysBuffer[i].resize(clientArraysSizebytes[i]);
3867 }
3868 }
~ReplayContext()3869 ReplayContext::~ReplayContext() {}
3870
3871 FrameCapture::FrameCapture() = default;
3872 FrameCapture::~FrameCapture() = default;
3873
reset()3874 void FrameCapture::reset()
3875 {
3876 mSetupCalls.clear();
3877 }
3878
FrameCaptureShared()3879 FrameCaptureShared::FrameCaptureShared()
3880 : mEnabled(true),
3881 mSerializeStateEnabled(false),
3882 mCompression(true),
3883 mClientVertexArrayMap{},
3884 mFrameIndex(1),
3885 mCaptureStartFrame(1),
3886 mCaptureEndFrame(10),
3887 mClientArraySizes{},
3888 mReadBufferSize(0),
3889 mHasResourceType{},
3890 mCaptureTrigger(0),
3891 mWindowSurfaceContextID({0})
3892 {
3893 reset();
3894
3895 std::string enabledFromEnv =
3896 GetEnvironmentVarOrUnCachedAndroidProperty(kEnabledVarName, kAndroidCaptureEnabled);
3897 if (enabledFromEnv == "0")
3898 {
3899 mEnabled = false;
3900 }
3901
3902 std::string pathFromEnv =
3903 GetEnvironmentVarOrUnCachedAndroidProperty(kOutDirectoryVarName, kAndroidOutDir);
3904 if (pathFromEnv.empty())
3905 {
3906 mOutDirectory = GetDefaultOutDirectory();
3907 }
3908 else
3909 {
3910 mOutDirectory = pathFromEnv;
3911 }
3912
3913 // Ensure the capture path ends with a slash.
3914 if (mOutDirectory.back() != '\\' && mOutDirectory.back() != '/')
3915 {
3916 mOutDirectory += '/';
3917 }
3918
3919 std::string startFromEnv =
3920 GetEnvironmentVarOrUnCachedAndroidProperty(kFrameStartVarName, kAndroidFrameStart);
3921 if (!startFromEnv.empty())
3922 {
3923 mCaptureStartFrame = atoi(startFromEnv.c_str());
3924 }
3925
3926 std::string endFromEnv =
3927 GetEnvironmentVarOrUnCachedAndroidProperty(kFrameEndVarName, kAndroidFrameEnd);
3928 if (!endFromEnv.empty())
3929 {
3930 mCaptureEndFrame = atoi(endFromEnv.c_str());
3931 }
3932
3933 std::string captureTriggerFromEnv =
3934 GetEnvironmentVarOrUnCachedAndroidProperty(kCaptureTriggerVarName, kAndroidCaptureTrigger);
3935 if (!captureTriggerFromEnv.empty())
3936 {
3937 mCaptureTrigger = atoi(captureTriggerFromEnv.c_str());
3938
3939 // If the trigger has been populated, ignore the other frame range variables by setting them
3940 // to unreasonable values. This isn't perfect, but it is effective.
3941 mCaptureStartFrame = mCaptureEndFrame = std::numeric_limits<uint32_t>::max();
3942 INFO() << "Capture trigger detected, disabling capture start/end frame.";
3943 }
3944
3945 std::string labelFromEnv =
3946 GetEnvironmentVarOrUnCachedAndroidProperty(kCaptureLabel, kAndroidCaptureLabel);
3947 if (!labelFromEnv.empty())
3948 {
3949 // Optional label to provide unique file names and namespaces
3950 mCaptureLabel = labelFromEnv;
3951 }
3952
3953 std::string compressionFromEnv =
3954 GetEnvironmentVarOrUnCachedAndroidProperty(kCompression, kAndroidCompression);
3955 if (compressionFromEnv == "0")
3956 {
3957 mCompression = false;
3958 }
3959 std::string serializeStateEnabledFromEnv =
3960 angle::GetEnvironmentVar(kSerializeStateEnabledVarName);
3961 if (serializeStateEnabledFromEnv == "1")
3962 {
3963 mSerializeStateEnabled = true;
3964 }
3965 }
3966
3967 FrameCaptureShared::~FrameCaptureShared() = default;
3968
copyCompressedTextureData(const gl::Context * context,const CallCapture & call)3969 void FrameCaptureShared::copyCompressedTextureData(const gl::Context *context,
3970 const CallCapture &call)
3971 {
3972 // For compressed textures, we need to copy the source data that was already captured into a new
3973 // cached texture entry for use during mid-execution capture, rather than reading it back with
3974 // ANGLE_get_image.
3975
3976 GLenum srcTarget = call.params.getParam("srcTarget", ParamType::TGLenum, 1).value.GLenumVal;
3977 GLenum dstTarget = call.params.getParam("dstTarget", ParamType::TGLenum, 7).value.GLenumVal;
3978
3979 // TODO(anglebug.com/6104): Type of incoming ID varies based on target type, but we're only
3980 // handling textures for now. If either of these asserts fire, then we need to add renderbuffer
3981 // support.
3982 ASSERT(srcTarget == GL_TEXTURE_2D || srcTarget == GL_TEXTURE_2D_ARRAY ||
3983 srcTarget == GL_TEXTURE_3D || srcTarget == GL_TEXTURE_CUBE_MAP);
3984 ASSERT(dstTarget == GL_TEXTURE_2D || dstTarget == GL_TEXTURE_2D_ARRAY ||
3985 dstTarget == GL_TEXTURE_3D || dstTarget == GL_TEXTURE_CUBE_MAP);
3986
3987 gl::TextureID srcName =
3988 call.params.getParam("srcName", ParamType::TTextureID, 0).value.TextureIDVal;
3989 GLint srcLevel = call.params.getParam("srcLevel", ParamType::TGLint, 2).value.GLintVal;
3990 gl::TextureID dstName =
3991 call.params.getParam("dstName", ParamType::TTextureID, 6).value.TextureIDVal;
3992 GLint dstLevel = call.params.getParam("dstLevel", ParamType::TGLint, 8).value.GLintVal;
3993
3994 // Look up the texture type
3995 gl::TextureTarget dstTargetPacked = gl::PackParam<gl::TextureTarget>(dstTarget);
3996 gl::TextureType dstTextureType = gl::TextureTargetToType(dstTargetPacked);
3997
3998 // Look up the currently bound texture
3999 gl::Texture *dstTexture = context->getState().getTargetTexture(dstTextureType);
4000 ASSERT(dstTexture);
4001
4002 const gl::InternalFormat &dstFormat = *dstTexture->getFormat(dstTargetPacked, dstLevel).info;
4003
4004 if (dstFormat.compressed)
4005 {
4006 context->getShareGroup()->getFrameCaptureShared()->copyCachedTextureLevel(
4007 context, srcName, srcLevel, dstName, dstLevel, call);
4008 }
4009 }
4010
captureCompressedTextureData(const gl::Context * context,const CallCapture & call)4011 void FrameCaptureShared::captureCompressedTextureData(const gl::Context *context,
4012 const CallCapture &call)
4013 {
4014 // For compressed textures, track a shadow copy of the data
4015 // for use during mid-execution capture, rather than reading it back
4016 // with ANGLE_get_image
4017
4018 // Storing the compressed data is handled the same for all entry points,
4019 // they just have slightly different parameter locations
4020 int dataParamOffset = -1;
4021 int xoffsetParamOffset = -1;
4022 int yoffsetParamOffset = -1;
4023 int zoffsetParamOffset = -1;
4024 int widthParamOffset = -1;
4025 int heightParamOffset = -1;
4026 int depthParamOffset = -1;
4027 switch (call.entryPoint)
4028 {
4029 case EntryPoint::GLCompressedTexSubImage3D:
4030 xoffsetParamOffset = 2;
4031 yoffsetParamOffset = 3;
4032 zoffsetParamOffset = 4;
4033 widthParamOffset = 5;
4034 heightParamOffset = 6;
4035 depthParamOffset = 7;
4036 dataParamOffset = 10;
4037 break;
4038 case EntryPoint::GLCompressedTexImage3D:
4039 widthParamOffset = 3;
4040 heightParamOffset = 4;
4041 depthParamOffset = 5;
4042 dataParamOffset = 8;
4043 break;
4044 case EntryPoint::GLCompressedTexSubImage2D:
4045 xoffsetParamOffset = 2;
4046 yoffsetParamOffset = 3;
4047 widthParamOffset = 4;
4048 heightParamOffset = 5;
4049 dataParamOffset = 8;
4050 break;
4051 case EntryPoint::GLCompressedTexImage2D:
4052 widthParamOffset = 3;
4053 heightParamOffset = 4;
4054 dataParamOffset = 7;
4055 break;
4056 default:
4057 // There should be no other callers of this function
4058 ASSERT(0);
4059 break;
4060 }
4061
4062 gl::Buffer *pixelUnpackBuffer =
4063 context->getState().getTargetBuffer(gl::BufferBinding::PixelUnpack);
4064
4065 const uint8_t *data = static_cast<const uint8_t *>(
4066 call.params.getParam("data", ParamType::TvoidConstPointer, dataParamOffset)
4067 .value.voidConstPointerVal);
4068
4069 GLsizei imageSize = call.params.getParam("imageSize", ParamType::TGLsizei, dataParamOffset - 1)
4070 .value.GLsizeiVal;
4071
4072 const uint8_t *pixelData = nullptr;
4073
4074 if (pixelUnpackBuffer)
4075 {
4076 // If using pixel unpack buffer, map the buffer and track its data
4077 ASSERT(!pixelUnpackBuffer->isMapped());
4078 (void)pixelUnpackBuffer->mapRange(context, reinterpret_cast<GLintptr>(data), imageSize,
4079 GL_MAP_READ_BIT);
4080
4081 pixelData = reinterpret_cast<const uint8_t *>(pixelUnpackBuffer->getMapPointer());
4082 }
4083 else
4084 {
4085 pixelData = data;
4086 }
4087
4088 if (!pixelData)
4089 {
4090 // If no pointer was provided and we weren't able to map the buffer, there is no data to
4091 // capture
4092 return;
4093 }
4094
4095 // Look up the texture type
4096 gl::TextureTarget targetPacked =
4097 call.params.getParam("targetPacked", ParamType::TTextureTarget, 0).value.TextureTargetVal;
4098 gl::TextureType textureType = gl::TextureTargetToType(targetPacked);
4099
4100 // Create a copy of the incoming data
4101 std::vector<uint8_t> compressedData;
4102 compressedData.assign(pixelData, pixelData + imageSize);
4103
4104 // Look up the currently bound texture
4105 gl::Texture *texture = context->getState().getTargetTexture(textureType);
4106 ASSERT(texture);
4107
4108 // Record the data, indexed by textureID and level
4109 GLint level = call.params.getParam("level", ParamType::TGLint, 1).value.GLintVal;
4110 std::vector<uint8_t> &levelData =
4111 context->getShareGroup()->getFrameCaptureShared()->getCachedTextureLevelData(
4112 texture, targetPacked, level, call.entryPoint);
4113
4114 // Unpack the various pixel rectangle parameters.
4115 ASSERT(widthParamOffset != -1);
4116 ASSERT(heightParamOffset != -1);
4117 GLsizei pixelWidth =
4118 call.params.getParam("width", ParamType::TGLsizei, widthParamOffset).value.GLsizeiVal;
4119 GLsizei pixelHeight =
4120 call.params.getParam("height", ParamType::TGLsizei, heightParamOffset).value.GLsizeiVal;
4121 GLsizei pixelDepth = 1;
4122 if (depthParamOffset != -1)
4123 {
4124 pixelDepth =
4125 call.params.getParam("depth", ParamType::TGLsizei, depthParamOffset).value.GLsizeiVal;
4126 }
4127
4128 GLint xoffset = 0;
4129 GLint yoffset = 0;
4130 GLint zoffset = 0;
4131
4132 if (xoffsetParamOffset != -1)
4133 {
4134 xoffset =
4135 call.params.getParam("xoffset", ParamType::TGLint, xoffsetParamOffset).value.GLintVal;
4136 }
4137
4138 if (yoffsetParamOffset != -1)
4139 {
4140 yoffset =
4141 call.params.getParam("yoffset", ParamType::TGLint, yoffsetParamOffset).value.GLintVal;
4142 }
4143
4144 if (zoffsetParamOffset != -1)
4145 {
4146 zoffset =
4147 call.params.getParam("zoffset", ParamType::TGLint, zoffsetParamOffset).value.GLintVal;
4148 }
4149
4150 // Get the format of the texture for use with the compressed block size math.
4151 const gl::InternalFormat &format = *texture->getFormat(targetPacked, level).info;
4152
4153 // Divide dimensions according to block size.
4154 const gl::Extents &levelExtents = texture->getExtents(targetPacked, level);
4155
4156 // Scale down the width/height pixel offsets to reflect block size
4157 int blockWidth = static_cast<int>(format.compressedBlockWidth);
4158 int blockHeight = static_cast<int>(format.compressedBlockHeight);
4159 ASSERT(format.compressedBlockDepth == 1);
4160
4161 // Round the incoming width and height up to align with block size
4162 pixelWidth = rx::roundUp(pixelWidth, blockWidth);
4163 pixelHeight = rx::roundUp(pixelHeight, blockHeight);
4164
4165 // Scale the width, height, and offsets
4166 pixelWidth /= blockWidth;
4167 pixelHeight /= blockHeight;
4168 xoffset /= blockWidth;
4169 yoffset /= blockHeight;
4170
4171 GLint pixelBytes = static_cast<GLint>(format.pixelBytes);
4172
4173 // Also round the texture's width and height up to reflect block size
4174 int levelWidth = rx::roundUp(levelExtents.width, blockWidth);
4175 int levelHeight = rx::roundUp(levelExtents.height, blockHeight);
4176
4177 GLint pixelRowPitch = pixelWidth * pixelBytes;
4178 GLint pixelDepthPitch = pixelRowPitch * pixelHeight;
4179 GLint levelRowPitch = (levelWidth / blockWidth) * pixelBytes;
4180 GLint levelDepthPitch = (levelHeight / blockHeight) * levelRowPitch;
4181
4182 for (GLint zindex = 0; zindex < pixelDepth; ++zindex)
4183 {
4184 GLint z = zindex + zoffset;
4185 for (GLint yindex = 0; yindex < pixelHeight; ++yindex)
4186 {
4187 GLint y = yindex + yoffset;
4188 GLint pixelOffset = zindex * pixelDepthPitch + yindex * pixelRowPitch;
4189 GLint levelOffset = z * levelDepthPitch + y * levelRowPitch + xoffset * pixelBytes;
4190 ASSERT(static_cast<size_t>(levelOffset + pixelRowPitch) <= levelData.size());
4191 memcpy(&levelData[levelOffset], &pixelData[pixelOffset], pixelRowPitch);
4192 }
4193 }
4194
4195 if (pixelUnpackBuffer)
4196 {
4197 GLboolean success;
4198 (void)pixelUnpackBuffer->unmap(context, &success);
4199 ASSERT(success);
4200 }
4201 }
4202
trackBufferMapping(CallCapture * call,gl::BufferID id,GLintptr offset,GLsizeiptr length,bool writable)4203 void FrameCaptureShared::trackBufferMapping(CallCapture *call,
4204 gl::BufferID id,
4205 GLintptr offset,
4206 GLsizeiptr length,
4207 bool writable)
4208 {
4209 // Track that the buffer was mapped
4210 mResourceTracker.setBufferMapped(id);
4211
4212 if (writable)
4213 {
4214 // If this buffer was mapped writable, we don't have any visibility into what
4215 // happens to it. Therefore, remember the details about it, and we'll read it back
4216 // on Unmap to repopulate it during replay.
4217 mBufferDataMap[id] = std::make_pair(offset, length);
4218
4219 // Track that this buffer was potentially modified
4220 mResourceTracker.setBufferModified(id);
4221
4222 // Track the bufferID that was just mapped for use when writing return value
4223 call->params.setMappedBufferID(id);
4224 }
4225 }
4226
updateCopyImageSubData(CallCapture & call)4227 void FrameCaptureShared::updateCopyImageSubData(CallCapture &call)
4228 {
4229 // This call modifies srcName and dstName to no longer be object IDs (GLuint), but actual
4230 // packed types that can remapped using gTextureMap and gRenderbufferMap
4231
4232 GLint srcName = call.params.getParam("srcName", ParamType::TGLuint, 0).value.GLuintVal;
4233 GLenum srcTarget = call.params.getParam("srcTarget", ParamType::TGLenum, 1).value.GLenumVal;
4234 switch (srcTarget)
4235 {
4236 case GL_RENDERBUFFER:
4237 {
4238 // Convert the GLuint to RenderbufferID
4239 gl::RenderbufferID srcRenderbufferID = {static_cast<GLuint>(srcName)};
4240 call.params.setValueParamAtIndex("srcName", ParamType::TRenderbufferID,
4241 srcRenderbufferID, 0);
4242 break;
4243 }
4244 case GL_TEXTURE_2D:
4245 case GL_TEXTURE_2D_ARRAY:
4246 case GL_TEXTURE_3D:
4247 case GL_TEXTURE_CUBE_MAP:
4248 {
4249 // Convert the GLuint to TextureID
4250 gl::TextureID srcTextureID = {static_cast<GLuint>(srcName)};
4251 call.params.setValueParamAtIndex("srcName", ParamType::TTextureID, srcTextureID, 0);
4252 break;
4253 }
4254 default:
4255 ERR() << "Unhandled srcTarget = " << srcTarget;
4256 UNREACHABLE();
4257 break;
4258 }
4259
4260 // Change dstName to the appropriate type based on dstTarget
4261 GLint dstName = call.params.getParam("dstName", ParamType::TGLuint, 6).value.GLuintVal;
4262 GLenum dstTarget = call.params.getParam("dstTarget", ParamType::TGLenum, 7).value.GLenumVal;
4263 switch (dstTarget)
4264 {
4265 case GL_RENDERBUFFER:
4266 {
4267 // Convert the GLuint to RenderbufferID
4268 gl::RenderbufferID dstRenderbufferID = {static_cast<GLuint>(dstName)};
4269 call.params.setValueParamAtIndex("dstName", ParamType::TRenderbufferID,
4270 dstRenderbufferID, 6);
4271 break;
4272 }
4273 case GL_TEXTURE_2D:
4274 case GL_TEXTURE_2D_ARRAY:
4275 case GL_TEXTURE_3D:
4276 case GL_TEXTURE_CUBE_MAP:
4277 {
4278 // Convert the GLuint to TextureID
4279 gl::TextureID dstTextureID = {static_cast<GLuint>(dstName)};
4280 call.params.setValueParamAtIndex("dstName", ParamType::TTextureID, dstTextureID, 6);
4281 break;
4282 }
4283 default:
4284 ERR() << "Unhandled dstTarget = " << dstTarget;
4285 UNREACHABLE();
4286 break;
4287 }
4288 }
4289
maybeOverrideEntryPoint(const gl::Context * context,CallCapture & call)4290 void FrameCaptureShared::maybeOverrideEntryPoint(const gl::Context *context, CallCapture &call)
4291 {
4292 switch (call.entryPoint)
4293 {
4294 case EntryPoint::GLEGLImageTargetTexture2DOES:
4295 {
4296 // We don't support reading EGLImages. Instead, just pull from a tiny null texture.
4297 // TODO (anglebug.com/4964): Read back the image data and populate the texture.
4298 std::vector<uint8_t> pixelData = {0, 0, 0, 0};
4299 call = CaptureTexSubImage2D(context->getState(), true, gl::TextureTarget::_2D, 0, 0, 0,
4300 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixelData.data());
4301 break;
4302 }
4303 case EntryPoint::GLEGLImageTargetRenderbufferStorageOES:
4304 {
4305 UNIMPLEMENTED();
4306 break;
4307 }
4308 case EntryPoint::GLCopyImageSubData:
4309 case EntryPoint::GLCopyImageSubDataEXT:
4310 case EntryPoint::GLCopyImageSubDataOES:
4311 {
4312 // We must look at the src and dst target types to determine which remap table to use
4313 updateCopyImageSubData(call);
4314 break;
4315 }
4316 default:
4317 break;
4318 }
4319 }
4320
maybeCaptureDrawArraysClientData(const gl::Context * context,CallCapture & call,size_t instanceCount)4321 void FrameCaptureShared::maybeCaptureDrawArraysClientData(const gl::Context *context,
4322 CallCapture &call,
4323 size_t instanceCount)
4324 {
4325 if (!context->getStateCache().hasAnyActiveClientAttrib())
4326 {
4327 return;
4328 }
4329
4330 // Get counts from paramBuffer.
4331 GLint firstVertex =
4332 call.params.getParamFlexName("first", "start", ParamType::TGLint, 1).value.GLintVal;
4333 GLsizei drawCount = call.params.getParam("count", ParamType::TGLsizei, 2).value.GLsizeiVal;
4334 captureClientArraySnapshot(context, firstVertex + drawCount, instanceCount);
4335 }
4336
maybeCaptureDrawElementsClientData(const gl::Context * context,CallCapture & call,size_t instanceCount)4337 void FrameCaptureShared::maybeCaptureDrawElementsClientData(const gl::Context *context,
4338 CallCapture &call,
4339 size_t instanceCount)
4340 {
4341 if (!context->getStateCache().hasAnyActiveClientAttrib())
4342 {
4343 return;
4344 }
4345
4346 // if the count is zero then the index evaluation is not valid and we wouldn't be drawing
4347 // anything anyway, so skip capturing
4348 GLsizei count = call.params.getParam("count", ParamType::TGLsizei, 1).value.GLsizeiVal;
4349 if (count == 0)
4350 {
4351 return;
4352 }
4353
4354 gl::DrawElementsType drawElementsType =
4355 call.params.getParam("typePacked", ParamType::TDrawElementsType, 2)
4356 .value.DrawElementsTypeVal;
4357 const void *indices =
4358 call.params.getParam("indices", ParamType::TvoidConstPointer, 3).value.voidConstPointerVal;
4359
4360 gl::IndexRange indexRange;
4361
4362 bool restart = context->getState().isPrimitiveRestartEnabled();
4363
4364 gl::Buffer *elementArrayBuffer = context->getState().getVertexArray()->getElementArrayBuffer();
4365 if (elementArrayBuffer)
4366 {
4367 size_t offset = reinterpret_cast<size_t>(indices);
4368 (void)elementArrayBuffer->getIndexRange(context, drawElementsType, offset, count, restart,
4369 &indexRange);
4370 }
4371 else
4372 {
4373 ASSERT(indices);
4374 indexRange = gl::ComputeIndexRange(drawElementsType, indices, count, restart);
4375 }
4376
4377 // index starts from 0
4378 captureClientArraySnapshot(context, indexRange.end + 1, instanceCount);
4379 }
4380
maybeCapturePreCallUpdates(const gl::Context * context,CallCapture & call)4381 void FrameCaptureShared::maybeCapturePreCallUpdates(const gl::Context *context, CallCapture &call)
4382 {
4383 switch (call.entryPoint)
4384 {
4385 case EntryPoint::GLVertexAttribPointer:
4386 case EntryPoint::GLVertexPointer:
4387 case EntryPoint::GLColorPointer:
4388 case EntryPoint::GLTexCoordPointer:
4389 case EntryPoint::GLNormalPointer:
4390 case EntryPoint::GLPointSizePointerOES:
4391 {
4392 // Get array location
4393 GLuint index = 0;
4394 if (call.entryPoint == EntryPoint::GLVertexAttribPointer)
4395 {
4396 index = call.params.getParam("index", ParamType::TGLuint, 0).value.GLuintVal;
4397 }
4398 else
4399 {
4400 gl::ClientVertexArrayType type;
4401 switch (call.entryPoint)
4402 {
4403 case EntryPoint::GLVertexPointer:
4404 type = gl::ClientVertexArrayType::Vertex;
4405 break;
4406 case EntryPoint::GLColorPointer:
4407 type = gl::ClientVertexArrayType::Color;
4408 break;
4409 case EntryPoint::GLTexCoordPointer:
4410 type = gl::ClientVertexArrayType::TextureCoord;
4411 break;
4412 case EntryPoint::GLNormalPointer:
4413 type = gl::ClientVertexArrayType::Normal;
4414 break;
4415 case EntryPoint::GLPointSizePointerOES:
4416 type = gl::ClientVertexArrayType::PointSize;
4417 break;
4418 default:
4419 UNREACHABLE();
4420 type = gl::ClientVertexArrayType::InvalidEnum;
4421 }
4422 index = gl::GLES1Renderer::VertexArrayIndex(type, context->getState().gles1());
4423 }
4424
4425 if (call.params.hasClientArrayData())
4426 {
4427 mClientVertexArrayMap[index] = static_cast<int>(mFrameCalls.size());
4428 }
4429 else
4430 {
4431 mClientVertexArrayMap[index] = -1;
4432 }
4433 break;
4434 }
4435
4436 case EntryPoint::GLDeleteBuffers:
4437 {
4438 GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
4439 const gl::BufferID *bufferIDs =
4440 call.params.getParam("buffersPacked", ParamType::TBufferIDConstPointer, 1)
4441 .value.BufferIDConstPointerVal;
4442 FrameCaptureShared *frameCaptureShared =
4443 context->getShareGroup()->getFrameCaptureShared();
4444 ResourceTracker &resourceTracker = context->getFrameCaptureSharedResourceTracker();
4445 for (GLsizei i = 0; i < count; i++)
4446 {
4447 // For each buffer being deleted, check our backup of data and remove it
4448 const auto &bufferDataInfo = mBufferDataMap.find(bufferIDs[i]);
4449 if (bufferDataInfo != mBufferDataMap.end())
4450 {
4451 mBufferDataMap.erase(bufferDataInfo);
4452 }
4453 // If we're capturing, track what buffers have been deleted
4454 if (frameCaptureShared->isCaptureActive())
4455 {
4456 resourceTracker.setDeletedBuffer(bufferIDs[i]);
4457 }
4458 }
4459 break;
4460 }
4461
4462 case EntryPoint::GLGenBuffers:
4463 {
4464 GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
4465 const gl::BufferID *bufferIDs =
4466 call.params.getParam("buffersPacked", ParamType::TBufferIDPointer, 1)
4467 .value.BufferIDPointerVal;
4468 FrameCaptureShared *frameCaptureShared =
4469 context->getShareGroup()->getFrameCaptureShared();
4470 ResourceTracker &resourceTracker = context->getFrameCaptureSharedResourceTracker();
4471 for (GLsizei i = 0; i < count; i++)
4472 {
4473 // If we're capturing, track what new buffers have been genned
4474 if (frameCaptureShared->isCaptureActive())
4475 {
4476 resourceTracker.setGennedBuffer(bufferIDs[i]);
4477 }
4478 }
4479 break;
4480 }
4481
4482 case EntryPoint::GLDeleteSync:
4483 {
4484 GLsync sync = call.params.getParam("sync", ParamType::TGLsync, 0).value.GLsyncVal;
4485 FrameCaptureShared *frameCaptureShared =
4486 context->getShareGroup()->getFrameCaptureShared();
4487 ResourceTracker &resourceTracker = context->getFrameCaptureSharedResourceTracker();
4488 // If we're capturing, track which fence sync has been deleted
4489 if (frameCaptureShared->isCaptureActive())
4490 {
4491 resourceTracker.setDeletedFenceSync(sync);
4492 }
4493 break;
4494 }
4495
4496 case EntryPoint::GLDrawArrays:
4497 {
4498 maybeCaptureDrawArraysClientData(context, call, 1);
4499 break;
4500 }
4501
4502 case EntryPoint::GLDrawArraysInstanced:
4503 case EntryPoint::GLDrawArraysInstancedANGLE:
4504 case EntryPoint::GLDrawArraysInstancedEXT:
4505 {
4506 GLsizei instancecount =
4507 call.params.getParamFlexName("instancecount", "primcount", ParamType::TGLsizei, 3)
4508 .value.GLsizeiVal;
4509 maybeCaptureDrawArraysClientData(context, call, instancecount);
4510 break;
4511 }
4512
4513 case EntryPoint::GLDrawElements:
4514 {
4515 maybeCaptureDrawElementsClientData(context, call, 1);
4516 break;
4517 }
4518
4519 case EntryPoint::GLDrawElementsInstanced:
4520 case EntryPoint::GLDrawElementsInstancedANGLE:
4521 case EntryPoint::GLDrawElementsInstancedEXT:
4522 {
4523 GLsizei instancecount =
4524 call.params.getParamFlexName("instancecount", "primcount", ParamType::TGLsizei, 4)
4525 .value.GLsizeiVal;
4526 maybeCaptureDrawElementsClientData(context, call, instancecount);
4527 break;
4528 }
4529
4530 case EntryPoint::GLCreateShaderProgramv:
4531 {
4532 // Refresh the cached shader sources.
4533 // The command CreateShaderProgramv() creates a stand-alone program from an array of
4534 // null-terminated source code strings for a single shader type, so we need update the
4535 // Shader and Program sources, similar to GLCompileShader + GLLinkProgram handling.
4536 gl::ShaderProgramID programID = {call.params.getReturnValue().value.GLuintVal};
4537 const ParamCapture ¶mCapture =
4538 call.params.getParam("typePacked", ParamType::TShaderType, 0);
4539 gl::ShaderType shaderType = paramCapture.value.ShaderTypeVal;
4540 gl::Program *program = context->getProgramResolveLink(programID);
4541 ASSERT(program);
4542 const gl::Shader *shader = program->getAttachedShader(shaderType);
4543 ASSERT(shader);
4544 FrameCaptureShared *frameCaptureShared =
4545 context->getShareGroup()->getFrameCaptureShared();
4546 frameCaptureShared->setShaderSource(shader->getHandle(), shader->getSourceString());
4547 frameCaptureShared->setProgramSources(programID, GetAttachedProgramSources(program));
4548
4549 if (isCaptureActive())
4550 {
4551 mResourceTracker.setCreatedProgram(programID);
4552 }
4553 break;
4554 }
4555
4556 case EntryPoint::GLCreateProgram:
4557 {
4558 // If we're capturing, track which programs have been created
4559 if (isCaptureActive())
4560 {
4561 gl::ShaderProgramID programID = {call.params.getReturnValue().value.GLuintVal};
4562 mResourceTracker.setCreatedProgram(programID);
4563 }
4564 break;
4565 }
4566
4567 case EntryPoint::GLDeleteProgram:
4568 {
4569 // If we're capturing, track which programs have been deleted
4570 if (isCaptureActive())
4571 {
4572 const ParamCapture ¶m =
4573 call.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
4574
4575 mResourceTracker.setDeletedProgram(param.value.ShaderProgramIDVal);
4576 }
4577 break;
4578 }
4579
4580 case EntryPoint::GLCompileShader:
4581 {
4582 // Refresh the cached shader sources.
4583 gl::ShaderProgramID shaderID =
4584 call.params.getParam("shaderPacked", ParamType::TShaderProgramID, 0)
4585 .value.ShaderProgramIDVal;
4586 const gl::Shader *shader = context->getShader(shaderID);
4587 context->getShareGroup()->getFrameCaptureShared()->setShaderSource(
4588 shaderID, shader->getSourceString());
4589 break;
4590 }
4591
4592 case EntryPoint::GLLinkProgram:
4593 {
4594 // Refresh the cached program sources.
4595 gl::ShaderProgramID programID =
4596 call.params.getParam("programPacked", ParamType::TShaderProgramID, 0)
4597 .value.ShaderProgramIDVal;
4598 const gl::Program *program = context->getProgramResolveLink(programID);
4599 context->getShareGroup()->getFrameCaptureShared()->setProgramSources(
4600 programID, GetAttachedProgramSources(program));
4601 break;
4602 }
4603
4604 case EntryPoint::GLCompressedTexImage1D:
4605 case EntryPoint::GLCompressedTexSubImage1D:
4606 {
4607 UNIMPLEMENTED();
4608 break;
4609 }
4610
4611 case EntryPoint::GLCompressedTexImage2D:
4612 case EntryPoint::GLCompressedTexImage3D:
4613 case EntryPoint::GLCompressedTexSubImage2D:
4614 case EntryPoint::GLCompressedTexSubImage3D:
4615 {
4616 captureCompressedTextureData(context, call);
4617 break;
4618 }
4619
4620 case EntryPoint::GLCopyImageSubData:
4621 case EntryPoint::GLCopyImageSubDataEXT:
4622 case EntryPoint::GLCopyImageSubDataOES:
4623 {
4624 // glCopyImageSubData supports copying compressed and uncompressed texture formats.
4625 copyCompressedTextureData(context, call);
4626 break;
4627 }
4628
4629 case EntryPoint::GLDeleteTextures:
4630 {
4631 // Free any TextureLevelDataMap entries being tracked for this texture
4632 // This is to cover the scenario where a texture has been created, its
4633 // levels cached, then texture deleted and recreated, receiving the same ID
4634
4635 // Look up how many textures are being deleted
4636 GLsizei n = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
4637
4638 // Look up the pointer to list of textures
4639 const gl::TextureID *textureIDs =
4640 call.params.getParam("texturesPacked", ParamType::TTextureIDConstPointer, 1)
4641 .value.TextureIDConstPointerVal;
4642
4643 // For each texture listed for deletion
4644 for (int32_t i = 0; i < n; ++i)
4645 {
4646 // Look it up in the cache, and delete it if found
4647 context->getShareGroup()->getFrameCaptureShared()->deleteCachedTextureLevelData(
4648 textureIDs[i]);
4649 }
4650 break;
4651 }
4652
4653 case EntryPoint::GLMapBuffer:
4654 case EntryPoint::GLMapBufferOES:
4655 {
4656 gl::BufferBinding target =
4657 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
4658 .value.BufferBindingVal;
4659
4660 GLbitfield access =
4661 call.params.getParam("access", ParamType::TGLenum, 1).value.GLenumVal;
4662
4663 gl::Buffer *buffer = context->getState().getTargetBuffer(target);
4664
4665 GLintptr offset = 0;
4666 GLsizeiptr length = static_cast<GLsizeiptr>(buffer->getSize());
4667
4668 bool writable =
4669 access == GL_WRITE_ONLY_OES || access == GL_WRITE_ONLY || access == GL_READ_WRITE;
4670
4671 FrameCaptureShared *frameCaptureShared =
4672 context->getShareGroup()->getFrameCaptureShared();
4673 frameCaptureShared->trackBufferMapping(&call, buffer->id(), offset, length, writable);
4674 break;
4675 }
4676
4677 case EntryPoint::GLUnmapNamedBuffer:
4678 {
4679 UNIMPLEMENTED();
4680 break;
4681 }
4682
4683 case EntryPoint::GLMapBufferRange:
4684 case EntryPoint::GLMapBufferRangeEXT:
4685 {
4686 GLintptr offset =
4687 call.params.getParam("offset", ParamType::TGLintptr, 1).value.GLintptrVal;
4688 GLsizeiptr length =
4689 call.params.getParam("length", ParamType::TGLsizeiptr, 2).value.GLsizeiptrVal;
4690 GLbitfield access =
4691 call.params.getParam("access", ParamType::TGLbitfield, 3).value.GLbitfieldVal;
4692
4693 gl::BufferBinding target =
4694 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
4695 .value.BufferBindingVal;
4696 gl::Buffer *buffer = context->getState().getTargetBuffer(target);
4697
4698 FrameCaptureShared *frameCaptureShared =
4699 context->getShareGroup()->getFrameCaptureShared();
4700 frameCaptureShared->trackBufferMapping(&call, buffer->id(), offset, length,
4701 access & GL_MAP_WRITE_BIT);
4702 break;
4703 }
4704
4705 case EntryPoint::GLUnmapBuffer:
4706 case EntryPoint::GLUnmapBufferOES:
4707 {
4708 // See if we need to capture the buffer contents
4709 captureMappedBufferSnapshot(context, call);
4710
4711 // Track that the buffer was unmapped, for use during state reset
4712 ResourceTracker &resourceTracker = context->getFrameCaptureSharedResourceTracker();
4713 gl::BufferBinding target =
4714 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
4715 .value.BufferBindingVal;
4716 gl::Buffer *buffer = context->getState().getTargetBuffer(target);
4717 resourceTracker.setBufferUnmapped(buffer->id());
4718 break;
4719 }
4720
4721 case EntryPoint::GLBufferData:
4722 case EntryPoint::GLBufferSubData:
4723 {
4724 gl::BufferBinding target =
4725 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
4726 .value.BufferBindingVal;
4727
4728 gl::Buffer *buffer = context->getState().getTargetBuffer(target);
4729
4730 // Track that this buffer's contents have been modified
4731 ResourceTracker &resourceTracker = context->getFrameCaptureSharedResourceTracker();
4732 resourceTracker.setBufferModified(buffer->id());
4733
4734 // BufferData is equivalent to UnmapBuffer, for what we're tracking.
4735 // From the ES 3.1 spec in BufferData section:
4736 // If any portion of the buffer object is mapped in the current context or any
4737 // context current to another thread, it is as though UnmapBuffer (see section
4738 // 6.3.1) is executed in each such context prior to deleting the existing data
4739 // store.
4740 // Track that the buffer was unmapped, for use during state reset
4741 resourceTracker.setBufferUnmapped(buffer->id());
4742
4743 break;
4744 }
4745 default:
4746 break;
4747 }
4748
4749 updateReadBufferSize(call.params.getReadBufferSize());
4750
4751 gl::ShaderProgramID shaderProgramID;
4752 if (FindShaderProgramIDInCall(call, &shaderProgramID))
4753 {
4754 ResourceTracker &resourceTracker = context->getFrameCaptureSharedResourceTracker();
4755 resourceTracker.onShaderProgramAccess(shaderProgramID);
4756 }
4757 }
4758
captureCall(const gl::Context * context,CallCapture && call,bool isCallValid)4759 void FrameCaptureShared::captureCall(const gl::Context *context,
4760 CallCapture &&call,
4761 bool isCallValid)
4762 {
4763 if (SkipCall(call.entryPoint))
4764 {
4765 return;
4766 }
4767
4768 maybeOverrideEntryPoint(context, call);
4769
4770 maybeCapturePreCallUpdates(context, call);
4771
4772 if (isCallValid)
4773 {
4774 mFrameCalls.emplace_back(std::move(call));
4775 }
4776 else
4777 {
4778 INFO() << "FrameCapture: Not capturing invalid call to "
4779 << GetEntryPointName(call.entryPoint);
4780 }
4781
4782 maybeCapturePostCallUpdates(context);
4783 }
4784
maybeCapturePostCallUpdates(const gl::Context * context)4785 void FrameCaptureShared::maybeCapturePostCallUpdates(const gl::Context *context)
4786 {
4787 // Process resource ID updates.
4788 MaybeCaptureUpdateResourceIDs(&mFrameCalls);
4789
4790 const CallCapture &lastCall = mFrameCalls.back();
4791 switch (lastCall.entryPoint)
4792 {
4793 case EntryPoint::GLCreateShaderProgramv:
4794 {
4795 gl::ShaderProgramID programId;
4796 programId.value = lastCall.params.getReturnValue().value.GLuintVal;
4797 const gl::Program *program = context->getProgramResolveLink(programId);
4798 CaptureUpdateUniformLocations(program, &mFrameCalls);
4799 CaptureUpdateUniformBlockIndexes(program, &mFrameCalls);
4800 break;
4801 }
4802 case EntryPoint::GLLinkProgram:
4803 {
4804 const ParamCapture ¶m =
4805 lastCall.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
4806 const gl::Program *program =
4807 context->getProgramResolveLink(param.value.ShaderProgramIDVal);
4808 CaptureUpdateUniformLocations(program, &mFrameCalls);
4809 CaptureUpdateUniformBlockIndexes(program, &mFrameCalls);
4810 break;
4811 }
4812 case EntryPoint::GLUseProgram:
4813 CaptureUpdateCurrentProgram(lastCall, &mFrameCalls);
4814 break;
4815 case EntryPoint::GLDeleteProgram:
4816 {
4817 const ParamCapture ¶m =
4818 lastCall.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
4819 CaptureDeleteUniformLocations(param.value.ShaderProgramIDVal, &mFrameCalls);
4820 break;
4821 }
4822 default:
4823 break;
4824 }
4825 }
4826
captureClientArraySnapshot(const gl::Context * context,size_t vertexCount,size_t instanceCount)4827 void FrameCaptureShared::captureClientArraySnapshot(const gl::Context *context,
4828 size_t vertexCount,
4829 size_t instanceCount)
4830 {
4831 const gl::VertexArray *vao = context->getState().getVertexArray();
4832
4833 // Capture client array data.
4834 for (size_t attribIndex : context->getStateCache().getActiveClientAttribsMask())
4835 {
4836 const gl::VertexAttribute &attrib = vao->getVertexAttribute(attribIndex);
4837 const gl::VertexBinding &binding = vao->getVertexBinding(attrib.bindingIndex);
4838
4839 int callIndex = mClientVertexArrayMap[attribIndex];
4840
4841 if (callIndex != -1)
4842 {
4843 size_t count = vertexCount;
4844
4845 if (binding.getDivisor() > 0)
4846 {
4847 count = rx::UnsignedCeilDivide(static_cast<uint32_t>(instanceCount),
4848 binding.getDivisor());
4849 }
4850
4851 // The last capture element doesn't take up the full stride.
4852 size_t bytesToCapture = (count - 1) * binding.getStride() + attrib.format->pixelBytes;
4853
4854 CallCapture &call = mFrameCalls[callIndex];
4855 ParamCapture ¶m = call.params.getClientArrayPointerParameter();
4856 ASSERT(param.type == ParamType::TvoidConstPointer);
4857
4858 ParamBuffer updateParamBuffer;
4859 updateParamBuffer.addValueParam<GLint>("arrayIndex", ParamType::TGLint,
4860 static_cast<uint32_t>(attribIndex));
4861
4862 ParamCapture updateMemory("pointer", ParamType::TvoidConstPointer);
4863 CaptureMemory(param.value.voidConstPointerVal, bytesToCapture, &updateMemory);
4864 updateParamBuffer.addParam(std::move(updateMemory));
4865
4866 updateParamBuffer.addValueParam<GLuint64>("size", ParamType::TGLuint64, bytesToCapture);
4867
4868 mFrameCalls.emplace_back("UpdateClientArrayPointer", std::move(updateParamBuffer));
4869
4870 mClientArraySizes[attribIndex] =
4871 std::max(mClientArraySizes[attribIndex], bytesToCapture);
4872 }
4873 }
4874 }
4875
captureMappedBufferSnapshot(const gl::Context * context,const CallCapture & call)4876 void FrameCaptureShared::captureMappedBufferSnapshot(const gl::Context *context,
4877 const CallCapture &call)
4878 {
4879 // If the buffer was mapped writable, we need to restore its data, since we have no visibility
4880 // into what the client did to the buffer while mapped
4881 // This sequence will result in replay calls like this:
4882 // ...
4883 // gMappedBufferData[gBufferMap[42]] = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, 65536,
4884 // GL_MAP_WRITE_BIT);
4885 // ...
4886 // UpdateClientBufferData(42, &gBinaryData[164631024], 65536);
4887 // glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
4888 // ...
4889
4890 // Re-map the buffer, using the info we tracked about the buffer
4891 gl::BufferBinding target =
4892 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0).value.BufferBindingVal;
4893
4894 FrameCaptureShared *frameCaptureShared = context->getShareGroup()->getFrameCaptureShared();
4895 gl::Buffer *buffer = context->getState().getTargetBuffer(target);
4896 if (!frameCaptureShared->hasBufferData(buffer->id()))
4897 {
4898 // This buffer was not marked writable, so we did not back it up
4899 return;
4900 }
4901
4902 std::pair<GLintptr, GLsizeiptr> bufferDataOffsetAndLength =
4903 frameCaptureShared->getBufferDataOffsetAndLength(buffer->id());
4904 GLintptr offset = bufferDataOffsetAndLength.first;
4905 GLsizeiptr length = bufferDataOffsetAndLength.second;
4906
4907 // Map the buffer so we can copy its contents out
4908 ASSERT(!buffer->isMapped());
4909 angle::Result result = buffer->mapRange(context, offset, length, GL_MAP_READ_BIT);
4910 if (result != angle::Result::Continue)
4911 {
4912 ERR() << "Failed to mapRange of buffer" << std::endl;
4913 }
4914 const uint8_t *data = reinterpret_cast<const uint8_t *>(buffer->getMapPointer());
4915
4916 // Create the parameters to our helper for use during replay
4917 ParamBuffer dataParamBuffer;
4918
4919 // Pass in the target buffer ID
4920 dataParamBuffer.addValueParam("dest", ParamType::TGLuint, buffer->id().value);
4921
4922 // Capture the current buffer data with a binary param
4923 ParamCapture captureData("source", ParamType::TvoidConstPointer);
4924 CaptureMemory(data, length, &captureData);
4925 dataParamBuffer.addParam(std::move(captureData));
4926
4927 // Also track its size for use with memcpy
4928 dataParamBuffer.addValueParam<GLsizeiptr>("size", ParamType::TGLsizeiptr, length);
4929
4930 // Call the helper that populates the buffer with captured data
4931 mFrameCalls.emplace_back("UpdateClientBufferData", std::move(dataParamBuffer));
4932
4933 // Unmap the buffer and move on
4934 GLboolean dontCare;
4935 (void)buffer->unmap(context, &dontCare);
4936 }
4937
checkForCaptureTrigger()4938 void FrameCaptureShared::checkForCaptureTrigger()
4939 {
4940 // If the capture trigger has not been set, move on
4941 if (mCaptureTrigger == 0)
4942 {
4943 return;
4944 }
4945
4946 // Otherwise, poll the value for a change
4947 std::string captureTriggerStr = GetCaptureTrigger();
4948 if (captureTriggerStr.empty())
4949 {
4950 return;
4951 }
4952
4953 // If the value has changed, use the original value as the frame count
4954 // TODO (anglebug.com/4949): Improve capture at unknown frame time. It is good to
4955 // avoid polling if the feature is not enabled, but not entirely intuitive to set
4956 // a value to zero when you want to trigger it.
4957 uint32_t captureTrigger = atoi(captureTriggerStr.c_str());
4958 if (captureTrigger != mCaptureTrigger)
4959 {
4960 // Start mid-execution capture for the next frame
4961 mCaptureStartFrame = mFrameIndex + 1;
4962
4963 // Use the original trigger value as the frame count
4964 mCaptureEndFrame = mCaptureStartFrame + (mCaptureTrigger - 1);
4965
4966 INFO() << "Capture triggered after frame " << mFrameIndex << " for " << mCaptureTrigger
4967 << " frames";
4968
4969 // Stop polling
4970 mCaptureTrigger = 0;
4971 }
4972 }
4973
setupSharedAndAuxReplay(const gl::Context * context,bool isMidExecutionCapture)4974 void FrameCaptureShared::setupSharedAndAuxReplay(const gl::Context *context,
4975 bool isMidExecutionCapture)
4976 {
4977 // Make sure all pending work for every Context in the share group has completed so all data
4978 // (buffers, textures, etc.) has been updated and no resources are in use.
4979 egl::ShareGroup *shareGroup = context->getShareGroup();
4980 const egl::ContextSet *shareContextSet = shareGroup->getContexts();
4981 for (gl::Context *shareContext : *shareContextSet)
4982 {
4983 shareContext->finish();
4984 }
4985
4986 clearSetupCalls();
4987 if (isMidExecutionCapture)
4988 {
4989 CaptureSharedContextMidExecutionSetup(context, &mSetupCalls, &mResourceTracker);
4990 }
4991
4992 WriteSharedContextCppReplay(mCompression, mOutDirectory, mCaptureLabel, 1, 1, mSetupCalls,
4993 &mResourceTracker, &mBinaryData, mSerializeStateEnabled, *this);
4994
4995 for (const gl::Context *shareContext : *shareContextSet)
4996 {
4997 FrameCapture *frameCapture = shareContext->getFrameCapture();
4998 frameCapture->clearSetupCalls();
4999
5000 if (isMidExecutionCapture)
5001 {
5002 CaptureMidExecutionSetup(shareContext, &frameCapture->getSetupCalls(),
5003 &mResourceTracker);
5004 }
5005
5006 if (!frameCapture->getSetupCalls().empty() && shareContext->id() != context->id())
5007 {
5008 // The presentation context's setup functions will be written later as part of the
5009 // WriteWindowSurfaceContextCppReplay() output.
5010 WriteAuxiliaryContextCppSetupReplay(mCompression, mOutDirectory, shareContext,
5011 mCaptureLabel, 1, frameCapture->getSetupCalls(),
5012 &mBinaryData, mSerializeStateEnabled, *this);
5013 }
5014 }
5015 }
5016
onEndFrame(const gl::Context * context)5017 void FrameCaptureShared::onEndFrame(const gl::Context *context)
5018 {
5019 if (!enabled() || mFrameIndex > mCaptureEndFrame)
5020 {
5021 setCaptureInactive();
5022 return;
5023 }
5024
5025 FrameCapture *frameCapture = context->getFrameCapture();
5026
5027 // Count resource IDs. This is also done on every frame. It could probably be done by
5028 // checking the GL state instead of the calls.
5029 for (const CallCapture &call : mFrameCalls)
5030 {
5031 for (const ParamCapture ¶m : call.params.getParamCaptures())
5032 {
5033 ResourceIDType idType = GetResourceIDTypeFromParamType(param.type);
5034 if (idType != ResourceIDType::InvalidEnum)
5035 {
5036 mHasResourceType.set(idType);
5037 }
5038 }
5039 }
5040
5041 // On Android, we can trigger a capture during the run
5042 checkForCaptureTrigger();
5043 // Done after checkForCaptureTrigger(), since that can modify mCaptureStartFrame.
5044 if (mFrameIndex >= mCaptureStartFrame)
5045 {
5046 setCaptureActive();
5047 // Assume that the context performing the swap is the "main" context.
5048 mWindowSurfaceContextID = context->id();
5049 }
5050 else
5051 {
5052 reset();
5053 mFrameIndex++;
5054
5055 // When performing a mid-execution capture, setup the replay before capturing calls for the
5056 // first frame.
5057 if (mFrameIndex == mCaptureStartFrame)
5058 {
5059 setupSharedAndAuxReplay(context, true);
5060 }
5061
5062 // Not capturing yet, so return.
5063 return;
5064 }
5065
5066 if (mIsFirstFrame)
5067 {
5068 mCaptureStartFrame = mFrameIndex;
5069
5070 // When *not* performing a mid-execution capture, setup the replay with the first frame.
5071 if (mCaptureStartFrame == 1)
5072 {
5073 setupSharedAndAuxReplay(context, false);
5074 }
5075 }
5076
5077 if (!mFrameCalls.empty())
5078 {
5079 mActiveFrameIndices.push_back(getReplayFrameIndex());
5080 }
5081
5082 // Note that we currently capture before the start frame to collect shader and program sources.
5083 // For simplicity, it's currently a requirement that the same context is used to perform the
5084 // swap every frame.
5085 ASSERT(mWindowSurfaceContextID == context->id());
5086
5087 // Make sure all pending work for every Context in the share group has completed so all data
5088 // (buffers, textures, etc.) has been updated and no resources are in use.
5089 egl::ShareGroup *shareGroup = context->getShareGroup();
5090 const egl::ContextSet *shareContextSet = shareGroup->getContexts();
5091 for (gl::Context *shareContext : *shareContextSet)
5092 {
5093 shareContext->finish();
5094 }
5095
5096 WriteWindowSurfaceContextCppReplay(mCompression, mOutDirectory, context, mCaptureLabel,
5097 getReplayFrameIndex(), getFrameCount(), mFrameCalls,
5098 frameCapture->getSetupCalls(), &mResourceTracker,
5099 &mBinaryData, mSerializeStateEnabled, *this);
5100
5101 if (mFrameIndex == mCaptureEndFrame)
5102 {
5103 // Save the index files after the last frame.
5104 writeCppReplayIndexFiles(context, false);
5105 SaveBinaryData(mCompression, mOutDirectory, kSharedContextId, mCaptureLabel, mBinaryData);
5106 mBinaryData.clear();
5107 mWroteIndexFile = true;
5108 }
5109
5110 reset();
5111 mFrameIndex++;
5112 mIsFirstFrame = false;
5113 }
5114
onDestroyContext(const gl::Context * context)5115 void FrameCaptureShared::onDestroyContext(const gl::Context *context)
5116 {
5117 if (!mEnabled)
5118 {
5119 return;
5120 }
5121 if (!mWroteIndexFile && mFrameIndex > mCaptureStartFrame)
5122 {
5123 // If context is destroyed before end frame is reached and at least
5124 // 1 frame has been recorded, then write the index files.
5125 // It doesnt make sense to write the index files when no frame has been recorded
5126 mFrameIndex -= 1;
5127 mCaptureEndFrame = mFrameIndex;
5128 writeCppReplayIndexFiles(context, true);
5129 SaveBinaryData(mCompression, mOutDirectory, kSharedContextId, mCaptureLabel, mBinaryData);
5130 mBinaryData.clear();
5131 mWroteIndexFile = true;
5132 }
5133 }
5134
onMakeCurrent(const gl::Context * context,const egl::Surface * drawSurface)5135 void FrameCaptureShared::onMakeCurrent(const gl::Context *context, const egl::Surface *drawSurface)
5136 {
5137 if (!drawSurface)
5138 {
5139 return;
5140 }
5141
5142 // Track the width and height of the draw surface as provided to makeCurrent
5143 mDrawSurfaceDimensions[context->id()] =
5144 gl::Extents(drawSurface->getWidth(), drawSurface->getHeight(), 1);
5145 }
5146
5147 DataCounters::DataCounters() = default;
5148
5149 DataCounters::~DataCounters() = default;
5150
getAndIncrement(EntryPoint entryPoint,const std::string & paramName)5151 int DataCounters::getAndIncrement(EntryPoint entryPoint, const std::string ¶mName)
5152 {
5153 Counter counterKey = {entryPoint, paramName};
5154 return mData[counterKey]++;
5155 }
5156
5157 DataTracker::DataTracker() = default;
5158
5159 DataTracker::~DataTracker() = default;
5160
5161 StringCounters::StringCounters() = default;
5162
5163 StringCounters::~StringCounters() = default;
5164
getStringCounter(std::vector<std::string> & strings)5165 int StringCounters::getStringCounter(std::vector<std::string> &strings)
5166 {
5167 const auto &id = mStringCounterMap.find(strings);
5168 if (id == mStringCounterMap.end())
5169 {
5170 return kStringsNotFound;
5171 }
5172 else
5173 {
5174 return mStringCounterMap[strings];
5175 }
5176 }
5177
setStringCounter(std::vector<std::string> & strings,int & counter)5178 void StringCounters::setStringCounter(std::vector<std::string> &strings, int &counter)
5179 {
5180 ASSERT(counter >= 0);
5181 mStringCounterMap[strings] = counter;
5182 }
5183
5184 ResourceTracker::ResourceTracker() = default;
5185
5186 ResourceTracker::~ResourceTracker() = default;
5187
setDeletedBuffer(gl::BufferID id)5188 void ResourceTracker::setDeletedBuffer(gl::BufferID id)
5189 {
5190 if (id.value == 0)
5191 {
5192 // Ignore buffer ID 0
5193 return;
5194 }
5195
5196 if (mNewBuffers.find(id) != mNewBuffers.end())
5197 {
5198 // This is a buffer genned after MEC was initialized, just clear it, since there will be no
5199 // actions required for it to return to starting state.
5200 mNewBuffers.erase(id);
5201 return;
5202 }
5203
5204 if (mStartingBuffers.find(id) != mStartingBuffers.end())
5205 {
5206 // The app is deleting a buffer we started with, we need to regen on loop
5207 mBuffersToRegen.insert(id);
5208 mBuffersToRestore.insert(id);
5209 }
5210
5211 // If none of the above is true, the app is deleting a buffer that was never genned.
5212 // This is allowed by the spec for DeleteBuffers:
5213 // Unused names in buffers are silently ignored, as is the value zero.
5214 }
5215
setDeletedFenceSync(GLsync sync)5216 void ResourceTracker::setDeletedFenceSync(GLsync sync)
5217 {
5218 ASSERT(sync != nullptr);
5219 if (mStartingFenceSyncs.find(sync) == mStartingFenceSyncs.end())
5220 {
5221 // This is a fence sync created after MEC was initialized. Ignore it.
5222 return;
5223 }
5224
5225 // In this case, the app is deleting a fence sync we started with, we need to regen on loop.
5226 mFenceSyncsToRegen.insert(sync);
5227 }
5228
setCreatedProgram(gl::ShaderProgramID id)5229 void ResourceTracker::setCreatedProgram(gl::ShaderProgramID id)
5230 {
5231 if (mStartingPrograms.find(id) == mStartingPrograms.end())
5232 {
5233 // This is a program created after MEC was initialized, track it
5234 mNewPrograms.insert(id);
5235 return;
5236 }
5237 }
5238
setDeletedProgram(gl::ShaderProgramID id)5239 void ResourceTracker::setDeletedProgram(gl::ShaderProgramID id)
5240 {
5241 if (id.value == 0)
5242 {
5243 // Ignore program ID 0
5244 return;
5245 }
5246
5247 if (mNewPrograms.find(id) != mNewPrograms.end())
5248 {
5249 // This is a program created after MEC was initialized, just clear it, since there will be
5250 // no actions required for it to return to starting state.
5251 mNewPrograms.erase(id);
5252 return;
5253 }
5254
5255 // Ensure this program was in our starting set
5256 // It's possible this could fire if the app deletes programs that were never generated
5257 ASSERT(mStartingPrograms.empty() || (mStartingPrograms.find(id) != mStartingPrograms.end()));
5258
5259 // In this case, the app is deleting a program we started with, we need to regen on loop
5260 mProgramsToRegen.insert(id);
5261 }
5262
setGennedBuffer(gl::BufferID id)5263 void ResourceTracker::setGennedBuffer(gl::BufferID id)
5264 {
5265 if (mStartingBuffers.find(id) == mStartingBuffers.end())
5266 {
5267 // This is a buffer genned after MEC was initialized, track it
5268 mNewBuffers.insert(id);
5269 return;
5270 }
5271 }
5272
setBufferModified(gl::BufferID id)5273 void ResourceTracker::setBufferModified(gl::BufferID id)
5274 {
5275 // If this was a starting buffer, we need to track it for restore
5276 if (mStartingBuffers.find(id) != mStartingBuffers.end())
5277 {
5278 mBuffersToRestore.insert(id);
5279 }
5280 }
5281
setBufferMapped(gl::BufferID id)5282 void ResourceTracker::setBufferMapped(gl::BufferID id)
5283 {
5284 // If this was a starting buffer, we may need to restore it to original state during Reset
5285 if (mStartingBuffers.find(id) != mStartingBuffers.end())
5286 {
5287 // Track that its current state is mapped (true)
5288 mStartingBuffersMappedCurrent[id] = true;
5289 }
5290 }
5291
setBufferUnmapped(gl::BufferID id)5292 void ResourceTracker::setBufferUnmapped(gl::BufferID id)
5293 {
5294 // If this was a starting buffer, we may need to restore it to original state during Reset
5295 if (mStartingBuffers.find(id) != mStartingBuffers.end())
5296 {
5297 // Track that its current state is unmapped (false)
5298 mStartingBuffersMappedCurrent[id] = false;
5299 }
5300 }
5301
onShaderProgramAccess(gl::ShaderProgramID shaderProgramID)5302 void ResourceTracker::onShaderProgramAccess(gl::ShaderProgramID shaderProgramID)
5303 {
5304 mMaxShaderPrograms = std::max(mMaxShaderPrograms, shaderProgramID.value + 1);
5305 }
5306
isCapturing() const5307 bool FrameCaptureShared::isCapturing() const
5308 {
5309 // Currently we will always do a capture up until the last frame. In the future we could improve
5310 // mid execution capture by only capturing between the start and end frames. The only necessary
5311 // reason we need to capture before the start is for attached program and shader sources.
5312 return mEnabled && mFrameIndex <= mCaptureEndFrame;
5313 }
5314
getFrameCount() const5315 uint32_t FrameCaptureShared::getFrameCount() const
5316 {
5317 return mCaptureEndFrame - mCaptureStartFrame + 1;
5318 }
5319
getReplayFrameIndex() const5320 uint32_t FrameCaptureShared::getReplayFrameIndex() const
5321 {
5322 return mFrameIndex - mCaptureStartFrame + 1;
5323 }
5324
replay(gl::Context * context)5325 void FrameCaptureShared::replay(gl::Context *context)
5326 {
5327 ReplayContext replayContext(mReadBufferSize, mClientArraySizes);
5328 for (const CallCapture &call : mFrameCalls)
5329 {
5330 INFO() << "frame index: " << mFrameIndex << " " << call.name();
5331
5332 if (call.entryPoint == EntryPoint::GLInvalid)
5333 {
5334 if (call.customFunctionName == "UpdateClientArrayPointer")
5335 {
5336 GLint arrayIndex =
5337 call.params.getParam("arrayIndex", ParamType::TGLint, 0).value.GLintVal;
5338 ASSERT(arrayIndex < gl::MAX_VERTEX_ATTRIBS);
5339
5340 const ParamCapture &pointerParam =
5341 call.params.getParam("pointer", ParamType::TvoidConstPointer, 1);
5342 ASSERT(pointerParam.data.size() == 1);
5343 const void *pointer = pointerParam.data[0].data();
5344
5345 size_t size = static_cast<size_t>(
5346 call.params.getParam("size", ParamType::TGLuint64, 2).value.GLuint64Val);
5347
5348 std::vector<uint8_t> &curClientArrayBuffer =
5349 replayContext.getClientArraysBuffer()[arrayIndex];
5350 ASSERT(curClientArrayBuffer.size() >= size);
5351 memcpy(curClientArrayBuffer.data(), pointer, size);
5352 }
5353 continue;
5354 }
5355
5356 ReplayCall(context, &replayContext, call);
5357 }
5358 }
5359
writeCppReplayIndexFiles(const gl::Context * context,bool writeResetContextCall)5360 void FrameCaptureShared::writeCppReplayIndexFiles(const gl::Context *context,
5361 bool writeResetContextCall)
5362 {
5363 const gl::ContextID contextId = context->id();
5364 const egl::Config *config = context->getConfig();
5365 const egl::AttributeMap &attributes = context->getDisplay()->getAttributeMap();
5366
5367 unsigned frameCount = getFrameCount();
5368
5369 std::stringstream header;
5370 std::stringstream source;
5371
5372 header << "#pragma once\n";
5373 header << "\n";
5374 header << "#include <EGL/egl.h>\n";
5375 header << "#include <cstdint>\n";
5376 header << "\n";
5377
5378 if (!mCaptureLabel.empty())
5379 {
5380 header << "namespace " << mCaptureLabel << "\n";
5381 header << "{\n";
5382 }
5383 header << "// Begin Trace Metadata\n";
5384 header << "#define ANGLE_REPLAY_VERSION";
5385 if (!mCaptureLabel.empty())
5386 {
5387 std::string captureLabelUpper = mCaptureLabel;
5388 angle::ToUpper(&captureLabelUpper);
5389 header << "_" << captureLabelUpper;
5390 }
5391 header << " " << ANGLE_REVISION << "\n";
5392 header << "constexpr uint32_t kReplayContextClientMajorVersion = "
5393 << context->getClientMajorVersion() << ";\n";
5394 header << "constexpr uint32_t kReplayContextClientMinorVersion = "
5395 << context->getClientMinorVersion() << ";\n";
5396 header << "constexpr EGLint kReplayPlatformType = "
5397 << attributes.getAsInt(EGL_PLATFORM_ANGLE_TYPE_ANGLE) << ";\n";
5398 header << "constexpr EGLint kReplayDeviceType = "
5399 << attributes.getAsInt(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE) << ";\n";
5400 header << "constexpr uint32_t kReplayFrameStart = 1;\n";
5401 header << "constexpr uint32_t kReplayFrameEnd = " << frameCount << ";\n";
5402 header << "constexpr EGLint kReplayDrawSurfaceWidth = "
5403 << mDrawSurfaceDimensions.at(contextId).width << ";\n";
5404 header << "constexpr EGLint kReplayDrawSurfaceHeight = "
5405 << mDrawSurfaceDimensions.at(contextId).height << ";\n";
5406 header << "constexpr EGLint kDefaultFramebufferRedBits = "
5407 << (config ? std::to_string(config->redSize) : "EGL_DONT_CARE") << ";\n";
5408 header << "constexpr EGLint kDefaultFramebufferGreenBits = "
5409 << (config ? std::to_string(config->greenSize) : "EGL_DONT_CARE") << ";\n";
5410 header << "constexpr EGLint kDefaultFramebufferBlueBits = "
5411 << (config ? std::to_string(config->blueSize) : "EGL_DONT_CARE") << ";\n";
5412 header << "constexpr EGLint kDefaultFramebufferAlphaBits = "
5413 << (config ? std::to_string(config->alphaSize) : "EGL_DONT_CARE") << ";\n";
5414 header << "constexpr EGLint kDefaultFramebufferDepthBits = "
5415 << (config ? std::to_string(config->depthSize) : "EGL_DONT_CARE") << ";\n";
5416 header << "constexpr EGLint kDefaultFramebufferStencilBits = "
5417 << (config ? std::to_string(config->stencilSize) : "EGL_DONT_CARE") << ";\n";
5418 header << "constexpr bool kIsBinaryDataCompressed = " << (mCompression ? "true" : "false")
5419 << ";\n";
5420 header << "constexpr bool kAreClientArraysEnabled = "
5421 << (context->getState().areClientArraysEnabled() ? "true" : "false") << ";\n";
5422 header << "constexpr bool kbindGeneratesResources = "
5423 << (context->getState().isBindGeneratesResourceEnabled() ? "true" : "false") << ";\n";
5424 header << "constexpr bool kWebGLCompatibility = "
5425 << (context->getState().getExtensions().webglCompatibility ? "true" : "false") << ";\n";
5426 header << "constexpr bool kRobustResourceInit = "
5427 << (context->getState().isRobustResourceInitEnabled() ? "true" : "false") << ";\n";
5428
5429 header << "// End Trace Metadata\n";
5430 header << "\n";
5431 for (uint32_t frameIndex = 1; frameIndex <= frameCount; ++frameIndex)
5432 {
5433 header << "void " << FmtReplayFunction(contextId, frameIndex) << ";\n";
5434 }
5435 header << "\n";
5436 if (mSerializeStateEnabled)
5437 {
5438 for (uint32_t frameIndex = 1; frameIndex <= frameCount; ++frameIndex)
5439 {
5440 header << "const char *" << FmtGetSerializedContextStateFunction(contextId, frameIndex)
5441 << ";\n";
5442 }
5443 header << "\n";
5444 }
5445
5446 header << "void InitReplay();\n";
5447
5448 source << "#include \"" << FmtCapturePrefix(contextId, mCaptureLabel) << ".h\"\n";
5449 source << "#include \"trace_fixture.h\"\n";
5450 source << "#include \"angle_trace_gl.h\"\n";
5451 source << "\n";
5452
5453 if (!mCaptureLabel.empty())
5454 {
5455 source << "using namespace " << mCaptureLabel << ";\n";
5456 source << "\n";
5457 }
5458
5459 source << "void " << mCaptureLabel << "::InitReplay()\n";
5460 source << "{\n";
5461 WriteInitReplayCall(mCompression, source, kSharedContextId, mCaptureLabel,
5462 MaxClientArraySize(mClientArraySizes), mReadBufferSize);
5463 source << "}\n";
5464
5465 source << "extern \"C\" {\n";
5466 source << "void ReplayFrame(uint32_t frameIndex)\n";
5467 source << "{\n";
5468 source << " switch (frameIndex)\n";
5469 source << " {\n";
5470 for (uint32_t frameIndex : mActiveFrameIndices)
5471 {
5472 source << " case " << frameIndex << ":\n";
5473 source << " " << FmtReplayFunction(contextId, frameIndex) << ";\n";
5474 source << " break;\n";
5475 }
5476 source << " default:\n";
5477 source << " break;\n";
5478 source << " }\n";
5479 source << "}\n";
5480 source << "\n";
5481
5482 if (writeResetContextCall)
5483 {
5484 source << "void ResetReplay()\n";
5485 source << "{\n";
5486 source << " // Reset context is empty because context is destroyed before end "
5487 "frame is reached\n";
5488 source << "}\n";
5489 source << "\n";
5490 }
5491
5492 if (mSerializeStateEnabled)
5493 {
5494 source << "const char *GetSerializedContextState(uint32_t frameIndex)\n";
5495 source << "{\n";
5496 source << " switch (frameIndex)\n";
5497 source << " {\n";
5498 for (uint32_t frameIndex = 1; frameIndex <= frameCount; ++frameIndex)
5499 {
5500 source << " case " << frameIndex << ":\n";
5501 source << " return "
5502 << FmtGetSerializedContextStateFunction(contextId, frameIndex) << ";\n";
5503 }
5504 source << " default:\n";
5505 source << " return \"\";\n";
5506 source << " }\n";
5507 source << "}\n";
5508 source << "\n";
5509 }
5510
5511 source << "} // extern \"C\"\n";
5512
5513 if (!mCaptureLabel.empty())
5514 {
5515 header << "} // namespace " << mCaptureLabel << "\n";
5516 }
5517
5518 {
5519 std::string headerContents = header.str();
5520
5521 std::stringstream headerPathStream;
5522 headerPathStream << mOutDirectory << FmtCapturePrefix(contextId, mCaptureLabel) << ".h";
5523 std::string headerPath = headerPathStream.str();
5524
5525 SaveFileHelper saveHeader(headerPath);
5526 saveHeader << headerContents;
5527 }
5528
5529 {
5530 std::string sourceContents = source.str();
5531
5532 std::stringstream sourcePathStream;
5533 sourcePathStream << mOutDirectory << FmtCapturePrefix(contextId, mCaptureLabel) << ".cpp";
5534 std::string sourcePath = sourcePathStream.str();
5535
5536 SaveFileHelper saveSource(sourcePath);
5537 saveSource << sourceContents;
5538 }
5539
5540 {
5541 std::stringstream indexPathStream;
5542 indexPathStream << mOutDirectory << FmtCapturePrefix(contextId, mCaptureLabel)
5543 << "_files.txt";
5544 std::string indexPath = indexPathStream.str();
5545
5546 SaveFileHelper saveIndex(indexPath);
5547 for (uint32_t frameIndex = 1; frameIndex <= frameCount; ++frameIndex)
5548 {
5549 saveIndex << GetCaptureFileName(contextId, mCaptureLabel, frameIndex, ".cpp") << "\n";
5550 }
5551
5552 egl::ShareGroup *shareGroup = context->getShareGroup();
5553 egl::ContextSet *shareContextSet = shareGroup->getContexts();
5554 for (gl::Context *shareContext : *shareContextSet)
5555 {
5556 if (shareContext->id() == contextId)
5557 {
5558 // We already listed all of the "main" context's files, so skip it here.
5559 continue;
5560 }
5561 saveIndex << GetCaptureFileName(shareContext->id(), mCaptureLabel, 1, ".cpp") << "\n";
5562 }
5563 saveIndex << GetCaptureFileName(kSharedContextId, mCaptureLabel, 1, ".cpp") << "\n";
5564 }
5565 }
5566
reset()5567 void FrameCaptureShared::reset()
5568 {
5569 mFrameCalls.clear();
5570 mClientVertexArrayMap.fill(-1);
5571
5572 // Do not reset replay-specific settings like the maximum read buffer size, client array sizes,
5573 // or the 'has seen' type map. We could refine this into per-frame and per-capture maximums if
5574 // necessary.
5575 }
5576
getShaderSource(gl::ShaderProgramID id) const5577 const std::string &FrameCaptureShared::getShaderSource(gl::ShaderProgramID id) const
5578 {
5579 const auto &foundSources = mCachedShaderSource.find(id);
5580 ASSERT(foundSources != mCachedShaderSource.end());
5581 return foundSources->second;
5582 }
5583
setShaderSource(gl::ShaderProgramID id,std::string source)5584 void FrameCaptureShared::setShaderSource(gl::ShaderProgramID id, std::string source)
5585 {
5586 mCachedShaderSource[id] = source;
5587 }
5588
getProgramSources(gl::ShaderProgramID id) const5589 const ProgramSources &FrameCaptureShared::getProgramSources(gl::ShaderProgramID id) const
5590 {
5591 const auto &foundSources = mCachedProgramSources.find(id);
5592 ASSERT(foundSources != mCachedProgramSources.end());
5593 return foundSources->second;
5594 }
5595
setProgramSources(gl::ShaderProgramID id,ProgramSources sources)5596 void FrameCaptureShared::setProgramSources(gl::ShaderProgramID id, ProgramSources sources)
5597 {
5598 mCachedProgramSources[id] = sources;
5599 }
5600
retrieveCachedTextureLevel(gl::TextureID id,gl::TextureTarget target,GLint level)5601 const std::vector<uint8_t> &FrameCaptureShared::retrieveCachedTextureLevel(gl::TextureID id,
5602 gl::TextureTarget target,
5603 GLint level)
5604 {
5605 // Look up the data for the requested texture
5606 const auto &foundTextureLevels = mCachedTextureLevelData.find(id);
5607 ASSERT(foundTextureLevels != mCachedTextureLevelData.end());
5608
5609 GLint adjustedLevel = GetAdjustedTextureCacheLevel(target, level);
5610
5611 const auto &foundTextureLevel = foundTextureLevels->second.find(adjustedLevel);
5612 ASSERT(foundTextureLevel != foundTextureLevels->second.end());
5613 const std::vector<uint8_t> &capturedTextureLevel = foundTextureLevel->second;
5614
5615 return capturedTextureLevel;
5616 }
5617
copyCachedTextureLevel(const gl::Context * context,gl::TextureID srcID,GLint srcLevel,gl::TextureID dstID,GLint dstLevel,const CallCapture & call)5618 void FrameCaptureShared::copyCachedTextureLevel(const gl::Context *context,
5619 gl::TextureID srcID,
5620 GLint srcLevel,
5621 gl::TextureID dstID,
5622 GLint dstLevel,
5623 const CallCapture &call)
5624 {
5625 // TODO(http://anglebug.com/5604): Add support for partial level copies.
5626 ASSERT(call.params.getParam("srcX", ParamType::TGLint, 3).value.GLintVal == 0);
5627 ASSERT(call.params.getParam("srcY", ParamType::TGLint, 4).value.GLintVal == 0);
5628 ASSERT(call.params.getParam("srcZ", ParamType::TGLint, 5).value.GLintVal == 0);
5629 ASSERT(call.params.getParam("dstX", ParamType::TGLint, 9).value.GLintVal == 0);
5630 ASSERT(call.params.getParam("dstY", ParamType::TGLint, 10).value.GLintVal == 0);
5631 ASSERT(call.params.getParam("dstZ", ParamType::TGLint, 11).value.GLintVal == 0);
5632 GLenum srcTarget = call.params.getParam("srcTarget", ParamType::TGLenum, 1).value.GLenumVal;
5633 GLsizei srcWidth = call.params.getParam("srcWidth", ParamType::TGLsizei, 12).value.GLsizeiVal;
5634 GLsizei srcHeight = call.params.getParam("srcHeight", ParamType::TGLsizei, 13).value.GLsizeiVal;
5635 GLsizei srcDepth = call.params.getParam("srcDepth", ParamType::TGLsizei, 14).value.GLsizeiVal;
5636 gl::Texture *srcTexture = context->getTexture({srcID});
5637 gl::TextureTarget srcTargetPacked = gl::PackParam<gl::TextureTarget>(srcTarget);
5638 const gl::Extents &srcExtents = srcTexture->getExtents(srcTargetPacked, srcLevel);
5639 ASSERT(srcExtents.width == srcWidth && srcExtents.height == srcHeight &&
5640 srcExtents.depth == srcDepth);
5641
5642 // Look up the data for the source texture
5643 const auto &foundSrcTextureLevels = mCachedTextureLevelData.find(srcID);
5644 ASSERT(foundSrcTextureLevels != mCachedTextureLevelData.end());
5645
5646 // For that texture, look up the data for the given level
5647 const auto &foundSrcTextureLevel = foundSrcTextureLevels->second.find(srcLevel);
5648 ASSERT(foundSrcTextureLevel != foundSrcTextureLevels->second.end());
5649 const std::vector<uint8_t> &srcTextureLevel = foundSrcTextureLevel->second;
5650
5651 auto foundDstTextureLevels = mCachedTextureLevelData.find(dstID);
5652 if (foundDstTextureLevels == mCachedTextureLevelData.end())
5653 {
5654 // Initialize the texture ID data.
5655 auto emplaceResult = mCachedTextureLevelData.emplace(dstID, TextureLevels());
5656 ASSERT(emplaceResult.second);
5657 foundDstTextureLevels = emplaceResult.first;
5658 }
5659
5660 TextureLevels &foundDstLevels = foundDstTextureLevels->second;
5661 TextureLevels::iterator foundDstLevel = foundDstLevels.find(dstLevel);
5662 if (foundDstLevel != foundDstLevels.end())
5663 {
5664 // If we have a cache for this level, remove it since we're recreating it.
5665 foundDstLevels.erase(dstLevel);
5666 }
5667
5668 // Initialize destination texture data and copy the source into it.
5669 std::vector<uint8_t> dstTextureLevel = srcTextureLevel;
5670 auto emplaceResult = foundDstLevels.emplace(dstLevel, std::move(dstTextureLevel));
5671 ASSERT(emplaceResult.second);
5672 }
5673
getCachedTextureLevelData(gl::Texture * texture,gl::TextureTarget target,GLint textureLevel,EntryPoint entryPoint)5674 std::vector<uint8_t> &FrameCaptureShared::getCachedTextureLevelData(gl::Texture *texture,
5675 gl::TextureTarget target,
5676 GLint textureLevel,
5677 EntryPoint entryPoint)
5678 {
5679 auto foundTextureLevels = mCachedTextureLevelData.find(texture->id());
5680 if (foundTextureLevels == mCachedTextureLevelData.end())
5681 {
5682 // Initialize the texture ID data.
5683 auto emplaceResult = mCachedTextureLevelData.emplace(texture->id(), TextureLevels());
5684 ASSERT(emplaceResult.second);
5685 foundTextureLevels = emplaceResult.first;
5686 }
5687
5688 // For this texture, look up the adjusted level, which may not match 1:1 due to cubes
5689 GLint adjustedLevel = GetAdjustedTextureCacheLevel(target, textureLevel);
5690
5691 TextureLevels &foundLevels = foundTextureLevels->second;
5692 TextureLevels::iterator foundLevel = foundLevels.find(adjustedLevel);
5693 if (foundLevel != foundLevels.end())
5694 {
5695 if (entryPoint == EntryPoint::GLCompressedTexImage2D ||
5696 entryPoint == EntryPoint::GLCompressedTexImage3D)
5697 {
5698 // Delete the cached entry in case the caller is respecifying the level.
5699 foundLevels.erase(adjustedLevel);
5700 }
5701 else
5702 {
5703 ASSERT(entryPoint == EntryPoint::GLCompressedTexSubImage2D ||
5704 entryPoint == EntryPoint::GLCompressedTexSubImage3D);
5705
5706 // If we have a cache for this level, return it now
5707 return foundLevel->second;
5708 }
5709 }
5710
5711 // Otherwise, create an appropriately sized cache for this level
5712
5713 // Get the format of the texture for use with the compressed block size math.
5714 const gl::InternalFormat &format = *texture->getFormat(target, textureLevel).info;
5715
5716 // Divide dimensions according to block size.
5717 const gl::Extents &levelExtents = texture->getExtents(target, textureLevel);
5718
5719 // Calculate the size needed to store the compressed level
5720 GLuint sizeInBytes;
5721 bool result = format.computeCompressedImageSize(levelExtents, &sizeInBytes);
5722 ASSERT(result);
5723
5724 // Initialize texture rectangle data. Default init to zero for stability.
5725 std::vector<uint8_t> newPixelData(sizeInBytes, 0);
5726 auto emplaceResult = foundLevels.emplace(adjustedLevel, std::move(newPixelData));
5727 ASSERT(emplaceResult.second);
5728
5729 // Using the level entry we just created, return the location (a byte vector) where compressed
5730 // texture level data should be stored
5731 return emplaceResult.first->second;
5732 }
5733
deleteCachedTextureLevelData(gl::TextureID id)5734 void FrameCaptureShared::deleteCachedTextureLevelData(gl::TextureID id)
5735 {
5736 const auto &foundTextureLevels = mCachedTextureLevelData.find(id);
5737 if (foundTextureLevels != mCachedTextureLevelData.end())
5738 {
5739 // Delete all texture levels at once
5740 mCachedTextureLevelData.erase(foundTextureLevels);
5741 }
5742 }
5743
CaptureMemory(const void * source,size_t size,ParamCapture * paramCapture)5744 void CaptureMemory(const void *source, size_t size, ParamCapture *paramCapture)
5745 {
5746 std::vector<uint8_t> data(size);
5747 memcpy(data.data(), source, size);
5748 paramCapture->data.emplace_back(std::move(data));
5749 }
5750
CaptureString(const GLchar * str,ParamCapture * paramCapture)5751 void CaptureString(const GLchar *str, ParamCapture *paramCapture)
5752 {
5753 // include the '\0' suffix
5754 CaptureMemory(str, strlen(str) + 1, paramCapture);
5755 }
5756
CaptureStringLimit(const GLchar * str,uint32_t limit,ParamCapture * paramCapture)5757 void CaptureStringLimit(const GLchar *str, uint32_t limit, ParamCapture *paramCapture)
5758 {
5759 // Write the incoming string up to limit, including null terminator
5760 size_t length = strlen(str) + 1;
5761
5762 if (length > limit)
5763 {
5764 // If too many characters, resize the string to fit in the limit
5765 std::string newStr = str;
5766 newStr.resize(limit - 1);
5767 CaptureString(newStr.c_str(), paramCapture);
5768 }
5769 else
5770 {
5771 CaptureMemory(str, length, paramCapture);
5772 }
5773 }
5774
CaptureVertexPointerGLES1(const gl::State & glState,gl::ClientVertexArrayType type,const void * pointer,ParamCapture * paramCapture)5775 void CaptureVertexPointerGLES1(const gl::State &glState,
5776 gl::ClientVertexArrayType type,
5777 const void *pointer,
5778 ParamCapture *paramCapture)
5779 {
5780 paramCapture->value.voidConstPointerVal = pointer;
5781 if (!glState.getTargetBuffer(gl::BufferBinding::Array))
5782 {
5783 paramCapture->arrayClientPointerIndex =
5784 gl::GLES1Renderer::VertexArrayIndex(type, glState.gles1());
5785 }
5786 }
5787
GetProgramForCapture(const gl::State & glState,gl::ShaderProgramID handle)5788 gl::Program *GetProgramForCapture(const gl::State &glState, gl::ShaderProgramID handle)
5789 {
5790 gl::Program *program = glState.getShaderProgramManagerForCapture().getProgram(handle);
5791 return program;
5792 }
5793
CaptureGetActiveUniformBlockivParameters(const gl::State & glState,gl::ShaderProgramID handle,gl::UniformBlockIndex uniformBlockIndex,GLenum pname,ParamCapture * paramCapture)5794 void CaptureGetActiveUniformBlockivParameters(const gl::State &glState,
5795 gl::ShaderProgramID handle,
5796 gl::UniformBlockIndex uniformBlockIndex,
5797 GLenum pname,
5798 ParamCapture *paramCapture)
5799 {
5800 int numParams = 1;
5801
5802 // From the OpenGL ES 3.0 spec:
5803 // If pname is UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, then a list of the
5804 // active uniform indices for the uniform block identified by uniformBlockIndex is
5805 // returned. The number of elements that will be written to params is the value of
5806 // UNIFORM_BLOCK_ACTIVE_UNIFORMS for uniformBlockIndex
5807 if (pname == GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES)
5808 {
5809 gl::Program *program = GetProgramForCapture(glState, handle);
5810 if (program)
5811 {
5812 gl::QueryActiveUniformBlockiv(program, uniformBlockIndex,
5813 GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &numParams);
5814 }
5815 }
5816
5817 paramCapture->readBufferSizeBytes = sizeof(GLint) * numParams;
5818 }
5819
CaptureGetParameter(const gl::State & glState,GLenum pname,size_t typeSize,ParamCapture * paramCapture)5820 void CaptureGetParameter(const gl::State &glState,
5821 GLenum pname,
5822 size_t typeSize,
5823 ParamCapture *paramCapture)
5824 {
5825 // kMaxReportedCapabilities is the biggest array we'll need to hold data from glGet calls.
5826 // This value needs to be updated if any new extensions are introduced that would allow for
5827 // more compressed texture formats. The current value is taken from:
5828 // http://opengles.gpuinfo.org/displaycapability.php?name=GL_NUM_COMPRESSED_TEXTURE_FORMATS&esversion=2
5829 constexpr unsigned int kMaxReportedCapabilities = 69;
5830 paramCapture->readBufferSizeBytes = typeSize * kMaxReportedCapabilities;
5831 }
5832
CaptureGenHandlesImpl(GLsizei n,GLuint * handles,ParamCapture * paramCapture)5833 void CaptureGenHandlesImpl(GLsizei n, GLuint *handles, ParamCapture *paramCapture)
5834 {
5835 paramCapture->readBufferSizeBytes = sizeof(GLuint) * n;
5836 CaptureMemory(handles, paramCapture->readBufferSizeBytes, paramCapture);
5837 }
5838
CaptureShaderStrings(GLsizei count,const GLchar * const * strings,const GLint * length,ParamCapture * paramCapture)5839 void CaptureShaderStrings(GLsizei count,
5840 const GLchar *const *strings,
5841 const GLint *length,
5842 ParamCapture *paramCapture)
5843 {
5844 for (GLsizei index = 0; index < count; ++index)
5845 {
5846 size_t len = ((length && length[index] >= 0) ? length[index] : strlen(strings[index]));
5847 // includes the '\0' suffix
5848 std::vector<uint8_t> data(len + 1, 0);
5849 memcpy(data.data(), strings[index], len);
5850 paramCapture->data.emplace_back(std::move(data));
5851 }
5852 }
5853
5854 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLboolean value)5855 void WriteParamValueReplay<ParamType::TGLboolean>(std::ostream &os,
5856 const CallCapture &call,
5857 GLboolean value)
5858 {
5859 switch (value)
5860 {
5861 case GL_TRUE:
5862 os << "GL_TRUE";
5863 break;
5864 case GL_FALSE:
5865 os << "GL_FALSE";
5866 break;
5867 default:
5868 os << "0x" << std::hex << std::uppercase << GLint(value);
5869 }
5870 }
5871
5872 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,const void * value)5873 void WriteParamValueReplay<ParamType::TvoidConstPointer>(std::ostream &os,
5874 const CallCapture &call,
5875 const void *value)
5876 {
5877 if (value == 0)
5878 {
5879 os << "nullptr";
5880 }
5881 else
5882 {
5883 os << "reinterpret_cast<const void *>("
5884 << static_cast<int>(reinterpret_cast<uintptr_t>(value)) << ")";
5885 }
5886 }
5887
5888 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,const GLfloat * value)5889 void WriteParamValueReplay<ParamType::TGLfloatConstPointer>(std::ostream &os,
5890 const CallCapture &call,
5891 const GLfloat *value)
5892 {
5893 if (value == 0)
5894 {
5895 os << "nullptr";
5896 }
5897 else
5898 {
5899 os << "reinterpret_cast<const GLfloat *>("
5900 << static_cast<int>(reinterpret_cast<uintptr_t>(value)) << ")";
5901 }
5902 }
5903
5904 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,const GLuint * value)5905 void WriteParamValueReplay<ParamType::TGLuintConstPointer>(std::ostream &os,
5906 const CallCapture &call,
5907 const GLuint *value)
5908 {
5909 if (value == 0)
5910 {
5911 os << "nullptr";
5912 }
5913 else
5914 {
5915 os << "reinterpret_cast<const GLuint *>("
5916 << static_cast<int>(reinterpret_cast<uintptr_t>(value)) << ")";
5917 }
5918 }
5919
5920 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLDEBUGPROCKHR value)5921 void WriteParamValueReplay<ParamType::TGLDEBUGPROCKHR>(std::ostream &os,
5922 const CallCapture &call,
5923 GLDEBUGPROCKHR value)
5924 {}
5925
5926 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLDEBUGPROC value)5927 void WriteParamValueReplay<ParamType::TGLDEBUGPROC>(std::ostream &os,
5928 const CallCapture &call,
5929 GLDEBUGPROC value)
5930 {}
5931
5932 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::BufferID value)5933 void WriteParamValueReplay<ParamType::TBufferID>(std::ostream &os,
5934 const CallCapture &call,
5935 gl::BufferID value)
5936 {
5937 os << "gBufferMap[" << value.value << "]";
5938 }
5939
5940 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::FenceNVID value)5941 void WriteParamValueReplay<ParamType::TFenceNVID>(std::ostream &os,
5942 const CallCapture &call,
5943 gl::FenceNVID value)
5944 {
5945 os << "gFenceNVMap[" << value.value << "]";
5946 }
5947
5948 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::FramebufferID value)5949 void WriteParamValueReplay<ParamType::TFramebufferID>(std::ostream &os,
5950 const CallCapture &call,
5951 gl::FramebufferID value)
5952 {
5953 os << "gFramebufferMap[" << value.value << "]";
5954 }
5955
5956 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::MemoryObjectID value)5957 void WriteParamValueReplay<ParamType::TMemoryObjectID>(std::ostream &os,
5958 const CallCapture &call,
5959 gl::MemoryObjectID value)
5960 {
5961 os << "gMemoryObjectMap[" << value.value << "]";
5962 }
5963
5964 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::ProgramPipelineID value)5965 void WriteParamValueReplay<ParamType::TProgramPipelineID>(std::ostream &os,
5966 const CallCapture &call,
5967 gl::ProgramPipelineID value)
5968 {
5969 os << "gProgramPipelineMap[" << value.value << "]";
5970 }
5971
5972 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::QueryID value)5973 void WriteParamValueReplay<ParamType::TQueryID>(std::ostream &os,
5974 const CallCapture &call,
5975 gl::QueryID value)
5976 {
5977 os << "gQueryMap[" << value.value << "]";
5978 }
5979
5980 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::RenderbufferID value)5981 void WriteParamValueReplay<ParamType::TRenderbufferID>(std::ostream &os,
5982 const CallCapture &call,
5983 gl::RenderbufferID value)
5984 {
5985 os << "gRenderbufferMap[" << value.value << "]";
5986 }
5987
5988 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::SamplerID value)5989 void WriteParamValueReplay<ParamType::TSamplerID>(std::ostream &os,
5990 const CallCapture &call,
5991 gl::SamplerID value)
5992 {
5993 os << "gSamplerMap[" << value.value << "]";
5994 }
5995
5996 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::SemaphoreID value)5997 void WriteParamValueReplay<ParamType::TSemaphoreID>(std::ostream &os,
5998 const CallCapture &call,
5999 gl::SemaphoreID value)
6000 {
6001 os << "gSemaphoreMap[" << value.value << "]";
6002 }
6003
6004 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::ShaderProgramID value)6005 void WriteParamValueReplay<ParamType::TShaderProgramID>(std::ostream &os,
6006 const CallCapture &call,
6007 gl::ShaderProgramID value)
6008 {
6009 os << "gShaderProgramMap[" << value.value << "]";
6010 }
6011
6012 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLsync value)6013 void WriteParamValueReplay<ParamType::TGLsync>(std::ostream &os,
6014 const CallCapture &call,
6015 GLsync value)
6016 {
6017 os << "gSyncMap[" << SyncIndexValue(value) << "]";
6018 }
6019
6020 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::TextureID value)6021 void WriteParamValueReplay<ParamType::TTextureID>(std::ostream &os,
6022 const CallCapture &call,
6023 gl::TextureID value)
6024 {
6025 os << "gTextureMap[" << value.value << "]";
6026 }
6027
6028 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::TransformFeedbackID value)6029 void WriteParamValueReplay<ParamType::TTransformFeedbackID>(std::ostream &os,
6030 const CallCapture &call,
6031 gl::TransformFeedbackID value)
6032 {
6033 os << "gTransformFeedbackMap[" << value.value << "]";
6034 }
6035
6036 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::VertexArrayID value)6037 void WriteParamValueReplay<ParamType::TVertexArrayID>(std::ostream &os,
6038 const CallCapture &call,
6039 gl::VertexArrayID value)
6040 {
6041 os << "gVertexArrayMap[" << value.value << "]";
6042 }
6043
6044 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::UniformLocation value)6045 void WriteParamValueReplay<ParamType::TUniformLocation>(std::ostream &os,
6046 const CallCapture &call,
6047 gl::UniformLocation value)
6048 {
6049 if (value.value == -1)
6050 {
6051 os << "-1";
6052 return;
6053 }
6054
6055 os << "gUniformLocations[";
6056
6057 // Find the program from the call parameters.
6058 gl::ShaderProgramID programID;
6059 if (FindShaderProgramIDInCall(call, &programID))
6060 {
6061 os << "gShaderProgramMap[" << programID.value << "]";
6062 }
6063 else
6064 {
6065 os << "gCurrentProgram";
6066 }
6067
6068 os << "][" << value.value << "]";
6069 }
6070
6071 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::UniformBlockIndex value)6072 void WriteParamValueReplay<ParamType::TUniformBlockIndex>(std::ostream &os,
6073 const CallCapture &call,
6074 gl::UniformBlockIndex value)
6075 {
6076 // Find the program from the call parameters.
6077 gl::ShaderProgramID programID;
6078 bool foundProgram = FindShaderProgramIDInCall(call, &programID);
6079 ASSERT(foundProgram);
6080
6081 os << "gUniformBlockIndexes[gShaderProgramMap[" << programID.value << "]][" << value.value
6082 << "]";
6083 }
6084
6085 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLeglImageOES value)6086 void WriteParamValueReplay<ParamType::TGLeglImageOES>(std::ostream &os,
6087 const CallCapture &call,
6088 GLeglImageOES value)
6089 {
6090 uint64_t pointerValue = reinterpret_cast<uint64_t>(value);
6091 os << "reinterpret_cast<EGLImageKHR>(" << pointerValue << "ul)";
6092 }
6093
6094 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLubyte value)6095 void WriteParamValueReplay<ParamType::TGLubyte>(std::ostream &os,
6096 const CallCapture &call,
6097 GLubyte value)
6098 {
6099 const int v = value;
6100 os << v;
6101 }
6102
6103 } // namespace angle
6104