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