• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 GL implementation.
8 //
9 
10 #include "libANGLE/capture/FrameCapture.h"
11 
12 #include <cerrno>
13 #include <cstring>
14 #include <fstream>
15 #include <queue>
16 #include <string>
17 
18 #include "common/aligned_memory.h"
19 #include "common/angle_version_info.h"
20 #include "common/frame_capture_utils.h"
21 #include "common/gl_enum_utils.h"
22 #include "common/mathutil.h"
23 #include "common/serializer/JsonSerializer.h"
24 #include "common/string_utils.h"
25 #include "common/system_utils.h"
26 #include "gpu_info_util/SystemInfo.h"
27 #include "image_util/storeimage.h"
28 #include "libANGLE/Config.h"
29 #include "libANGLE/Context.h"
30 #include "libANGLE/Context.inl.h"
31 #include "libANGLE/Display.h"
32 #include "libANGLE/EGLSync.h"
33 #include "libANGLE/Fence.h"
34 #include "libANGLE/Framebuffer.h"
35 #include "libANGLE/GLES1Renderer.h"
36 #include "libANGLE/Query.h"
37 #include "libANGLE/ResourceMap.h"
38 #include "libANGLE/Shader.h"
39 #include "libANGLE/Surface.h"
40 #include "libANGLE/VertexArray.h"
41 #include "libANGLE/capture/capture_egl_autogen.h"
42 #include "libANGLE/capture/capture_gles_1_0_autogen.h"
43 #include "libANGLE/capture/capture_gles_2_0_autogen.h"
44 #include "libANGLE/capture/capture_gles_3_0_autogen.h"
45 #include "libANGLE/capture/capture_gles_3_1_autogen.h"
46 #include "libANGLE/capture/capture_gles_3_2_autogen.h"
47 #include "libANGLE/capture/capture_gles_ext_autogen.h"
48 #include "libANGLE/capture/serialize.h"
49 #include "libANGLE/entry_points_utils.h"
50 #include "libANGLE/queryconversions.h"
51 #include "libANGLE/queryutils.h"
52 #include "libANGLE/renderer/driver_utils.h"
53 #include "libANGLE/validationEGL.h"
54 #include "third_party/ceval/ceval.h"
55 
56 #define USE_SYSTEM_ZLIB
57 #include "compression_utils_portable.h"
58 
59 #if !ANGLE_CAPTURE_ENABLED
60 #    error Frame capture must be enabled to include this file.
61 #endif  // !ANGLE_CAPTURE_ENABLED
62 
63 namespace angle
64 {
65 
66 struct FramebufferCaptureFuncs
67 {
FramebufferCaptureFuncsangle::FramebufferCaptureFuncs68     FramebufferCaptureFuncs(bool isGLES1)
69     {
70         if (isGLES1)
71         {
72             // From GL_OES_framebuffer_object
73             framebufferTexture2D    = &gl::CaptureFramebufferTexture2DOES;
74             framebufferRenderbuffer = &gl::CaptureFramebufferRenderbufferOES;
75             bindFramebuffer         = &gl::CaptureBindFramebufferOES;
76             genFramebuffers         = &gl::CaptureGenFramebuffersOES;
77             bindRenderbuffer        = &gl::CaptureBindRenderbufferOES;
78             genRenderbuffers        = &gl::CaptureGenRenderbuffersOES;
79             renderbufferStorage     = &gl::CaptureRenderbufferStorageOES;
80         }
81         else
82         {
83             framebufferTexture2D    = &gl::CaptureFramebufferTexture2D;
84             framebufferRenderbuffer = &gl::CaptureFramebufferRenderbuffer;
85             bindFramebuffer         = &gl::CaptureBindFramebuffer;
86             genFramebuffers         = &gl::CaptureGenFramebuffers;
87             bindRenderbuffer        = &gl::CaptureBindRenderbuffer;
88             genRenderbuffers        = &gl::CaptureGenRenderbuffers;
89             renderbufferStorage     = &gl::CaptureRenderbufferStorage;
90         }
91     }
92 
93     decltype(&gl::CaptureFramebufferTexture2D) framebufferTexture2D;
94     decltype(&gl::CaptureFramebufferRenderbuffer) framebufferRenderbuffer;
95     decltype(&gl::CaptureBindFramebuffer) bindFramebuffer;
96     decltype(&gl::CaptureGenFramebuffers) genFramebuffers;
97     decltype(&gl::CaptureBindRenderbuffer) bindRenderbuffer;
98     decltype(&gl::CaptureGenRenderbuffers) genRenderbuffers;
99     decltype(&gl::CaptureRenderbufferStorage) renderbufferStorage;
100 };
101 
102 struct VertexArrayCaptureFuncs
103 {
VertexArrayCaptureFuncsangle::VertexArrayCaptureFuncs104     VertexArrayCaptureFuncs(bool isGLES1)
105     {
106         if (isGLES1)
107         {
108             // From GL_OES_vertex_array_object
109             bindVertexArray    = &gl::CaptureBindVertexArrayOES;
110             deleteVertexArrays = &gl::CaptureDeleteVertexArraysOES;
111             genVertexArrays    = &gl::CaptureGenVertexArraysOES;
112             isVertexArray      = &gl::CaptureIsVertexArrayOES;
113         }
114         else
115         {
116             bindVertexArray    = &gl::CaptureBindVertexArray;
117             deleteVertexArrays = &gl::CaptureDeleteVertexArrays;
118             genVertexArrays    = &gl::CaptureGenVertexArrays;
119             isVertexArray      = &gl::CaptureIsVertexArray;
120         }
121     }
122 
123     decltype(&gl::CaptureBindVertexArray) bindVertexArray;
124     decltype(&gl::CaptureDeleteVertexArrays) deleteVertexArrays;
125     decltype(&gl::CaptureGenVertexArrays) genVertexArrays;
126     decltype(&gl::CaptureIsVertexArray) isVertexArray;
127 };
128 
GetCaptureTrigger()129 std::string GetCaptureTrigger()
130 {
131     // Use the GetAndSet variant to improve future lookup times
132     return GetAndSetEnvironmentVarOrUnCachedAndroidProperty(kTriggerVarName, kAndroidTrigger);
133 }
134 
135 struct FmtGetSerializedContextStateFunction
136 {
FmtGetSerializedContextStateFunctionangle::FmtGetSerializedContextStateFunction137     FmtGetSerializedContextStateFunction(gl::ContextID contextIdIn,
138                                          FuncUsage usageIn,
139                                          uint32_t frameIndexIn)
140         : contextId(contextIdIn), usage(usageIn), frameIndex(frameIndexIn)
141     {}
142     gl::ContextID contextId;
143     FuncUsage usage;
144     uint32_t frameIndex;
145 };
146 
operator <<(std::ostream & os,const FmtGetSerializedContextStateFunction & fmt)147 std::ostream &operator<<(std::ostream &os, const FmtGetSerializedContextStateFunction &fmt)
148 {
149     os << "GetSerializedContext" << fmt.contextId << "StateFrame" << fmt.frameIndex << "Data"
150        << fmt.usage;
151     return os;
152 }
153 
WriteGLFloatValue(std::ostream & out,GLfloat value)154 void WriteGLFloatValue(std::ostream &out, GLfloat value)
155 {
156     // Check for non-representable values
157     ASSERT(std::numeric_limits<float>::has_infinity);
158     ASSERT(std::numeric_limits<float>::has_quiet_NaN);
159 
160     if (std::isinf(value))
161     {
162         float negativeInf = -std::numeric_limits<float>::infinity();
163         if (value == negativeInf)
164         {
165             out << "-";
166         }
167         out << "INFINITY";
168     }
169     else if (std::isnan(value))
170     {
171         out << "NAN";
172     }
173     else
174     {
175         // Write a decimal point to preserve the zero sign on replay
176         out << (value == 0.0 ? std::showpoint : std::noshowpoint);
177         out << std::setprecision(16);
178         out << value;
179     }
180 }
181 
WriteStringParamReplay(ReplayWriter & replayWriter,std::ostream & out,std::ostream & header,const CallCapture & call,const ParamCapture & param,std::vector<uint8_t> * binaryData)182 void WriteStringParamReplay(ReplayWriter &replayWriter,
183                             std::ostream &out,
184                             std::ostream &header,
185                             const CallCapture &call,
186                             const ParamCapture &param,
187                             std::vector<uint8_t> *binaryData)
188 {
189     const std::vector<uint8_t> &data = param.data[0];
190     // null terminate C style string
191     ASSERT(data.size() > 0 && data.back() == '\0');
192     std::string str(data.begin(), data.end() - 1);
193 
194     constexpr size_t kMaxInlineStringLength = 20000;
195     if (str.size() > kMaxInlineStringLength)
196     {
197         // Store in binary file if the string is too long.
198         // Round up to 16-byte boundary for cross ABI safety.
199         size_t offset = rx::roundUpPow2(binaryData->size(), kBinaryAlignment);
200         binaryData->resize(offset + str.size() + 1);
201         memcpy(binaryData->data() + offset, str.data(), str.size() + 1);
202         out << "(const char *)&gBinaryData[" << offset << "]";
203     }
204     else if (str.find('\n') != std::string::npos)
205     {
206         std::string varName = replayWriter.getInlineVariableName(call.entryPoint, param.name);
207         header << "const char " << varName << "[] = \n" << FmtMultiLineString(str) << ";";
208         out << varName;
209     }
210     else
211     {
212         out << "\"" << str << "\"";
213     }
214 }
215 
216 enum class Indent
217 {
218     Indent,
219     NoIdent,
220 };
221 
UpdateResourceIDBuffer(std::ostream & out,Indent indent,size_t bufferIndex,ResourceIDType resourceIDType,gl::ContextID contextID,GLuint resourceID)222 void UpdateResourceIDBuffer(std::ostream &out,
223                             Indent indent,
224                             size_t bufferIndex,
225                             ResourceIDType resourceIDType,
226                             gl::ContextID contextID,
227                             GLuint resourceID)
228 {
229     if (indent == Indent::Indent)
230     {
231         out << "    ";
232     }
233     out << "UpdateResourceIDBuffer(" << bufferIndex << ", g"
234         << GetResourceIDTypeName(resourceIDType) << "Map";
235     if (IsTrackedPerContext(resourceIDType))
236     {
237         out << "PerContext[" << contextID.value << "]";
238     }
239     out << "[" << resourceID << "]);\n";
240 }
241 
242 template <typename ParamT>
WriteResourceIDPointerParamReplay(ReplayWriter & replayWriter,std::ostream & out,std::ostream & header,const CallCapture & call,const ParamCapture & param,size_t * maxResourceIDBufferSize)243 void WriteResourceIDPointerParamReplay(ReplayWriter &replayWriter,
244                                        std::ostream &out,
245                                        std::ostream &header,
246                                        const CallCapture &call,
247                                        const ParamCapture &param,
248                                        size_t *maxResourceIDBufferSize)
249 {
250     const ResourceIDType resourceIDType = GetResourceIDTypeFromParamType(param.type);
251     ASSERT(resourceIDType != ResourceIDType::InvalidEnum);
252 
253     if (param.dataNElements > 0)
254     {
255         ASSERT(param.data.size() == 1);
256 
257         const ParamT *returnedIDs = reinterpret_cast<const ParamT *>(param.data[0].data());
258         for (GLsizei resIndex = 0; resIndex < param.dataNElements; ++resIndex)
259         {
260             ParamT id = returnedIDs[resIndex];
261             UpdateResourceIDBuffer(header, Indent::NoIdent, resIndex, resourceIDType,
262                                    call.contextID, id.value);
263         }
264 
265         *maxResourceIDBufferSize = std::max<size_t>(*maxResourceIDBufferSize, param.dataNElements);
266     }
267 
268     out << "gResourceIDBuffer";
269 }
270 
WriteCppReplayForCall(const CallCapture & call,ReplayWriter & replayWriter,std::ostream & out,std::ostream & header,std::vector<uint8_t> * binaryData,size_t * maxResourceIDBufferSize)271 void WriteCppReplayForCall(const CallCapture &call,
272                            ReplayWriter &replayWriter,
273                            std::ostream &out,
274                            std::ostream &header,
275                            std::vector<uint8_t> *binaryData,
276                            size_t *maxResourceIDBufferSize)
277 {
278     if (call.customFunctionName == "Comment")
279     {
280         // Just write it directly to the file and move on
281         WriteComment(out, call);
282         return;
283     }
284 
285     std::ostringstream callOut;
286 
287     callOut << call.name() << "(";
288 
289     bool first = true;
290     for (const ParamCapture &param : call.params.getParamCaptures())
291     {
292         if (!first)
293         {
294             callOut << ", ";
295         }
296 
297         if (param.arrayClientPointerIndex != -1 && param.value.voidConstPointerVal != nullptr)
298         {
299             callOut << "gClientArrays[" << param.arrayClientPointerIndex << "]";
300         }
301         else if (param.readBufferSizeBytes > 0)
302         {
303             callOut << "(" << ParamTypeToString(param.type) << ")gReadBuffer";
304         }
305         else if (param.data.empty())
306         {
307             if (param.type == ParamType::TGLenum)
308             {
309                 OutputGLenumString(callOut, param.enumGroup, param.value.GLenumVal);
310             }
311             else if (param.type == ParamType::TGLbitfield)
312             {
313                 OutputGLbitfieldString(callOut, param.enumGroup, param.value.GLbitfieldVal);
314             }
315             else if (param.type == ParamType::TGLfloat)
316             {
317                 WriteGLFloatValue(callOut, param.value.GLfloatVal);
318             }
319             else if (param.type == ParamType::TGLsync)
320             {
321                 callOut << "gSyncMap[" << FmtPointerIndex(param.value.GLsyncVal) << "]";
322             }
323             else if (param.type == ParamType::TGLuint64 && param.name == "timeout")
324             {
325                 if (param.value.GLuint64Val == GL_TIMEOUT_IGNORED)
326                 {
327                     callOut << "GL_TIMEOUT_IGNORED";
328                 }
329                 else
330                 {
331                     WriteParamCaptureReplay(callOut, call, param);
332                 }
333             }
334             else
335             {
336                 WriteParamCaptureReplay(callOut, call, param);
337             }
338         }
339         else
340         {
341             switch (param.type)
342             {
343                 case ParamType::TGLcharConstPointer:
344                     WriteStringParamReplay(replayWriter, callOut, header, call, param, binaryData);
345                     break;
346                 case ParamType::TGLcharConstPointerPointer:
347                     WriteStringPointerParamReplay(replayWriter, callOut, header, call, param);
348                     break;
349                 case ParamType::TBufferIDConstPointer:
350                     WriteResourceIDPointerParamReplay<gl::BufferID>(
351                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
352                     break;
353                 case ParamType::TFenceNVIDConstPointer:
354                     WriteResourceIDPointerParamReplay<gl::FenceNVID>(
355                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
356                     break;
357                 case ParamType::TFramebufferIDConstPointer:
358                     WriteResourceIDPointerParamReplay<gl::FramebufferID>(
359                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
360                     break;
361                 case ParamType::TMemoryObjectIDConstPointer:
362                     WriteResourceIDPointerParamReplay<gl::MemoryObjectID>(
363                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
364                     break;
365                 case ParamType::TProgramPipelineIDConstPointer:
366                     WriteResourceIDPointerParamReplay<gl::ProgramPipelineID>(
367                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
368                     break;
369                 case ParamType::TQueryIDConstPointer:
370                     WriteResourceIDPointerParamReplay<gl::QueryID>(replayWriter, callOut, out, call,
371                                                                    param, maxResourceIDBufferSize);
372                     break;
373                 case ParamType::TRenderbufferIDConstPointer:
374                     WriteResourceIDPointerParamReplay<gl::RenderbufferID>(
375                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
376                     break;
377                 case ParamType::TSamplerIDConstPointer:
378                     WriteResourceIDPointerParamReplay<gl::SamplerID>(
379                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
380                     break;
381                 case ParamType::TSemaphoreIDConstPointer:
382                     WriteResourceIDPointerParamReplay<gl::SemaphoreID>(
383                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
384                     break;
385                 case ParamType::TTextureIDConstPointer:
386                     WriteResourceIDPointerParamReplay<gl::TextureID>(
387                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
388                     break;
389                 case ParamType::TTransformFeedbackIDConstPointer:
390                     WriteResourceIDPointerParamReplay<gl::TransformFeedbackID>(
391                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
392                     break;
393                 case ParamType::TVertexArrayIDConstPointer:
394                     WriteResourceIDPointerParamReplay<gl::VertexArrayID>(
395                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
396                     break;
397                 default:
398                     WriteBinaryParamReplay(replayWriter, callOut, header, call, param, binaryData);
399                     break;
400             }
401         }
402 
403         first = false;
404     }
405 
406     callOut << ")";
407 
408     out << callOut.str();
409 }
410 
MaxClientArraySize(const gl::AttribArray<size_t> & clientArraySizes)411 size_t MaxClientArraySize(const gl::AttribArray<size_t> &clientArraySizes)
412 {
413     size_t found = 0;
414     for (size_t size : clientArraySizes)
415     {
416         if (size > found)
417         {
418             found = size;
419         }
420     }
421 
422     return found;
423 }
424 
WriteInitReplayCall(bool compression,std::ostream & out,gl::ContextID contextID,const std::string & captureLabel,size_t maxClientArraySize,size_t readBufferSize,size_t resourceIDBufferSize,const PackedEnumMap<ResourceIDType,uint32_t> & maxIDs)425 void WriteInitReplayCall(bool compression,
426                          std::ostream &out,
427                          gl::ContextID contextID,
428                          const std::string &captureLabel,
429                          size_t maxClientArraySize,
430                          size_t readBufferSize,
431                          size_t resourceIDBufferSize,
432                          const PackedEnumMap<ResourceIDType, uint32_t> &maxIDs)
433 {
434     std::string binaryDataFileName = GetBinaryDataFilePath(compression, captureLabel);
435 
436     out << "    // binaryDataFileName = " << binaryDataFileName << "\n";
437     out << "    // maxClientArraySize = " << maxClientArraySize << "\n";
438     out << "    // readBufferSize = " << readBufferSize << "\n";
439     out << "    // resourceIDBufferSize = " << resourceIDBufferSize << "\n";
440     out << "    // contextID = " << contextID << "\n";
441     for (ResourceIDType resourceID : AllEnums<ResourceIDType>())
442     {
443         const char *name = GetResourceIDTypeName(resourceID);
444         out << "    // max" << name << " = " << maxIDs[resourceID] << "\n";
445     }
446     out << "    InitializeReplay4(\"" << binaryDataFileName << "\", " << maxClientArraySize << ", "
447         << readBufferSize << ", " << resourceIDBufferSize << ", " << contextID;
448 
449     for (ResourceIDType resourceID : AllEnums<ResourceIDType>())
450     {
451         // Sanity check for catching e.g. uninitialized memory reads like b/380296979
452         ASSERT(maxIDs[resourceID] < 1000000);
453         out << ", " << maxIDs[resourceID];
454     }
455 
456     out << ");\n";
457 }
458 
DeleteResourcesInReset(std::stringstream & out,const gl::ContextID contextID,const ResourceSet & newResources,const ResourceSet & resourcesToDelete,const ResourceIDType resourceIDType,size_t * maxResourceIDBufferSize)459 void DeleteResourcesInReset(std::stringstream &out,
460                             const gl::ContextID contextID,
461                             const ResourceSet &newResources,
462                             const ResourceSet &resourcesToDelete,
463                             const ResourceIDType resourceIDType,
464                             size_t *maxResourceIDBufferSize)
465 {
466     if (!newResources.empty() || !resourcesToDelete.empty())
467     {
468         size_t count = 0;
469 
470         for (GLuint oldResource : resourcesToDelete)
471         {
472             UpdateResourceIDBuffer(out, Indent::Indent, count++, resourceIDType, contextID,
473                                    oldResource);
474         }
475 
476         for (GLuint newResource : newResources)
477         {
478             UpdateResourceIDBuffer(out, Indent::Indent, count++, resourceIDType, contextID,
479                                    newResource);
480         }
481 
482         // Delete all the new and old buffers at once
483         out << "    glDelete" << GetResourceIDTypeName(resourceIDType) << "s(" << count
484             << ", gResourceIDBuffer);\n";
485 
486         *maxResourceIDBufferSize = std::max(*maxResourceIDBufferSize, count);
487     }
488 }
489 
490 // TODO (http://anglebug.com/42263204): Reset more state on frame loop
MaybeResetResources(egl::Display * display,gl::ContextID contextID,ResourceIDType resourceIDType,ReplayWriter & replayWriter,std::stringstream & out,std::stringstream & header,ResourceTracker * resourceTracker,std::vector<uint8_t> * binaryData,bool & anyResourceReset,size_t * maxResourceIDBufferSize)491 void MaybeResetResources(egl::Display *display,
492                          gl::ContextID contextID,
493                          ResourceIDType resourceIDType,
494                          ReplayWriter &replayWriter,
495                          std::stringstream &out,
496                          std::stringstream &header,
497                          ResourceTracker *resourceTracker,
498                          std::vector<uint8_t> *binaryData,
499                          bool &anyResourceReset,
500                          size_t *maxResourceIDBufferSize)
501 {
502     // Track the initial output position so we can detect if it has moved
503     std::streampos initialOutPos = out.tellp();
504 
505     switch (resourceIDType)
506     {
507         case ResourceIDType::Buffer:
508         {
509             TrackedResource &trackedBuffers =
510                 resourceTracker->getTrackedResource(contextID, ResourceIDType::Buffer);
511             ResourceSet &newBuffers           = trackedBuffers.getNewResources();
512             ResourceSet &buffersToDelete      = trackedBuffers.getResourcesToDelete();
513             ResourceSet &buffersToRegen       = trackedBuffers.getResourcesToRegen();
514             ResourceCalls &bufferRegenCalls   = trackedBuffers.getResourceRegenCalls();
515             ResourceCalls &bufferRestoreCalls = trackedBuffers.getResourceRestoreCalls();
516 
517             BufferCalls &bufferMapCalls   = resourceTracker->getBufferMapCalls();
518             BufferCalls &bufferUnmapCalls = resourceTracker->getBufferUnmapCalls();
519 
520             DeleteResourcesInReset(out, contextID, newBuffers, buffersToDelete, resourceIDType,
521                                    maxResourceIDBufferSize);
522 
523             // If any of our starting buffers were deleted during the run, recreate them
524             for (GLuint id : buffersToRegen)
525             {
526                 // Emit their regen calls
527                 for (CallCapture &call : bufferRegenCalls[id])
528                 {
529                     out << "    ";
530                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
531                                           maxResourceIDBufferSize);
532                     out << ";\n";
533                 }
534             }
535 
536             // If any of our starting buffers were modified during the run, restore their contents
537             ResourceSet &buffersToRestore = trackedBuffers.getResourcesToRestore();
538             for (GLuint id : buffersToRestore)
539             {
540                 if (resourceTracker->getStartingBuffersMappedCurrent(id))
541                 {
542                     // Some drivers require the buffer to be unmapped before you can update data,
543                     // which violates the spec. See gl::Buffer::bufferDataImpl().
544                     for (CallCapture &call : bufferUnmapCalls[id])
545                     {
546                         out << "    ";
547                         WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
548                                               maxResourceIDBufferSize);
549                         out << ";\n";
550                     }
551                 }
552 
553                 // Emit their restore calls
554                 for (CallCapture &call : bufferRestoreCalls[id])
555                 {
556                     out << "    ";
557                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
558                                           maxResourceIDBufferSize);
559                     out << ";\n";
560 
561                     // Also note that this buffer has been implicitly unmapped by this call
562                     resourceTracker->setBufferUnmapped(contextID, id);
563                 }
564             }
565 
566             // Update the map/unmap of buffers to match the starting state
567             ResourceSet startingBuffers = trackedBuffers.getStartingResources();
568             for (GLuint id : startingBuffers)
569             {
570                 // If the buffer was mapped at the start, but is not mapped now, we need to map
571                 if (resourceTracker->getStartingBuffersMappedInitial(id) &&
572                     !resourceTracker->getStartingBuffersMappedCurrent(id))
573                 {
574                     // Emit their map calls
575                     for (CallCapture &call : bufferMapCalls[id])
576                     {
577                         out << "    ";
578                         WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
579                                               maxResourceIDBufferSize);
580                         out << ";\n";
581                     }
582                 }
583                 // If the buffer was unmapped at the start, but is mapped now, we need to unmap
584                 if (!resourceTracker->getStartingBuffersMappedInitial(id) &&
585                     resourceTracker->getStartingBuffersMappedCurrent(id))
586                 {
587                     // Emit their unmap calls
588                     for (CallCapture &call : bufferUnmapCalls[id])
589                     {
590                         out << "    ";
591                         WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
592                                               maxResourceIDBufferSize);
593                         out << ";\n";
594                     }
595                 }
596             }
597             break;
598         }
599         case ResourceIDType::Framebuffer:
600         {
601             TrackedResource &trackedFramebuffers =
602                 resourceTracker->getTrackedResource(contextID, ResourceIDType::Framebuffer);
603             ResourceSet &newFramebuffers           = trackedFramebuffers.getNewResources();
604             ResourceSet &framebuffersToDelete      = trackedFramebuffers.getResourcesToDelete();
605             ResourceSet &framebuffersToRegen       = trackedFramebuffers.getResourcesToRegen();
606             ResourceCalls &framebufferRegenCalls   = trackedFramebuffers.getResourceRegenCalls();
607             ResourceCalls &framebufferRestoreCalls = trackedFramebuffers.getResourceRestoreCalls();
608 
609             DeleteResourcesInReset(out, contextID, newFramebuffers, framebuffersToDelete,
610                                    resourceIDType, maxResourceIDBufferSize);
611 
612             for (GLuint id : framebuffersToRegen)
613             {
614                 // Emit their regen calls
615                 for (CallCapture &call : framebufferRegenCalls[id])
616                 {
617                     out << "    ";
618                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
619                                           maxResourceIDBufferSize);
620                     out << ";\n";
621                 }
622             }
623 
624             // If any of our starting framebuffers were modified during the run, restore their
625             // contents
626             ResourceSet &framebuffersToRestore = trackedFramebuffers.getResourcesToRestore();
627             for (GLuint id : framebuffersToRestore)
628             {
629                 // Emit their restore calls
630                 for (CallCapture &call : framebufferRestoreCalls[id])
631                 {
632                     out << "    ";
633                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
634                                           maxResourceIDBufferSize);
635                     out << ";\n";
636                 }
637             }
638             break;
639         }
640         case ResourceIDType::Renderbuffer:
641         {
642             TrackedResource &trackedRenderbuffers =
643                 resourceTracker->getTrackedResource(contextID, ResourceIDType::Renderbuffer);
644             ResourceSet &newRenderbuffers         = trackedRenderbuffers.getNewResources();
645             ResourceSet &renderbuffersToDelete    = trackedRenderbuffers.getResourcesToDelete();
646             ResourceSet &renderbuffersToRegen     = trackedRenderbuffers.getResourcesToRegen();
647             ResourceCalls &renderbufferRegenCalls = trackedRenderbuffers.getResourceRegenCalls();
648             ResourceCalls &renderbufferRestoreCalls =
649                 trackedRenderbuffers.getResourceRestoreCalls();
650 
651             DeleteResourcesInReset(out, contextID, newRenderbuffers, renderbuffersToDelete,
652                                    resourceIDType, maxResourceIDBufferSize);
653 
654             for (GLuint id : renderbuffersToRegen)
655             {
656                 // Emit their regen calls
657                 for (CallCapture &call : renderbufferRegenCalls[id])
658                 {
659                     out << "    ";
660                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
661                                           maxResourceIDBufferSize);
662                     out << ";\n";
663                 }
664             }
665 
666             // If any of our starting renderbuffers were modified during the run, restore their
667             // contents
668             ResourceSet &renderbuffersToRestore = trackedRenderbuffers.getResourcesToRestore();
669             for (GLuint id : renderbuffersToRestore)
670             {
671                 // Emit their restore calls
672                 for (CallCapture &call : renderbufferRestoreCalls[id])
673                 {
674                     out << "    ";
675                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
676                                           maxResourceIDBufferSize);
677                     out << ";\n";
678                 }
679             }
680             break;
681         }
682         case ResourceIDType::ShaderProgram:
683         {
684             TrackedResource &trackedShaderPrograms =
685                 resourceTracker->getTrackedResource(contextID, ResourceIDType::ShaderProgram);
686             ResourceSet &newShaderPrograms         = trackedShaderPrograms.getNewResources();
687             ResourceSet &shaderProgramsToDelete    = trackedShaderPrograms.getResourcesToDelete();
688             ResourceSet &shaderProgramsToRegen     = trackedShaderPrograms.getResourcesToRegen();
689             ResourceSet &shaderProgramsToRestore   = trackedShaderPrograms.getResourcesToRestore();
690             ResourceCalls &shaderProgramRegenCalls = trackedShaderPrograms.getResourceRegenCalls();
691             ResourceCalls &shaderProgramRestoreCalls =
692                 trackedShaderPrograms.getResourceRestoreCalls();
693 
694             // If we have any new shaders or programs created and not deleted during the run, delete
695             // them now
696             for (const GLuint &newShaderProgram : newShaderPrograms)
697             {
698                 if (resourceTracker->getShaderProgramType({newShaderProgram}) ==
699                     ShaderProgramType::ShaderType)
700                 {
701                     out << "    glDeleteShader(gShaderProgramMap[" << newShaderProgram << "]);\n";
702                 }
703                 else
704                 {
705                     ASSERT(resourceTracker->getShaderProgramType({newShaderProgram}) ==
706                            ShaderProgramType::ProgramType);
707                     out << "    glDeleteProgram(gShaderProgramMap[" << newShaderProgram << "]);\n";
708                 }
709             }
710 
711             // Do the same for shaders/programs to be deleted
712             for (const GLuint &shaderProgramToDelete : shaderProgramsToDelete)
713             {
714                 if (resourceTracker->getShaderProgramType({shaderProgramToDelete}) ==
715                     ShaderProgramType::ShaderType)
716                 {
717                     out << "    glDeleteShader(gShaderProgramMap[" << shaderProgramToDelete
718                         << "]);\n";
719                 }
720                 else
721                 {
722                     ASSERT(resourceTracker->getShaderProgramType({shaderProgramToDelete}) ==
723                            ShaderProgramType::ProgramType);
724                     out << "    glDeleteProgram(gShaderProgramMap[" << shaderProgramToDelete
725                         << "]);\n";
726                 }
727             }
728 
729             for (const GLuint id : shaderProgramsToRegen)
730             {
731                 // Emit their regen calls
732                 for (CallCapture &call : shaderProgramRegenCalls[id])
733                 {
734                     out << "    ";
735                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
736                                           maxResourceIDBufferSize);
737                     out << ";\n";
738                 }
739             }
740 
741             for (const GLuint id : shaderProgramsToRestore)
742             {
743                 // Emit their restore calls
744                 for (CallCapture &call : shaderProgramRestoreCalls[id])
745                 {
746                     out << "    ";
747                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
748                                           maxResourceIDBufferSize);
749                     out << ";\n";
750                 }
751             }
752 
753             break;
754         }
755         case ResourceIDType::Texture:
756         {
757             TrackedResource &trackedTextures =
758                 resourceTracker->getTrackedResource(contextID, ResourceIDType::Texture);
759             ResourceSet &newTextures           = trackedTextures.getNewResources();
760             ResourceSet &texturesToDelete      = trackedTextures.getResourcesToDelete();
761             ResourceSet &texturesToRegen       = trackedTextures.getResourcesToRegen();
762             ResourceCalls &textureRegenCalls   = trackedTextures.getResourceRegenCalls();
763             ResourceCalls &textureRestoreCalls = trackedTextures.getResourceRestoreCalls();
764 
765             DeleteResourcesInReset(out, contextID, newTextures, texturesToDelete, resourceIDType,
766                                    maxResourceIDBufferSize);
767 
768             // If any of our starting textures were deleted, regen them
769             for (GLuint id : texturesToRegen)
770             {
771                 // Emit their regen calls
772                 for (CallCapture &call : textureRegenCalls[id])
773                 {
774                     out << "    ";
775                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
776                                           maxResourceIDBufferSize);
777                     out << ";\n";
778                 }
779             }
780 
781             // If any of our starting textures were modified during the run, restore their contents
782             ResourceSet &texturesToRestore = trackedTextures.getResourcesToRestore();
783 
784             // Do some setup if we have any textures to restore
785             if (texturesToRestore.size() != 0)
786             {
787                 // We need to unbind PIXEL_UNPACK_BUFFER before restoring textures
788                 // The correct binding will be restored in context state reset
789                 gl::Context *context = display->getContext(contextID);
790                 if (context->getState().getTargetBuffer(gl::BufferBinding::PixelUnpack))
791                 {
792                     out << "    // Clearing PIXEL_UNPACK_BUFFER binding for texture restore\n";
793                     out << "    ";
794                     WriteCppReplayForCall(CaptureBindBuffer(context->getState(), true,
795                                                             gl::BufferBinding::PixelUnpack, {0}),
796                                           replayWriter, out, header, binaryData,
797                                           maxResourceIDBufferSize);
798                     out << ";\n";
799                 }
800             }
801 
802             for (GLuint id : texturesToRestore)
803             {
804                 // Emit their restore calls
805                 for (CallCapture &call : textureRestoreCalls[id])
806                 {
807                     out << "    ";
808                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
809                                           maxResourceIDBufferSize);
810                     out << ";\n";
811                 }
812             }
813             break;
814         }
815         case ResourceIDType::VertexArray:
816         {
817             TrackedResource &trackedVertexArrays =
818                 resourceTracker->getTrackedResource(contextID, ResourceIDType::VertexArray);
819             ResourceSet &newVertexArrays           = trackedVertexArrays.getNewResources();
820             ResourceSet &vertexArraysToDelete      = trackedVertexArrays.getResourcesToDelete();
821             ResourceSet &vertexArraysToRegen       = trackedVertexArrays.getResourcesToRegen();
822             ResourceSet &vertexArraysToRestore     = trackedVertexArrays.getResourcesToRestore();
823             ResourceCalls &vertexArrayRegenCalls   = trackedVertexArrays.getResourceRegenCalls();
824             ResourceCalls &vertexArrayRestoreCalls = trackedVertexArrays.getResourceRestoreCalls();
825 
826             DeleteResourcesInReset(out, contextID, newVertexArrays, vertexArraysToDelete,
827                                    resourceIDType, maxResourceIDBufferSize);
828 
829             // If any of our starting vertex arrays were deleted during the run, recreate them
830             for (GLuint id : vertexArraysToRegen)
831             {
832                 // Emit their regen calls
833                 for (CallCapture &call : vertexArrayRegenCalls[id])
834                 {
835                     out << "    ";
836                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
837                                           maxResourceIDBufferSize);
838                     out << ";\n";
839                 }
840             }
841 
842             // If any of our starting vertex arrays were modified during the run, restore their
843             // contents
844             for (GLuint id : vertexArraysToRestore)
845             {
846                 // Emit their restore calls
847                 for (CallCapture &call : vertexArrayRestoreCalls[id])
848                 {
849                     out << "    ";
850                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
851                                           maxResourceIDBufferSize);
852                     out << ";\n";
853                 }
854             }
855             break;
856         }
857         case ResourceIDType::egl_Sync:
858         {
859             TrackedResource &trackedEGLSyncs =
860                 resourceTracker->getTrackedResource(contextID, ResourceIDType::egl_Sync);
861             ResourceSet &newEGLSyncs         = trackedEGLSyncs.getNewResources();
862             ResourceSet &eglSyncsToDelete    = trackedEGLSyncs.getResourcesToDelete();
863             ResourceSet &eglSyncsToRegen     = trackedEGLSyncs.getResourcesToRegen();
864             ResourceCalls &eglSyncRegenCalls = trackedEGLSyncs.getResourceRegenCalls();
865 
866             if (!newEGLSyncs.empty() || !eglSyncsToDelete.empty())
867             {
868                 for (GLuint oldResource : eglSyncsToDelete)
869                 {
870                     out << "    eglDestroySyncKHR(gEGLDisplay, gEGLSyncMap[" << oldResource
871                         << "]);\n";
872                 }
873 
874                 for (GLuint newResource : newEGLSyncs)
875                 {
876                     out << "    eglDestroySyncKHR(gEGLDisplay, gEGLSyncMap[" << newResource
877                         << "]);\n";
878                 }
879             }
880 
881             // If any of our starting EGLsyncs were deleted during the run, recreate them
882             for (GLuint id : eglSyncsToRegen)
883             {
884                 // Emit their regen calls
885                 for (CallCapture &call : eglSyncRegenCalls[id])
886                 {
887                     out << "    ";
888                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
889                                           maxResourceIDBufferSize);
890                     out << ";\n";
891                 }
892             }
893             break;
894         }
895         case ResourceIDType::Image:
896         {
897             TrackedResource &trackedEGLImages =
898                 resourceTracker->getTrackedResource(contextID, ResourceIDType::Image);
899             ResourceSet &newEGLImages         = trackedEGLImages.getNewResources();
900             ResourceSet &eglImagesToDelete    = trackedEGLImages.getResourcesToDelete();
901             ResourceSet &eglImagesToRegen     = trackedEGLImages.getResourcesToRegen();
902             ResourceCalls &eglImageRegenCalls = trackedEGLImages.getResourceRegenCalls();
903 
904             if (!newEGLImages.empty() || !eglImagesToDelete.empty())
905             {
906                 for (GLuint oldResource : eglImagesToDelete)
907                 {
908                     out << "    DestroyEGLImageKHR(gEGLDisplay, gEGLImageMap2[" << oldResource
909                         << "], " << oldResource << ");\n";
910                 }
911 
912                 for (GLuint newResource : newEGLImages)
913                 {
914                     out << "    DestroyEGLImageKHR(gEGLDisplay, gEGLImageMap2[" << newResource
915                         << "], " << newResource << ");\n";
916                 }
917             }
918             // If any of our starting EGLImages were deleted during the run, recreate them
919             for (GLuint id : eglImagesToRegen)
920             {
921                 // Emit their regen calls
922                 for (CallCapture &call : eglImageRegenCalls[id])
923                 {
924                     out << "    ";
925                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
926                                           maxResourceIDBufferSize);
927                     out << ";\n";
928                 }
929             }
930             break;
931         }
932         default:
933             // TODO (http://anglebug.com/42263204): Reset more resource types
934             break;
935     }
936 
937     // If the output position has moved, we Reset something
938     anyResourceReset = (initialOutPos != out.tellp());
939 }
940 
MaybeResetFenceSyncObjects(std::stringstream & out,ReplayWriter & replayWriter,std::stringstream & header,ResourceTracker * resourceTracker,std::vector<uint8_t> * binaryData,size_t * maxResourceIDBufferSize)941 void MaybeResetFenceSyncObjects(std::stringstream &out,
942                                 ReplayWriter &replayWriter,
943                                 std::stringstream &header,
944                                 ResourceTracker *resourceTracker,
945                                 std::vector<uint8_t> *binaryData,
946                                 size_t *maxResourceIDBufferSize)
947 {
948     FenceSyncCalls &fenceSyncRegenCalls = resourceTracker->getFenceSyncRegenCalls();
949 
950     // If any of our starting fence sync objects were deleted during the run, recreate them
951     FenceSyncSet &fenceSyncsToRegen = resourceTracker->getFenceSyncsToRegen();
952     for (const gl::SyncID syncID : fenceSyncsToRegen)
953     {
954         // Emit their regen calls
955         for (CallCapture &call : fenceSyncRegenCalls[syncID])
956         {
957             out << "    ";
958             WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
959                                   maxResourceIDBufferSize);
960             out << ";\n";
961         }
962     }
963 }
964 
Capture(std::vector<CallCapture> * setupCalls,CallCapture && call)965 void Capture(std::vector<CallCapture> *setupCalls, CallCapture &&call)
966 {
967     setupCalls->emplace_back(std::move(call));
968 }
969 
CaptureUpdateCurrentProgram(const CallCapture & call,int programParamPos,std::vector<CallCapture> * callsOut)970 void CaptureUpdateCurrentProgram(const CallCapture &call,
971                                  int programParamPos,
972                                  std::vector<CallCapture> *callsOut)
973 {
974     const ParamCapture &param =
975         call.params.getParam("programPacked", ParamType::TShaderProgramID, programParamPos);
976     gl::ShaderProgramID programID = param.value.ShaderProgramIDVal;
977 
978     ParamBuffer paramBuffer;
979     paramBuffer.addValueParam("program", ParamType::TGLuint, programID.value);
980 
981     callsOut->emplace_back("UpdateCurrentProgram", std::move(paramBuffer));
982 }
983 
ProgramNeedsReset(const gl::Context * context,ResourceTracker * resourceTracker,gl::ShaderProgramID programID)984 bool ProgramNeedsReset(const gl::Context *context,
985                        ResourceTracker *resourceTracker,
986                        gl::ShaderProgramID programID)
987 {
988     // Check whether the program is listed in programs to regen or restore
989     TrackedResource &trackedShaderPrograms =
990         resourceTracker->getTrackedResource(context->id(), ResourceIDType::ShaderProgram);
991 
992     ResourceSet &shaderProgramsToRegen = trackedShaderPrograms.getResourcesToRegen();
993     if (shaderProgramsToRegen.count(programID.value) != 0)
994     {
995         return true;
996     }
997 
998     ResourceSet &shaderProgramsToRestore = trackedShaderPrograms.getResourcesToRestore();
999     if (shaderProgramsToRestore.count(programID.value) != 0)
1000     {
1001         return true;
1002     }
1003 
1004     // Deferred linked programs will also update their own uniforms
1005     FrameCaptureShared *frameCaptureShared = context->getShareGroup()->getFrameCaptureShared();
1006     if (frameCaptureShared->isDeferredLinkProgram(programID))
1007     {
1008         return true;
1009     }
1010 
1011     return false;
1012 }
1013 
MaybeResetDefaultUniforms(std::stringstream & out,ReplayWriter & replayWriter,std::stringstream & header,const gl::Context * context,ResourceTracker * resourceTracker,std::vector<uint8_t> * binaryData,size_t * maxResourceIDBufferSize)1014 void MaybeResetDefaultUniforms(std::stringstream &out,
1015                                ReplayWriter &replayWriter,
1016                                std::stringstream &header,
1017                                const gl::Context *context,
1018                                ResourceTracker *resourceTracker,
1019                                std::vector<uint8_t> *binaryData,
1020                                size_t *maxResourceIDBufferSize)
1021 {
1022     DefaultUniformLocationsPerProgramMap &defaultUniformsToReset =
1023         resourceTracker->getDefaultUniformsToReset();
1024 
1025     for (const auto &uniformIter : defaultUniformsToReset)
1026     {
1027         gl::ShaderProgramID programID               = uniformIter.first;
1028         const DefaultUniformLocationsSet &locations = uniformIter.second;
1029 
1030         if (ProgramNeedsReset(context, resourceTracker, programID))
1031         {
1032             // Skip programs marked for reset as they will update their own uniforms
1033             return;
1034         }
1035 
1036         // Bind the program to update its uniforms
1037         std::vector<CallCapture> bindCalls;
1038         Capture(&bindCalls, CaptureUseProgram(context->getState(), true, programID));
1039         CaptureUpdateCurrentProgram((&bindCalls)->back(), 0, &bindCalls);
1040         for (CallCapture &call : bindCalls)
1041         {
1042             out << "    ";
1043             WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1044                                   maxResourceIDBufferSize);
1045             out << ";\n";
1046         }
1047 
1048         DefaultUniformCallsPerLocationMap &defaultUniformResetCalls =
1049             resourceTracker->getDefaultUniformResetCalls(programID);
1050 
1051         // Uniform arrays might have been modified in the middle (i.e. location 5 out of 10)
1052         // We only have Reset calls for the entire array, so emit them once for the entire array
1053         std::set<gl::UniformLocation> alreadyReset;
1054 
1055         // Emit the reset calls per modified location
1056         for (const gl::UniformLocation &location : locations)
1057         {
1058             gl::UniformLocation baseLocation =
1059                 resourceTracker->getDefaultUniformBaseLocation(programID, location);
1060             if (alreadyReset.find(baseLocation) != alreadyReset.end())
1061             {
1062                 // We've already Reset this array
1063                 continue;
1064             }
1065             alreadyReset.insert(baseLocation);
1066 
1067             ASSERT(defaultUniformResetCalls.find(baseLocation) != defaultUniformResetCalls.end());
1068             std::vector<CallCapture> &callsPerLocation = defaultUniformResetCalls[baseLocation];
1069 
1070             for (CallCapture &call : callsPerLocation)
1071             {
1072                 out << "    ";
1073                 WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1074                                       maxResourceIDBufferSize);
1075                 out << ";\n";
1076             }
1077         }
1078     }
1079 }
1080 
MaybeResetOpaqueTypeObjects(ReplayWriter & replayWriter,std::stringstream & out,std::stringstream & header,const gl::Context * context,ResourceTracker * resourceTracker,std::vector<uint8_t> * binaryData,size_t * maxResourceIDBufferSize)1081 void MaybeResetOpaqueTypeObjects(ReplayWriter &replayWriter,
1082                                  std::stringstream &out,
1083                                  std::stringstream &header,
1084                                  const gl::Context *context,
1085                                  ResourceTracker *resourceTracker,
1086                                  std::vector<uint8_t> *binaryData,
1087                                  size_t *maxResourceIDBufferSize)
1088 {
1089     MaybeResetFenceSyncObjects(out, replayWriter, header, resourceTracker, binaryData,
1090                                maxResourceIDBufferSize);
1091 
1092     MaybeResetDefaultUniforms(out, replayWriter, header, context, resourceTracker, binaryData,
1093                               maxResourceIDBufferSize);
1094 }
1095 
MaybeResetContextState(ReplayWriter & replayWriter,std::stringstream & out,std::stringstream & header,ResourceTracker * resourceTracker,const gl::Context * context,std::vector<uint8_t> * binaryData,StateResetHelper & stateResetHelper,size_t * maxResourceIDBufferSize)1096 void MaybeResetContextState(ReplayWriter &replayWriter,
1097                             std::stringstream &out,
1098                             std::stringstream &header,
1099                             ResourceTracker *resourceTracker,
1100                             const gl::Context *context,
1101                             std::vector<uint8_t> *binaryData,
1102                             StateResetHelper &stateResetHelper,
1103                             size_t *maxResourceIDBufferSize)
1104 {
1105     // Check dirty states per entrypoint
1106     for (const EntryPoint &entryPoint : stateResetHelper.getDirtyEntryPoints())
1107     {
1108         const CallResetMap *resetCalls = &stateResetHelper.getResetCalls();
1109 
1110         // Create the default reset call for this entrypoint
1111         if (resetCalls->find(entryPoint) == resetCalls->end())
1112         {
1113             // If we don't have any reset calls for these entrypoints, that means we started capture
1114             // from the beginning, amd mid-execution capture was not invoked.
1115             stateResetHelper.setDefaultResetCalls(context, entryPoint);
1116         }
1117 
1118         // Emit the calls, if we added any
1119         if (resetCalls->find(entryPoint) != resetCalls->end())
1120         {
1121             for (const auto &call : resetCalls->at(entryPoint))
1122             {
1123                 out << "    ";
1124                 WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1125                                       maxResourceIDBufferSize);
1126                 out << ";\n";
1127             }
1128         }
1129     }
1130 
1131     // Reset buffer bindings that weren't bound at the beginning
1132     for (const gl::BufferBinding &dirtyBufferBinding : stateResetHelper.getDirtyBufferBindings())
1133     {
1134         // Check to see if dirty binding was part of starting set
1135         bool dirtyStartingBinding = false;
1136         for (const BufferBindingPair &startingBufferBinding :
1137              stateResetHelper.getStartingBufferBindings())
1138         {
1139             gl::BufferBinding startingBinding = startingBufferBinding.first;
1140             if (startingBinding == dirtyBufferBinding)
1141             {
1142                 dirtyStartingBinding = true;
1143             }
1144         }
1145 
1146         // If the dirty binding was not part of starting bindings, clear it
1147         if (!dirtyStartingBinding)
1148         {
1149             out << "    ";
1150             WriteCppReplayForCall(
1151                 CaptureBindBuffer(context->getState(), true, dirtyBufferBinding, {0}), replayWriter,
1152                 out, header, binaryData, maxResourceIDBufferSize);
1153             out << ";\n";
1154         }
1155     }
1156 
1157     // Restore starting buffer bindings to initial state
1158     std::vector<CallCapture> &bufferBindingCalls = resourceTracker->getBufferBindingCalls();
1159     for (CallCapture &call : bufferBindingCalls)
1160     {
1161         out << "    ";
1162         WriteCppReplayForCall(call, replayWriter, out, header, binaryData, maxResourceIDBufferSize);
1163         out << ";\n";
1164     }
1165 
1166     // Restore texture bindings to initial state
1167     size_t activeTexture                 = context->getState().getActiveSampler();
1168     const TextureResetMap &resetBindings = stateResetHelper.getResetTextureBindings();
1169     for (const auto &textureBinding : stateResetHelper.getDirtyTextureBindings())
1170     {
1171         TextureResetMap::const_iterator id = resetBindings.find(textureBinding);
1172         if (id != resetBindings.end())
1173         {
1174             const auto &[unit, target] = textureBinding;
1175 
1176             // Set active texture unit if necessary
1177             if (unit != activeTexture)
1178             {
1179                 out << "    ";
1180                 WriteCppReplayForCall(CaptureActiveTexture(context->getState(), true,
1181                                                            GL_TEXTURE0 + static_cast<GLenum>(unit)),
1182                                       replayWriter, out, header, binaryData,
1183                                       maxResourceIDBufferSize);
1184                 out << ";\n";
1185                 activeTexture = unit;
1186             }
1187 
1188             // Bind texture for this target
1189             out << "    ";
1190             WriteCppReplayForCall(CaptureBindTexture(context->getState(), true, target, id->second),
1191                                   replayWriter, out, header, binaryData, maxResourceIDBufferSize);
1192             out << ";\n";
1193         }
1194     }
1195 
1196     // Restore active texture unit to initial state if necessary
1197     if (activeTexture != stateResetHelper.getResetActiveTexture())
1198     {
1199         out << "    ";
1200         WriteCppReplayForCall(
1201             CaptureActiveTexture(
1202                 context->getState(), true,
1203                 GL_TEXTURE0 + static_cast<GLenum>(stateResetHelper.getResetActiveTexture())),
1204             replayWriter, out, header, binaryData, maxResourceIDBufferSize);
1205         out << ";\n";
1206     }
1207 }
1208 
MarkResourceIDActive(ResourceIDType resourceType,GLuint id,std::vector<CallCapture> * setupCalls,const ResourceIDToSetupCallsMap * resourceIDToSetupCallsMap)1209 void MarkResourceIDActive(ResourceIDType resourceType,
1210                           GLuint id,
1211                           std::vector<CallCapture> *setupCalls,
1212                           const ResourceIDToSetupCallsMap *resourceIDToSetupCallsMap)
1213 {
1214     const std::map<GLuint, gl::Range<size_t>> &resourceSetupCalls =
1215         (*resourceIDToSetupCallsMap)[resourceType];
1216     const auto iter = resourceSetupCalls.find(id);
1217     if (iter == resourceSetupCalls.end())
1218     {
1219         return;
1220     }
1221 
1222     // Mark all of the calls that were used to initialize this resource as ACTIVE
1223     const gl::Range<size_t> &calls = iter->second;
1224     for (size_t index : calls)
1225     {
1226         (*setupCalls)[index].isActive = true;
1227     }
1228 }
1229 
1230 // Some replay functions can get quite large. If over a certain size, this method breaks up the
1231 // 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,size_t * maxResourceIDBufferSize)1232 void WriteCppReplayFunctionWithParts(const gl::ContextID contextID,
1233                                      ReplayFunc replayFunc,
1234                                      ReplayWriter &replayWriter,
1235                                      uint32_t frameIndex,
1236                                      std::vector<uint8_t> *binaryData,
1237                                      const std::vector<CallCapture> &calls,
1238                                      std::stringstream &header,
1239                                      std::stringstream &out,
1240                                      size_t *maxResourceIDBufferSize)
1241 {
1242     int callCount = 0;
1243     int partCount = 0;
1244 
1245     if (calls.size() > kFunctionSizeLimit)
1246     {
1247         out << "void "
1248             << FmtFunction(replayFunc, contextID, FuncUsage::Definition, frameIndex, ++partCount)
1249             << "\n";
1250     }
1251     else
1252     {
1253         out << "void "
1254             << FmtFunction(replayFunc, contextID, FuncUsage::Definition, frameIndex, kNoPartId)
1255             << "\n";
1256     }
1257 
1258     out << "{\n";
1259 
1260     for (const CallCapture &call : calls)
1261     {
1262         // Process active calls for Setup and inactive calls for SetupInactive
1263         if ((call.isActive && replayFunc != ReplayFunc::SetupInactive) ||
1264             (!call.isActive && replayFunc == ReplayFunc::SetupInactive))
1265         {
1266             out << "    ";
1267             WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1268                                   maxResourceIDBufferSize);
1269             out << ";\n";
1270 
1271             if (partCount > 0 && ++callCount % kFunctionSizeLimit == 0)
1272             {
1273                 out << "}\n";
1274                 out << "\n";
1275                 out << "void "
1276                     << FmtFunction(replayFunc, contextID, FuncUsage::Definition, frameIndex,
1277                                    ++partCount)
1278                     << "\n";
1279                 out << "{\n";
1280             }
1281         }
1282     }
1283     out << "}\n";
1284 
1285     if (partCount > 0)
1286     {
1287         out << "\n";
1288         out << "void "
1289             << FmtFunction(replayFunc, contextID, FuncUsage::Definition, frameIndex, kNoPartId)
1290             << "\n";
1291         out << "{\n";
1292 
1293         // Write out the main call which calls all the parts.
1294         for (int i = 1; i <= partCount; i++)
1295         {
1296             out << "    " << FmtFunction(replayFunc, contextID, FuncUsage::Call, frameIndex, i)
1297                 << ";\n";
1298         }
1299 
1300         out << "}\n";
1301     }
1302 }
1303 
1304 // Performance can be gained by reordering traced calls and grouping them by context.
1305 // Side context calls (as opposed to main context) can be grouped together paying attention
1306 // to synchronization points in the original call stream.
WriteCppReplayFunctionWithPartsMultiContext(const gl::ContextID contextID,ReplayFunc replayFunc,ReplayWriter & replayWriter,uint32_t frameIndex,std::vector<uint8_t> * binaryData,std::vector<CallCapture> & calls,std::stringstream & header,std::stringstream & out,size_t * maxResourceIDBufferSize)1307 void WriteCppReplayFunctionWithPartsMultiContext(const gl::ContextID contextID,
1308                                                  ReplayFunc replayFunc,
1309                                                  ReplayWriter &replayWriter,
1310                                                  uint32_t frameIndex,
1311                                                  std::vector<uint8_t> *binaryData,
1312                                                  std::vector<CallCapture> &calls,
1313                                                  std::stringstream &header,
1314                                                  std::stringstream &out,
1315                                                  size_t *maxResourceIDBufferSize)
1316 {
1317     int callCount = 0;
1318     int partCount = 0;
1319 
1320     if (calls.size() > kFunctionSizeLimit)
1321     {
1322         out << "void "
1323             << FmtFunction(replayFunc, contextID, FuncUsage::Definition, frameIndex, ++partCount)
1324             << "\n";
1325     }
1326     else
1327     {
1328         out << "void "
1329             << FmtFunction(replayFunc, contextID, FuncUsage::Definition, frameIndex, kNoPartId)
1330             << "\n";
1331     }
1332 
1333     out << "{\n";
1334 
1335     std::map<gl::ContextID, std::queue<int>> sideContextCallIndices;
1336 
1337     // Helper lambda to write a context change command to the call stream
1338     auto writeMakeCurrentCall = [&](gl::ContextID cID) {
1339         CallCapture makeCurrentCall =
1340             egl::CaptureMakeCurrent(nullptr, true, nullptr, {0}, {0}, cID, EGL_TRUE);
1341         out << "    ";
1342         WriteCppReplayForCall(makeCurrentCall, replayWriter, out, header, binaryData,
1343                               maxResourceIDBufferSize);
1344         out << ";\n";
1345         callCount++;
1346     };
1347 
1348     // Helper lambda to write a call to the call stream
1349     auto writeCall = [&](CallCapture &outCall, gl::ContextID cID) {
1350         out << "    ";
1351         WriteCppReplayForCall(outCall, replayWriter, out, header, binaryData,
1352                               maxResourceIDBufferSize);
1353         out << ";\n";
1354         if (cID != contextID)
1355         {
1356             sideContextCallIndices[cID].pop();
1357         }
1358         callCount++;
1359     };
1360 
1361     int callIndex = 0;
1362     // Iterate through calls saving side context call indices in a per-side-context queue
1363     for (CallCapture &call : calls)
1364     {
1365         if (call.contextID != contextID)
1366         {
1367             sideContextCallIndices[call.contextID].push(callIndex);
1368         }
1369         callIndex++;
1370     }
1371 
1372     // At the beginning of the frame, output all side context calls occuring before a sync point.
1373     // If no sync points are present, all calls in that side context are written at this time
1374     for (auto const &sideContext : sideContextCallIndices)
1375     {
1376         gl::ContextID sideContextID = sideContext.first;
1377 
1378         // Make sidecontext current if there are commands before the first syncpoint
1379         if (!calls[sideContextCallIndices[sideContextID].front()].isSyncPoint)
1380         {
1381             writeMakeCurrentCall(sideContextID);
1382         }
1383         // Output all commands in sidecontext until a syncpoint is reached
1384         while (!sideContextCallIndices[sideContextID].empty() &&
1385                !calls[sideContextCallIndices[sideContextID].front()].isSyncPoint)
1386         {
1387             writeCall(calls[sideContextCallIndices[sideContextID].front()], sideContextID);
1388         }
1389     }
1390 
1391     // Make mainContext current
1392     writeMakeCurrentCall(contextID);
1393 
1394     // Iterate through calls writing out main context calls. When a sync point is reached, write the
1395     // next queued sequence of side context calls until another sync point is reached.
1396     for (CallCapture &call : calls)
1397     {
1398         if (call.contextID == contextID)
1399         {
1400             writeCall(call, call.contextID);
1401         }
1402         else
1403         {
1404             if (call.isSyncPoint)
1405             {
1406                 // Make sideContext current
1407                 writeMakeCurrentCall(call.contextID);
1408 
1409                 do
1410                 {
1411                     writeCall(calls[sideContextCallIndices[call.contextID].front()],
1412                               call.contextID);
1413                 } while (!sideContextCallIndices[call.contextID].empty() &&
1414                          !calls[sideContextCallIndices[call.contextID].front()].isSyncPoint);
1415 
1416                 // Make mainContext current
1417                 writeMakeCurrentCall(contextID);
1418 
1419                 if (partCount > 0 && ++callCount % kFunctionSizeLimit == 0)
1420                 {
1421                     out << "}\n";
1422                     out << "\n";
1423                     out << "void "
1424                         << FmtFunction(replayFunc, contextID, FuncUsage::Definition, frameIndex,
1425                                        ++partCount)
1426                         << "\n";
1427                     out << "{\n";
1428                 }
1429             }
1430         }
1431     }
1432     out << "}\n";
1433 
1434     if (partCount > 0)
1435     {
1436         out << "\n";
1437         out << "void "
1438             << FmtFunction(replayFunc, contextID, FuncUsage::Definition, frameIndex, kNoPartId)
1439             << "\n";
1440         out << "{\n";
1441 
1442         // Write out the main call which calls all the parts.
1443         for (int i = 1; i <= partCount; i++)
1444         {
1445             out << "    " << FmtFunction(replayFunc, contextID, FuncUsage::Call, frameIndex, i)
1446                 << ";\n";
1447         }
1448 
1449         out << "}\n";
1450     }
1451 }
1452 
1453 // Auxiliary contexts are other contexts in the share group that aren't the context calling
1454 // 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,size_t * maxResourceIDBufferSize)1455 void WriteAuxiliaryContextCppSetupReplay(ReplayWriter &replayWriter,
1456                                          bool compression,
1457                                          const std::string &outDir,
1458                                          const gl::Context *context,
1459                                          const std::string &captureLabel,
1460                                          uint32_t frameIndex,
1461                                          const std::vector<CallCapture> &setupCalls,
1462                                          std::vector<uint8_t> *binaryData,
1463                                          bool serializeStateEnabled,
1464                                          const FrameCaptureShared &frameCaptureShared,
1465                                          size_t *maxResourceIDBufferSize)
1466 {
1467     ASSERT(frameCaptureShared.getWindowSurfaceContextID() != context->id());
1468 
1469     {
1470         std::stringstream filenameStream;
1471         filenameStream << outDir << FmtCapturePrefix(context->id(), captureLabel);
1472         std::string filenamePattern = filenameStream.str();
1473         replayWriter.setFilenamePattern(filenamePattern);
1474     }
1475 
1476     {
1477         std::stringstream include;
1478         include << "#include \""
1479                 << FmtCapturePrefix(frameCaptureShared.getWindowSurfaceContextID(), captureLabel)
1480                 << ".h\"\n";
1481         include << "#include \"angle_trace_gl.h\"\n";
1482 
1483         std::string frameIncludes = include.str();
1484         replayWriter.setSourcePrologue(frameIncludes);
1485         replayWriter.setHeaderPrologue(frameIncludes);
1486     }
1487 
1488     {
1489         std::stringstream protoStream;
1490         std::stringstream headerStream;
1491         std::stringstream bodyStream;
1492 
1493         protoStream << "void " << FmtSetupFunction(kNoPartId, context->id(), FuncUsage::Prototype);
1494         std::string proto = protoStream.str();
1495 
1496         WriteCppReplayFunctionWithParts(context->id(), ReplayFunc::Setup, replayWriter, frameIndex,
1497                                         binaryData, setupCalls, headerStream, bodyStream,
1498                                         maxResourceIDBufferSize);
1499 
1500         replayWriter.addPrivateFunction(proto, headerStream, bodyStream);
1501     }
1502 
1503     replayWriter.saveFrame();
1504 }
1505 
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,size_t * maxResourceIDBufferSize)1506 void WriteShareGroupCppSetupReplay(ReplayWriter &replayWriter,
1507                                    bool compression,
1508                                    const std::string &outDir,
1509                                    const std::string &captureLabel,
1510                                    uint32_t frameIndex,
1511                                    uint32_t frameCount,
1512                                    const std::vector<CallCapture> &setupCalls,
1513                                    ResourceTracker *resourceTracker,
1514                                    std::vector<uint8_t> *binaryData,
1515                                    bool serializeStateEnabled,
1516                                    gl::ContextID windowSurfaceContextID,
1517                                    size_t *maxResourceIDBufferSize)
1518 {
1519     {
1520 
1521         std::stringstream include;
1522 
1523         include << "#include \"angle_trace_gl.h\"\n";
1524         include << "#include \"" << FmtCapturePrefix(windowSurfaceContextID, captureLabel)
1525                 << ".h\"\n";
1526 
1527         std::string includeString = include.str();
1528 
1529         replayWriter.setSourcePrologue(includeString);
1530     }
1531 
1532     {
1533         std::stringstream protoStream;
1534         std::stringstream headerStream;
1535         std::stringstream bodyStream;
1536 
1537         protoStream << "void "
1538                     << FmtSetupFunction(kNoPartId, kSharedContextId, FuncUsage::Prototype);
1539         std::string proto = protoStream.str();
1540 
1541         WriteCppReplayFunctionWithParts(kSharedContextId, ReplayFunc::Setup, replayWriter,
1542                                         frameIndex, binaryData, setupCalls, headerStream,
1543                                         bodyStream, maxResourceIDBufferSize);
1544 
1545         replayWriter.addPrivateFunction(proto, headerStream, bodyStream);
1546 
1547         protoStream.str("");
1548         headerStream.str("");
1549         bodyStream.str("");
1550         protoStream << "void "
1551                     << FmtSetupInactiveFunction(kNoPartId, kSharedContextId, FuncUsage::Prototype);
1552         proto = protoStream.str();
1553 
1554         WriteCppReplayFunctionWithParts(kSharedContextId, ReplayFunc::SetupInactive, replayWriter,
1555                                         frameIndex, binaryData, setupCalls, headerStream,
1556                                         bodyStream, maxResourceIDBufferSize);
1557         replayWriter.addPrivateFunction(proto, headerStream, bodyStream);
1558     }
1559 
1560     {
1561         std::stringstream filenameStream;
1562         filenameStream << outDir << FmtCapturePrefix(kSharedContextId, captureLabel);
1563 
1564         std::string filenamePattern = filenameStream.str();
1565 
1566         replayWriter.setFilenamePattern(filenamePattern);
1567     }
1568 
1569     replayWriter.saveSetupFile();
1570 }
1571 
GetAttachedProgramSources(const gl::Context * context,const gl::Program * program)1572 ProgramSources GetAttachedProgramSources(const gl::Context *context, const gl::Program *program)
1573 {
1574     ProgramSources sources;
1575     for (gl::ShaderType shaderType : gl::AllShaderTypes())
1576     {
1577         const gl::Shader *shader = program->getAttachedShader(shaderType);
1578         if (shader)
1579         {
1580             sources[shaderType] = shader->getSourceString();
1581         }
1582     }
1583     return sources;
1584 }
1585 
1586 template <typename IDType>
CaptureUpdateResourceIDs(const gl::Context * context,const CallCapture & call,const ParamCapture & param,ResourceTracker * resourceTracker,std::vector<CallCapture> * callsOut)1587 void CaptureUpdateResourceIDs(const gl::Context *context,
1588                               const CallCapture &call,
1589                               const ParamCapture &param,
1590                               ResourceTracker *resourceTracker,
1591                               std::vector<CallCapture> *callsOut)
1592 {
1593     GLsizei n = call.params.getParamFlexName("n", "count", ParamType::TGLsizei, 0).value.GLsizeiVal;
1594     ASSERT(param.data.size() == 1);
1595     ResourceIDType resourceIDType = GetResourceIDTypeFromParamType(param.type);
1596     ASSERT(resourceIDType != ResourceIDType::InvalidEnum &&
1597            resourceIDType != ResourceIDType::ShaderProgram);
1598     const char *resourceName = GetResourceIDTypeName(resourceIDType);
1599 
1600     std::stringstream updateFuncNameStr;
1601     updateFuncNameStr << "Update" << resourceName << "ID";
1602     bool trackedPerContext = IsTrackedPerContext(resourceIDType);
1603     if (trackedPerContext)
1604     {
1605         // TODO (https://issuetracker.google.com/169868803) The '2' version can be removed after all
1606         // context-local objects are tracked per-context
1607         updateFuncNameStr << "2";
1608     }
1609     std::string updateFuncName = updateFuncNameStr.str();
1610 
1611     const IDType *returnedIDs = reinterpret_cast<const IDType *>(param.data[0].data());
1612 
1613     ResourceSet &startingSet =
1614         resourceTracker->getTrackedResource(context->id(), resourceIDType).getStartingResources();
1615 
1616     for (GLsizei idIndex = 0; idIndex < n; ++idIndex)
1617     {
1618         IDType id                = returnedIDs[idIndex];
1619         GLsizei readBufferOffset = idIndex * sizeof(gl::RenderbufferID);
1620         ParamBuffer params;
1621         if (trackedPerContext)
1622         {
1623             params.addValueParam("contextId", ParamType::TGLuint, context->id().value);
1624         }
1625         params.addValueParam("id", ParamType::TGLuint, id.value);
1626         params.addValueParam("readBufferOffset", ParamType::TGLsizei, readBufferOffset);
1627         callsOut->emplace_back(updateFuncName, std::move(params));
1628 
1629         // Add only if not in starting resources.
1630         if (startingSet.find(id.value) == startingSet.end())
1631         {
1632             resourceTracker->getTrackedResource(context->id(), resourceIDType)
1633                 .getNewResources()
1634                 .insert(id.value);
1635         }
1636     }
1637 }
1638 
CaptureUpdateUniformLocations(const gl::Program * program,std::vector<CallCapture> * callsOut)1639 void CaptureUpdateUniformLocations(const gl::Program *program, std::vector<CallCapture> *callsOut)
1640 {
1641     const gl::ProgramExecutable &executable            = program->getExecutable();
1642     const std::vector<gl::LinkedUniform> &uniforms     = executable.getUniforms();
1643     const std::vector<gl::VariableLocation> &locations = executable.getUniformLocations();
1644 
1645     for (GLint location = 0; location < static_cast<GLint>(locations.size()); ++location)
1646     {
1647         const gl::VariableLocation &locationVar = locations[location];
1648 
1649         // This handles the case where the application calls glBindUniformLocationCHROMIUM
1650         // on an unused uniform. We must still store a -1 into gUniformLocations in case the
1651         // application attempts to call a glUniform* call. To do this we'll pass in a blank name to
1652         // force glGetUniformLocation to return -1.
1653         std::string name;
1654         int count = 1;
1655         ParamBuffer params;
1656         params.addValueParam("program", ParamType::TGLuint, program->id().value);
1657 
1658         if (locationVar.index >= uniforms.size())
1659         {
1660             name = "";
1661         }
1662         else
1663         {
1664             const gl::LinkedUniform &uniform = uniforms[locationVar.index];
1665 
1666             name = executable.getUniformNameByIndex(locationVar.index);
1667 
1668             if (uniform.isArray())
1669             {
1670                 if (locationVar.arrayIndex > 0)
1671                 {
1672                     // Non-sequential array uniform locations are not currently handled.
1673                     // In practice array locations shouldn't ever be non-sequential.
1674                     ASSERT(uniform.getLocation() == -1 ||
1675                            location ==
1676                                uniform.getLocation() + static_cast<int>(locationVar.arrayIndex));
1677                     continue;
1678                 }
1679 
1680                 name  = gl::StripLastArrayIndex(name);
1681                 count = uniform.getBasicTypeElementCount();
1682             }
1683         }
1684 
1685         ParamCapture nameParam("name", ParamType::TGLcharConstPointer);
1686         CaptureString(name.c_str(), &nameParam);
1687         params.addParam(std::move(nameParam));
1688         params.addValueParam("location", ParamType::TGLint, location);
1689         params.addValueParam("count", ParamType::TGLint, static_cast<GLint>(count));
1690         callsOut->emplace_back("UpdateUniformLocation", std::move(params));
1691     }
1692 }
1693 
CaptureValidateSerializedState(const gl::Context * context,std::vector<CallCapture> * callsOut)1694 void CaptureValidateSerializedState(const gl::Context *context, std::vector<CallCapture> *callsOut)
1695 {
1696     INFO() << "Capturing validation checkpoint at position " << callsOut->size();
1697 
1698     context->finishImmutable();
1699 
1700     std::string serializedState;
1701     angle::Result result = angle::SerializeContextToString(context, &serializedState);
1702     if (result != angle::Result::Continue)
1703     {
1704         ERR() << "Internal error serializing context state.";
1705         return;
1706     }
1707     ParamCapture serializedStateParam("serializedState", ParamType::TGLcharConstPointer);
1708     CaptureString(serializedState.c_str(), &serializedStateParam);
1709 
1710     ParamBuffer params;
1711     params.addParam(std::move(serializedStateParam));
1712 
1713     callsOut->emplace_back("VALIDATE_CHECKPOINT", std::move(params));
1714 }
1715 
CaptureUpdateUniformBlockIndexes(const gl::Program * program,std::vector<CallCapture> * callsOut)1716 void CaptureUpdateUniformBlockIndexes(const gl::Program *program,
1717                                       std::vector<CallCapture> *callsOut)
1718 {
1719     const std::vector<gl::InterfaceBlock> &uniformBlocks =
1720         program->getExecutable().getUniformBlocks();
1721 
1722     for (GLuint index = 0; index < uniformBlocks.size(); ++index)
1723     {
1724         ParamBuffer params;
1725 
1726         std::string name;
1727         params.addValueParam("program", ParamType::TShaderProgramID, program->id());
1728 
1729         const std::string fullName = uniformBlocks[index].nameWithArrayIndex();
1730         ParamCapture nameParam("name", ParamType::TGLcharConstPointer);
1731         CaptureString(fullName.c_str(), &nameParam);
1732         params.addParam(std::move(nameParam));
1733 
1734         params.addValueParam("index", ParamType::TGLuint, index);
1735         callsOut->emplace_back("UpdateUniformBlockIndex", std::move(params));
1736     }
1737 }
1738 
CaptureDeleteUniformLocations(gl::ShaderProgramID program,std::vector<CallCapture> * callsOut)1739 void CaptureDeleteUniformLocations(gl::ShaderProgramID program, std::vector<CallCapture> *callsOut)
1740 {
1741     ParamBuffer params;
1742     params.addValueParam("program", ParamType::TShaderProgramID, program);
1743     callsOut->emplace_back("DeleteUniformLocations", std::move(params));
1744 }
1745 
MaybeCaptureUpdateResourceIDs(const gl::Context * context,ResourceTracker * resourceTracker,std::vector<CallCapture> * callsOut)1746 void MaybeCaptureUpdateResourceIDs(const gl::Context *context,
1747                                    ResourceTracker *resourceTracker,
1748                                    std::vector<CallCapture> *callsOut)
1749 {
1750     const CallCapture &call = callsOut->back();
1751 
1752     switch (call.entryPoint)
1753     {
1754         case EntryPoint::GLGenBuffers:
1755         {
1756             const ParamCapture &buffers =
1757                 call.params.getParam("buffersPacked", ParamType::TBufferIDPointer, 1);
1758             CaptureUpdateResourceIDs<gl::BufferID>(context, call, buffers, resourceTracker,
1759                                                    callsOut);
1760             break;
1761         }
1762 
1763         case EntryPoint::GLGenFencesNV:
1764         {
1765             const ParamCapture &fences =
1766                 call.params.getParam("fencesPacked", ParamType::TFenceNVIDPointer, 1);
1767             CaptureUpdateResourceIDs<gl::FenceNVID>(context, call, fences, resourceTracker,
1768                                                     callsOut);
1769             break;
1770         }
1771 
1772         case EntryPoint::GLGenFramebuffers:
1773         case EntryPoint::GLGenFramebuffersOES:
1774         {
1775             const ParamCapture &framebuffers =
1776                 call.params.getParam("framebuffersPacked", ParamType::TFramebufferIDPointer, 1);
1777             CaptureUpdateResourceIDs<gl::FramebufferID>(context, call, framebuffers,
1778                                                         resourceTracker, callsOut);
1779             break;
1780         }
1781 
1782         case EntryPoint::GLGenProgramPipelines:
1783         {
1784             const ParamCapture &pipelines =
1785                 call.params.getParam("pipelinesPacked", ParamType::TProgramPipelineIDPointer, 1);
1786             CaptureUpdateResourceIDs<gl::ProgramPipelineID>(context, call, pipelines,
1787                                                             resourceTracker, callsOut);
1788             break;
1789         }
1790 
1791         case EntryPoint::GLGenQueries:
1792         case EntryPoint::GLGenQueriesEXT:
1793         {
1794             const ParamCapture &queries =
1795                 call.params.getParam("idsPacked", ParamType::TQueryIDPointer, 1);
1796             CaptureUpdateResourceIDs<gl::QueryID>(context, call, queries, resourceTracker,
1797                                                   callsOut);
1798             break;
1799         }
1800 
1801         case EntryPoint::GLGenRenderbuffers:
1802         case EntryPoint::GLGenRenderbuffersOES:
1803         {
1804             const ParamCapture &renderbuffers =
1805                 call.params.getParam("renderbuffersPacked", ParamType::TRenderbufferIDPointer, 1);
1806             CaptureUpdateResourceIDs<gl::RenderbufferID>(context, call, renderbuffers,
1807                                                          resourceTracker, callsOut);
1808             break;
1809         }
1810 
1811         case EntryPoint::GLGenSamplers:
1812         {
1813             const ParamCapture &samplers =
1814                 call.params.getParam("samplersPacked", ParamType::TSamplerIDPointer, 1);
1815             CaptureUpdateResourceIDs<gl::SamplerID>(context, call, samplers, resourceTracker,
1816                                                     callsOut);
1817             break;
1818         }
1819 
1820         case EntryPoint::GLGenSemaphoresEXT:
1821         {
1822             const ParamCapture &semaphores =
1823                 call.params.getParam("semaphoresPacked", ParamType::TSemaphoreIDPointer, 1);
1824             CaptureUpdateResourceIDs<gl::SemaphoreID>(context, call, semaphores, resourceTracker,
1825                                                       callsOut);
1826             break;
1827         }
1828 
1829         case EntryPoint::GLGenTextures:
1830         {
1831             const ParamCapture &textures =
1832                 call.params.getParam("texturesPacked", ParamType::TTextureIDPointer, 1);
1833             CaptureUpdateResourceIDs<gl::TextureID>(context, call, textures, resourceTracker,
1834                                                     callsOut);
1835             break;
1836         }
1837 
1838         case EntryPoint::GLGenTransformFeedbacks:
1839         {
1840             const ParamCapture &xfbs =
1841                 call.params.getParam("idsPacked", ParamType::TTransformFeedbackIDPointer, 1);
1842             CaptureUpdateResourceIDs<gl::TransformFeedbackID>(context, call, xfbs, resourceTracker,
1843                                                               callsOut);
1844             break;
1845         }
1846 
1847         case EntryPoint::GLGenVertexArrays:
1848         case EntryPoint::GLGenVertexArraysOES:
1849         {
1850             const ParamCapture &vertexArrays =
1851                 call.params.getParam("arraysPacked", ParamType::TVertexArrayIDPointer, 1);
1852             CaptureUpdateResourceIDs<gl::VertexArrayID>(context, call, vertexArrays,
1853                                                         resourceTracker, callsOut);
1854             break;
1855         }
1856 
1857         case EntryPoint::GLCreateMemoryObjectsEXT:
1858         {
1859             const ParamCapture &memoryObjects =
1860                 call.params.getParam("memoryObjectsPacked", ParamType::TMemoryObjectIDPointer, 1);
1861             CaptureUpdateResourceIDs<gl::MemoryObjectID>(context, call, memoryObjects,
1862                                                          resourceTracker, callsOut);
1863             break;
1864         }
1865 
1866         default:
1867             break;
1868     }
1869 }
1870 
IsDefaultCurrentValue(const gl::VertexAttribCurrentValueData & currentValue)1871 bool IsDefaultCurrentValue(const gl::VertexAttribCurrentValueData &currentValue)
1872 {
1873     if (currentValue.Type != gl::VertexAttribType::Float)
1874         return false;
1875 
1876     return currentValue.Values.FloatValues[0] == 0.0f &&
1877            currentValue.Values.FloatValues[1] == 0.0f &&
1878            currentValue.Values.FloatValues[2] == 0.0f && currentValue.Values.FloatValues[3] == 1.0f;
1879 }
1880 
IsQueryActive(const gl::State & glState,gl::QueryID & queryID)1881 bool IsQueryActive(const gl::State &glState, gl::QueryID &queryID)
1882 {
1883     const gl::ActiveQueryMap &activeQueries = glState.getActiveQueriesForCapture();
1884     for (const auto &activeQueryIter : activeQueries)
1885     {
1886         const gl::Query *activeQuery = activeQueryIter.get();
1887         if (activeQuery && activeQuery->id() == queryID)
1888         {
1889             return true;
1890         }
1891     }
1892 
1893     return false;
1894 }
1895 
IsTextureUpdate(CallCapture & call)1896 bool IsTextureUpdate(CallCapture &call)
1897 {
1898     switch (call.entryPoint)
1899     {
1900         case EntryPoint::GLCompressedCopyTextureCHROMIUM:
1901         case EntryPoint::GLCompressedTexImage2D:
1902         case EntryPoint::GLCompressedTexImage2DRobustANGLE:
1903         case EntryPoint::GLCompressedTexImage3D:
1904         case EntryPoint::GLCompressedTexImage3DOES:
1905         case EntryPoint::GLCompressedTexImage3DRobustANGLE:
1906         case EntryPoint::GLCompressedTexSubImage2D:
1907         case EntryPoint::GLCompressedTexSubImage2DRobustANGLE:
1908         case EntryPoint::GLCompressedTexSubImage3D:
1909         case EntryPoint::GLCompressedTexSubImage3DOES:
1910         case EntryPoint::GLCompressedTexSubImage3DRobustANGLE:
1911         case EntryPoint::GLCopyTexImage2D:
1912         case EntryPoint::GLCopyTexSubImage2D:
1913         case EntryPoint::GLCopyTexSubImage3D:
1914         case EntryPoint::GLCopyTexSubImage3DOES:
1915         case EntryPoint::GLCopyTexture3DANGLE:
1916         case EntryPoint::GLCopyTextureCHROMIUM:
1917         case EntryPoint::GLTexImage2D:
1918         case EntryPoint::GLTexImage2DExternalANGLE:
1919         case EntryPoint::GLTexImage2DRobustANGLE:
1920         case EntryPoint::GLTexImage3D:
1921         case EntryPoint::GLTexImage3DOES:
1922         case EntryPoint::GLTexImage3DRobustANGLE:
1923         case EntryPoint::GLTexSubImage2D:
1924         case EntryPoint::GLTexSubImage2DRobustANGLE:
1925         case EntryPoint::GLTexSubImage3D:
1926         case EntryPoint::GLTexSubImage3DOES:
1927         case EntryPoint::GLTexSubImage3DRobustANGLE:
1928         case EntryPoint::GLCopyImageSubData:
1929         case EntryPoint::GLCopyImageSubDataEXT:
1930         case EntryPoint::GLCopyImageSubDataOES:
1931             return true;
1932         default:
1933             return false;
1934     }
1935 }
1936 
IsImageUpdate(CallCapture & call)1937 bool IsImageUpdate(CallCapture &call)
1938 {
1939     switch (call.entryPoint)
1940     {
1941         case EntryPoint::GLDispatchCompute:
1942         case EntryPoint::GLDispatchComputeIndirect:
1943             return true;
1944         default:
1945             return false;
1946     }
1947 }
1948 
IsVertexArrayUpdate(CallCapture & call)1949 bool IsVertexArrayUpdate(CallCapture &call)
1950 {
1951     switch (call.entryPoint)
1952     {
1953         case EntryPoint::GLVertexAttribFormat:
1954         case EntryPoint::GLVertexAttribIFormat:
1955         case EntryPoint::GLBindVertexBuffer:
1956         case EntryPoint::GLVertexAttribBinding:
1957         case EntryPoint::GLVertexAttribPointer:
1958         case EntryPoint::GLVertexAttribIPointer:
1959         case EntryPoint::GLEnableVertexAttribArray:
1960         case EntryPoint::GLDisableVertexAttribArray:
1961         case EntryPoint::GLVertexBindingDivisor:
1962         case EntryPoint::GLVertexAttribDivisor:
1963             return true;
1964         default:
1965             return false;
1966     }
1967 }
1968 
IsSharedObjectResource(ResourceIDType type)1969 bool IsSharedObjectResource(ResourceIDType type)
1970 {
1971     // This helper function informs us which objects are shared vs. per context
1972     //
1973     //   OpenGL ES Version 3.2 (October 22, 2019)
1974     //   Chapter 5 Shared Objects and Multiple Contexts:
1975     //
1976     //   - Objects that can be shared between contexts include buffer objects, program
1977     //     and shader objects, renderbuffer objects, sampler objects, sync objects, and texture
1978     //     objects (except for the texture objects named zero).
1979     //   - Objects which contain references to other objects include framebuffer, program
1980     //     pipeline, transform feedback, and vertex array objects. Such objects are called
1981     //     container objects and are not shared.
1982     //
1983     // Notably absent from this list are Sync objects, which are not ResourceIDType, are handled
1984     // elsewhere, and are shared:
1985     //   - 2.6.13 Sync Objects: Sync objects may be shared.
1986 
1987     switch (type)
1988     {
1989         case ResourceIDType::Buffer:
1990             // 2.6.2 Buffer Objects: Buffer objects may be shared.
1991             return true;
1992 
1993         case ResourceIDType::Framebuffer:
1994             // 2.6.9 Framebuffer Objects: Framebuffer objects are container objects including
1995             // references to renderbuffer and / or texture objects, and are not shared.
1996             return false;
1997 
1998         case ResourceIDType::ProgramPipeline:
1999             // 2.6.5 Program Pipeline Objects: Program pipeline objects are container objects
2000             // including references to program objects, and are not shared.
2001             return false;
2002 
2003         case ResourceIDType::TransformFeedback:
2004             // 2.6.11 Transform Feedback Objects: Transform feedback objects are container objects
2005             // including references to buffer objects, and are not shared
2006             return false;
2007 
2008         case ResourceIDType::VertexArray:
2009             // 2.6.10 Vertex Array Objects: Vertex array objects are container objects including
2010             // references to buffer objects, and are not shared
2011             return false;
2012 
2013         case ResourceIDType::FenceNV:
2014             // From https://registry.khronos.org/OpenGL/extensions/NV/NV_fence.txt
2015             //  Are the fences sharable between multiple contexts?
2016             //   RESOLUTION: No.
2017             return false;
2018 
2019         case ResourceIDType::Renderbuffer:
2020             // 2.6.8 Renderbuffer Objects: Renderbuffer objects may be shared.
2021             return true;
2022 
2023         case ResourceIDType::ShaderProgram:
2024             // 2.6.3 Shader Objects: Shader objects may be shared.
2025             // 2.6.4 Program Objects: Program objects may be shared.
2026             return true;
2027 
2028         case ResourceIDType::Sampler:
2029             // 2.6.7 Sampler Objects: Sampler objects may be shared
2030             return true;
2031 
2032         case ResourceIDType::Sync:
2033             // 2.6.13 Sync Objects: Sync objects may be shared.
2034             return true;
2035 
2036         case ResourceIDType::Texture:
2037             // 2.6.6 Texture Objects: Texture objects may be shared
2038             return true;
2039 
2040         case ResourceIDType::Query:
2041             // 2.6.12 Query Objects: Query objects are not shared
2042             return false;
2043 
2044         case ResourceIDType::Semaphore:
2045             // From https://registry.khronos.org/OpenGL/extensions/EXT/EXT_external_objects.txt
2046             // 2.6.14 Semaphore Objects: Semaphore objects may be shared.
2047             return true;
2048 
2049         case ResourceIDType::MemoryObject:
2050             // From https://registry.khronos.org/OpenGL/extensions/EXT/EXT_external_objects.txt
2051             // 2.6.15 Memory Objects: Memory objects may be shared.
2052             return true;
2053 
2054         case ResourceIDType::Context:
2055         case ResourceIDType::Image:
2056         case ResourceIDType::Surface:
2057         case ResourceIDType::egl_Sync:
2058             // EGL types are associated with a display and not bound to a context
2059             // For the way this function is used, we can treat them as shared.
2060             return true;
2061 
2062         case ResourceIDType::EnumCount:
2063         default:
2064             ERR() << "Unhandled ResourceIDType= " << static_cast<int>(type);
2065             UNREACHABLE();
2066             return false;
2067     }
2068 }
2069 
2070 enum class DefaultUniformType
2071 {
2072     None,
2073     CurrentProgram,
2074     SpecifiedProgram,
2075 };
2076 
GetDefaultUniformType(const CallCapture & call)2077 DefaultUniformType GetDefaultUniformType(const CallCapture &call)
2078 {
2079     switch (call.entryPoint)
2080     {
2081         case EntryPoint::GLProgramUniform1f:
2082         case EntryPoint::GLProgramUniform1fEXT:
2083         case EntryPoint::GLProgramUniform1fv:
2084         case EntryPoint::GLProgramUniform1fvEXT:
2085         case EntryPoint::GLProgramUniform1i:
2086         case EntryPoint::GLProgramUniform1iEXT:
2087         case EntryPoint::GLProgramUniform1iv:
2088         case EntryPoint::GLProgramUniform1ivEXT:
2089         case EntryPoint::GLProgramUniform1ui:
2090         case EntryPoint::GLProgramUniform1uiEXT:
2091         case EntryPoint::GLProgramUniform1uiv:
2092         case EntryPoint::GLProgramUniform1uivEXT:
2093         case EntryPoint::GLProgramUniform2f:
2094         case EntryPoint::GLProgramUniform2fEXT:
2095         case EntryPoint::GLProgramUniform2fv:
2096         case EntryPoint::GLProgramUniform2fvEXT:
2097         case EntryPoint::GLProgramUniform2i:
2098         case EntryPoint::GLProgramUniform2iEXT:
2099         case EntryPoint::GLProgramUniform2iv:
2100         case EntryPoint::GLProgramUniform2ivEXT:
2101         case EntryPoint::GLProgramUniform2ui:
2102         case EntryPoint::GLProgramUniform2uiEXT:
2103         case EntryPoint::GLProgramUniform2uiv:
2104         case EntryPoint::GLProgramUniform2uivEXT:
2105         case EntryPoint::GLProgramUniform3f:
2106         case EntryPoint::GLProgramUniform3fEXT:
2107         case EntryPoint::GLProgramUniform3fv:
2108         case EntryPoint::GLProgramUniform3fvEXT:
2109         case EntryPoint::GLProgramUniform3i:
2110         case EntryPoint::GLProgramUniform3iEXT:
2111         case EntryPoint::GLProgramUniform3iv:
2112         case EntryPoint::GLProgramUniform3ivEXT:
2113         case EntryPoint::GLProgramUniform3ui:
2114         case EntryPoint::GLProgramUniform3uiEXT:
2115         case EntryPoint::GLProgramUniform3uiv:
2116         case EntryPoint::GLProgramUniform3uivEXT:
2117         case EntryPoint::GLProgramUniform4f:
2118         case EntryPoint::GLProgramUniform4fEXT:
2119         case EntryPoint::GLProgramUniform4fv:
2120         case EntryPoint::GLProgramUniform4fvEXT:
2121         case EntryPoint::GLProgramUniform4i:
2122         case EntryPoint::GLProgramUniform4iEXT:
2123         case EntryPoint::GLProgramUniform4iv:
2124         case EntryPoint::GLProgramUniform4ivEXT:
2125         case EntryPoint::GLProgramUniform4ui:
2126         case EntryPoint::GLProgramUniform4uiEXT:
2127         case EntryPoint::GLProgramUniform4uiv:
2128         case EntryPoint::GLProgramUniform4uivEXT:
2129         case EntryPoint::GLProgramUniformMatrix2fv:
2130         case EntryPoint::GLProgramUniformMatrix2fvEXT:
2131         case EntryPoint::GLProgramUniformMatrix2x3fv:
2132         case EntryPoint::GLProgramUniformMatrix2x3fvEXT:
2133         case EntryPoint::GLProgramUniformMatrix2x4fv:
2134         case EntryPoint::GLProgramUniformMatrix2x4fvEXT:
2135         case EntryPoint::GLProgramUniformMatrix3fv:
2136         case EntryPoint::GLProgramUniformMatrix3fvEXT:
2137         case EntryPoint::GLProgramUniformMatrix3x2fv:
2138         case EntryPoint::GLProgramUniformMatrix3x2fvEXT:
2139         case EntryPoint::GLProgramUniformMatrix3x4fv:
2140         case EntryPoint::GLProgramUniformMatrix3x4fvEXT:
2141         case EntryPoint::GLProgramUniformMatrix4fv:
2142         case EntryPoint::GLProgramUniformMatrix4fvEXT:
2143         case EntryPoint::GLProgramUniformMatrix4x2fv:
2144         case EntryPoint::GLProgramUniformMatrix4x2fvEXT:
2145         case EntryPoint::GLProgramUniformMatrix4x3fv:
2146         case EntryPoint::GLProgramUniformMatrix4x3fvEXT:
2147             return DefaultUniformType::SpecifiedProgram;
2148 
2149         case EntryPoint::GLUniform1f:
2150         case EntryPoint::GLUniform1fv:
2151         case EntryPoint::GLUniform1i:
2152         case EntryPoint::GLUniform1iv:
2153         case EntryPoint::GLUniform1ui:
2154         case EntryPoint::GLUniform1uiv:
2155         case EntryPoint::GLUniform2f:
2156         case EntryPoint::GLUniform2fv:
2157         case EntryPoint::GLUniform2i:
2158         case EntryPoint::GLUniform2iv:
2159         case EntryPoint::GLUniform2ui:
2160         case EntryPoint::GLUniform2uiv:
2161         case EntryPoint::GLUniform3f:
2162         case EntryPoint::GLUniform3fv:
2163         case EntryPoint::GLUniform3i:
2164         case EntryPoint::GLUniform3iv:
2165         case EntryPoint::GLUniform3ui:
2166         case EntryPoint::GLUniform3uiv:
2167         case EntryPoint::GLUniform4f:
2168         case EntryPoint::GLUniform4fv:
2169         case EntryPoint::GLUniform4i:
2170         case EntryPoint::GLUniform4iv:
2171         case EntryPoint::GLUniform4ui:
2172         case EntryPoint::GLUniform4uiv:
2173         case EntryPoint::GLUniformMatrix2fv:
2174         case EntryPoint::GLUniformMatrix2x3fv:
2175         case EntryPoint::GLUniformMatrix2x4fv:
2176         case EntryPoint::GLUniformMatrix3fv:
2177         case EntryPoint::GLUniformMatrix3x2fv:
2178         case EntryPoint::GLUniformMatrix3x4fv:
2179         case EntryPoint::GLUniformMatrix4fv:
2180         case EntryPoint::GLUniformMatrix4x2fv:
2181         case EntryPoint::GLUniformMatrix4x3fv:
2182             return DefaultUniformType::CurrentProgram;
2183 
2184         default:
2185             return DefaultUniformType::None;
2186     }
2187 }
2188 
CaptureFramebufferAttachment(std::vector<CallCapture> * setupCalls,const gl::State & replayState,const FramebufferCaptureFuncs & framebufferFuncs,const gl::FramebufferAttachment & attachment,std::vector<CallCapture> * shareGroupSetupCalls,ResourceIDToSetupCallsMap * resourceIDToSetupCalls)2189 void CaptureFramebufferAttachment(std::vector<CallCapture> *setupCalls,
2190                                   const gl::State &replayState,
2191                                   const FramebufferCaptureFuncs &framebufferFuncs,
2192                                   const gl::FramebufferAttachment &attachment,
2193                                   std::vector<CallCapture> *shareGroupSetupCalls,
2194                                   ResourceIDToSetupCallsMap *resourceIDToSetupCalls)
2195 {
2196     GLuint resourceID = attachment.getResource()->getId();
2197 
2198     if (attachment.type() == GL_TEXTURE)
2199     {
2200         gl::ImageIndex index = attachment.getTextureImageIndex();
2201 
2202         if (index.usesTex3D())
2203         {
2204             Capture(setupCalls, CaptureFramebufferTextureLayer(
2205                                     replayState, true, GL_FRAMEBUFFER, attachment.getBinding(),
2206                                     {resourceID}, index.getLevelIndex(), index.getLayerIndex()));
2207         }
2208         else
2209         {
2210             Capture(setupCalls,
2211                     framebufferFuncs.framebufferTexture2D(
2212                         replayState, true, GL_FRAMEBUFFER, attachment.getBinding(),
2213                         index.getTargetOrFirstCubeFace(), {resourceID}, index.getLevelIndex()));
2214         }
2215 
2216         std::vector<gl::TextureID> textureIDs;
2217         const CallCapture &call = setupCalls->back();
2218         if (FindResourceIDsInCall<gl::TextureID>(call, textureIDs))
2219         {
2220             // We skip the is active check on the assumption this call is made during MEC
2221             for (gl::TextureID textureID : textureIDs)
2222             {
2223                 // Track that this call referenced a Texture, setting it active for Setup
2224                 MarkResourceIDActive(ResourceIDType::Texture, textureID.value, shareGroupSetupCalls,
2225                                      resourceIDToSetupCalls);
2226             }
2227         }
2228     }
2229     else
2230     {
2231         ASSERT(attachment.type() == GL_RENDERBUFFER);
2232         Capture(setupCalls, framebufferFuncs.framebufferRenderbuffer(
2233                                 replayState, true, GL_FRAMEBUFFER, attachment.getBinding(),
2234                                 GL_RENDERBUFFER, {resourceID}));
2235     }
2236 }
2237 
CaptureUpdateUniformValues(const gl::State & replayState,const gl::Context * context,gl::Program * program,ResourceTracker * resourceTracker,std::vector<CallCapture> * callsOut)2238 void CaptureUpdateUniformValues(const gl::State &replayState,
2239                                 const gl::Context *context,
2240                                 gl::Program *program,
2241                                 ResourceTracker *resourceTracker,
2242                                 std::vector<CallCapture> *callsOut)
2243 {
2244     if (!program->isLinked())
2245     {
2246         // We can't populate uniforms if the program hasn't been linked
2247         return;
2248     }
2249 
2250     // We need to bind the program and update its uniforms
2251     if (!replayState.getProgram() || replayState.getProgram()->id() != program->id())
2252     {
2253         Capture(callsOut, CaptureUseProgram(replayState, true, program->id()));
2254         CaptureUpdateCurrentProgram(callsOut->back(), 0, callsOut);
2255     }
2256 
2257     const gl::ProgramExecutable &executable = program->getExecutable();
2258 
2259     for (GLuint uniformIndex = 0;
2260          uniformIndex < static_cast<GLuint>(executable.getUniforms().size()); uniformIndex++)
2261     {
2262         std::string uniformName          = executable.getUniformNameByIndex(uniformIndex);
2263         const gl::LinkedUniform &uniform = executable.getUniformByIndex(uniformIndex);
2264 
2265         int uniformCount = 1;
2266         if (uniform.isArray())
2267         {
2268             uniformCount = uniform.getBasicTypeElementCount();
2269             uniformName  = gl::StripLastArrayIndex(uniformName);
2270         }
2271 
2272         gl::UniformLocation uniformLoc      = executable.getUniformLocation(uniformName);
2273         const gl::UniformTypeInfo &typeInfo = gl::GetUniformTypeInfo(uniform.getType());
2274         int componentCount                  = typeInfo.componentCount;
2275         int uniformSize                     = uniformCount * componentCount;
2276 
2277         // For arrayed uniforms, we'll need to increment a read location
2278         gl::UniformLocation readLoc = uniformLoc;
2279 
2280         // If the uniform is unused, just continue
2281         if (readLoc.value == -1)
2282         {
2283             continue;
2284         }
2285 
2286         // Image uniforms are special and cannot be set this way
2287         if (typeInfo.isImageType)
2288         {
2289             continue;
2290         }
2291 
2292         DefaultUniformCallsPerLocationMap &resetCalls =
2293             resourceTracker->getDefaultUniformResetCalls(program->id());
2294 
2295         // Create two lists of calls for uniforms, one for Setup, one for Reset
2296         CallVector defaultUniformCalls({callsOut, &resetCalls[uniformLoc]});
2297 
2298         // Samplers should be populated with GL_INT, regardless of return type
2299         if (typeInfo.isSampler)
2300         {
2301             std::vector<GLint> uniformBuffer(uniformSize);
2302             for (int index = 0; index < uniformCount; index++, readLoc.value++)
2303             {
2304                 executable.getUniformiv(context, readLoc,
2305                                         uniformBuffer.data() + index * componentCount);
2306                 resourceTracker->setDefaultUniformBaseLocation(program->id(), readLoc, uniformLoc);
2307             }
2308 
2309             for (std::vector<CallCapture> *calls : defaultUniformCalls)
2310             {
2311                 Capture(calls, CaptureUniform1iv(replayState, true, uniformLoc, uniformCount,
2312                                                  uniformBuffer.data()));
2313             }
2314 
2315             continue;
2316         }
2317 
2318         switch (typeInfo.componentType)
2319         {
2320             case GL_FLOAT:
2321             {
2322                 std::vector<GLfloat> uniformBuffer(uniformSize);
2323                 for (int index = 0; index < uniformCount; index++, readLoc.value++)
2324                 {
2325                     executable.getUniformfv(context, readLoc,
2326                                             uniformBuffer.data() + index * componentCount);
2327                     resourceTracker->setDefaultUniformBaseLocation(program->id(), readLoc,
2328                                                                    uniformLoc);
2329                 }
2330                 switch (typeInfo.type)
2331                 {
2332                     // Note: All matrix uniforms are populated without transpose
2333                     case GL_FLOAT_MAT4x3:
2334                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2335                         {
2336                             Capture(calls, CaptureUniformMatrix4x3fv(replayState, true, uniformLoc,
2337                                                                      uniformCount, false,
2338                                                                      uniformBuffer.data()));
2339                         }
2340                         break;
2341                     case GL_FLOAT_MAT4x2:
2342                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2343                         {
2344                             Capture(calls, CaptureUniformMatrix4x2fv(replayState, true, uniformLoc,
2345                                                                      uniformCount, false,
2346                                                                      uniformBuffer.data()));
2347                         }
2348                         break;
2349                     case GL_FLOAT_MAT4:
2350                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2351                         {
2352                             Capture(calls, CaptureUniformMatrix4fv(replayState, true, uniformLoc,
2353                                                                    uniformCount, false,
2354                                                                    uniformBuffer.data()));
2355                         }
2356                         break;
2357                     case GL_FLOAT_MAT3x4:
2358                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2359                         {
2360                             Capture(calls, CaptureUniformMatrix3x4fv(replayState, true, uniformLoc,
2361                                                                      uniformCount, false,
2362                                                                      uniformBuffer.data()));
2363                         }
2364                         break;
2365                     case GL_FLOAT_MAT3x2:
2366                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2367                         {
2368                             Capture(calls, CaptureUniformMatrix3x2fv(replayState, true, uniformLoc,
2369                                                                      uniformCount, false,
2370                                                                      uniformBuffer.data()));
2371                         }
2372                         break;
2373                     case GL_FLOAT_MAT3:
2374                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2375                         {
2376                             Capture(calls, CaptureUniformMatrix3fv(replayState, true, uniformLoc,
2377                                                                    uniformCount, false,
2378                                                                    uniformBuffer.data()));
2379                         }
2380                         break;
2381                     case GL_FLOAT_MAT2x4:
2382                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2383                         {
2384                             Capture(calls, CaptureUniformMatrix2x4fv(replayState, true, uniformLoc,
2385                                                                      uniformCount, false,
2386                                                                      uniformBuffer.data()));
2387                         }
2388                         break;
2389                     case GL_FLOAT_MAT2x3:
2390                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2391                         {
2392                             Capture(calls, CaptureUniformMatrix2x3fv(replayState, true, uniformLoc,
2393                                                                      uniformCount, false,
2394                                                                      uniformBuffer.data()));
2395                         }
2396                         break;
2397                     case GL_FLOAT_MAT2:
2398                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2399                         {
2400                             Capture(calls, CaptureUniformMatrix2fv(replayState, true, uniformLoc,
2401                                                                    uniformCount, false,
2402                                                                    uniformBuffer.data()));
2403                         }
2404                         break;
2405                     case GL_FLOAT_VEC4:
2406                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2407                         {
2408                             Capture(calls, CaptureUniform4fv(replayState, true, uniformLoc,
2409                                                              uniformCount, uniformBuffer.data()));
2410                         }
2411                         break;
2412                     case GL_FLOAT_VEC3:
2413                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2414                         {
2415                             Capture(calls, CaptureUniform3fv(replayState, true, uniformLoc,
2416                                                              uniformCount, uniformBuffer.data()));
2417                         }
2418                         break;
2419                     case GL_FLOAT_VEC2:
2420                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2421                         {
2422                             Capture(calls, CaptureUniform2fv(replayState, true, uniformLoc,
2423                                                              uniformCount, uniformBuffer.data()));
2424                         }
2425                         break;
2426                     case GL_FLOAT:
2427                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2428                         {
2429                             Capture(calls, CaptureUniform1fv(replayState, true, uniformLoc,
2430                                                              uniformCount, uniformBuffer.data()));
2431                         }
2432                         break;
2433                     default:
2434                         UNIMPLEMENTED();
2435                         break;
2436                 }
2437                 break;
2438             }
2439             case GL_INT:
2440             {
2441                 std::vector<GLint> uniformBuffer(uniformSize);
2442                 for (int index = 0; index < uniformCount; index++, readLoc.value++)
2443                 {
2444                     executable.getUniformiv(context, readLoc,
2445                                             uniformBuffer.data() + index * componentCount);
2446                     resourceTracker->setDefaultUniformBaseLocation(program->id(), readLoc,
2447                                                                    uniformLoc);
2448                 }
2449                 switch (componentCount)
2450                 {
2451                     case 4:
2452                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2453                         {
2454                             Capture(calls, CaptureUniform4iv(replayState, true, uniformLoc,
2455                                                              uniformCount, uniformBuffer.data()));
2456                         }
2457                         break;
2458                     case 3:
2459                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2460                         {
2461                             Capture(calls, CaptureUniform3iv(replayState, true, uniformLoc,
2462                                                              uniformCount, uniformBuffer.data()));
2463                         }
2464                         break;
2465                     case 2:
2466                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2467                         {
2468                             Capture(calls, CaptureUniform2iv(replayState, true, uniformLoc,
2469                                                              uniformCount, uniformBuffer.data()));
2470                         }
2471                         break;
2472                     case 1:
2473                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2474                         {
2475                             Capture(calls, CaptureUniform1iv(replayState, true, uniformLoc,
2476                                                              uniformCount, uniformBuffer.data()));
2477                         }
2478                         break;
2479                     default:
2480                         UNIMPLEMENTED();
2481                         break;
2482                 }
2483                 break;
2484             }
2485             case GL_BOOL:
2486             case GL_UNSIGNED_INT:
2487             {
2488                 std::vector<GLuint> uniformBuffer(uniformSize);
2489                 for (int index = 0; index < uniformCount; index++, readLoc.value++)
2490                 {
2491                     executable.getUniformuiv(context, readLoc,
2492                                              uniformBuffer.data() + index * componentCount);
2493                     resourceTracker->setDefaultUniformBaseLocation(program->id(), readLoc,
2494                                                                    uniformLoc);
2495                 }
2496                 switch (componentCount)
2497                 {
2498                     case 4:
2499                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2500                         {
2501                             Capture(calls, CaptureUniform4uiv(replayState, true, uniformLoc,
2502                                                               uniformCount, uniformBuffer.data()));
2503                         }
2504                         break;
2505                     case 3:
2506                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2507                         {
2508                             Capture(calls, CaptureUniform3uiv(replayState, true, uniformLoc,
2509                                                               uniformCount, uniformBuffer.data()));
2510                         }
2511                         break;
2512                     case 2:
2513                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2514                         {
2515                             Capture(calls, CaptureUniform2uiv(replayState, true, uniformLoc,
2516                                                               uniformCount, uniformBuffer.data()));
2517                         }
2518                         break;
2519                     case 1:
2520                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2521                         {
2522                             Capture(calls, CaptureUniform1uiv(replayState, true, uniformLoc,
2523                                                               uniformCount, uniformBuffer.data()));
2524                         }
2525                         break;
2526                     default:
2527                         UNIMPLEMENTED();
2528                         break;
2529                 }
2530                 break;
2531             }
2532             default:
2533                 UNIMPLEMENTED();
2534                 break;
2535         }
2536     }
2537 }
2538 
CaptureVertexPointerES1(std::vector<CallCapture> * setupCalls,gl::State * replayState,GLuint attribIndex,const gl::VertexAttribute & attrib,const gl::VertexBinding & binding)2539 void CaptureVertexPointerES1(std::vector<CallCapture> *setupCalls,
2540                              gl::State *replayState,
2541                              GLuint attribIndex,
2542                              const gl::VertexAttribute &attrib,
2543                              const gl::VertexBinding &binding)
2544 {
2545     switch (gl::GLES1Renderer::VertexArrayType(attribIndex))
2546     {
2547         case gl::ClientVertexArrayType::Vertex:
2548             Capture(setupCalls,
2549                     CaptureVertexPointer(*replayState, true, attrib.format->channelCount,
2550                                          attrib.format->vertexAttribType, binding.getStride(),
2551                                          attrib.pointer));
2552             break;
2553         case gl::ClientVertexArrayType::Normal:
2554             Capture(setupCalls,
2555                     CaptureNormalPointer(*replayState, true, attrib.format->vertexAttribType,
2556                                          binding.getStride(), attrib.pointer));
2557             break;
2558         case gl::ClientVertexArrayType::Color:
2559             Capture(setupCalls, CaptureColorPointer(*replayState, true, attrib.format->channelCount,
2560                                                     attrib.format->vertexAttribType,
2561                                                     binding.getStride(), attrib.pointer));
2562             break;
2563         case gl::ClientVertexArrayType::PointSize:
2564             Capture(setupCalls,
2565                     CapturePointSizePointerOES(*replayState, true, attrib.format->vertexAttribType,
2566                                                binding.getStride(), attrib.pointer));
2567             break;
2568         case gl::ClientVertexArrayType::TextureCoord:
2569             Capture(setupCalls,
2570                     CaptureTexCoordPointer(*replayState, true, attrib.format->channelCount,
2571                                            attrib.format->vertexAttribType, binding.getStride(),
2572                                            attrib.pointer));
2573             break;
2574         default:
2575             UNREACHABLE();
2576     }
2577 }
2578 
CaptureTextureEnvironmentState(std::vector<CallCapture> * setupCalls,gl::State * replayState,const gl::State * apiState,unsigned int unit)2579 void CaptureTextureEnvironmentState(std::vector<CallCapture> *setupCalls,
2580                                     gl::State *replayState,
2581                                     const gl::State *apiState,
2582                                     unsigned int unit)
2583 {
2584     const gl::TextureEnvironmentParameters &currentEnv = apiState->gles1().textureEnvironment(unit);
2585     const gl::TextureEnvironmentParameters &defaultEnv =
2586         replayState->gles1().textureEnvironment(unit);
2587 
2588     if (currentEnv == defaultEnv)
2589     {
2590         return;
2591     }
2592 
2593     auto capIfNe = [setupCalls](auto currentState, auto defaultState, CallCapture &&call) {
2594         if (currentState != defaultState)
2595         {
2596             setupCalls->emplace_back(std::move(call));
2597         }
2598     };
2599 
2600     // When the texture env state differs on a non-default sampler unit, emit an ActiveTexture call.
2601     // The default sampler unit is GL_TEXTURE0.
2602     GLenum currentUnit = GL_TEXTURE0 + static_cast<GLenum>(unit);
2603     GLenum defaultUnit = GL_TEXTURE0 + static_cast<GLenum>(replayState->getActiveSampler());
2604     capIfNe(currentUnit, defaultUnit, CaptureActiveTexture(*replayState, true, currentUnit));
2605 
2606     auto capEnum = [capIfNe, replayState](gl::TextureEnvParameter pname, auto currentState,
2607                                           auto defaultState) {
2608         capIfNe(currentState, defaultState,
2609                 CaptureTexEnvi(*replayState, true, gl::TextureEnvTarget::Env, pname,
2610                                ToGLenum(currentState)));
2611     };
2612 
2613     capEnum(gl::TextureEnvParameter::Mode, currentEnv.mode, defaultEnv.mode);
2614 
2615     capEnum(gl::TextureEnvParameter::CombineRgb, currentEnv.combineRgb, defaultEnv.combineRgb);
2616     capEnum(gl::TextureEnvParameter::CombineAlpha, currentEnv.combineAlpha,
2617             defaultEnv.combineAlpha);
2618 
2619     capEnum(gl::TextureEnvParameter::Src0Rgb, currentEnv.src0Rgb, defaultEnv.src0Rgb);
2620     capEnum(gl::TextureEnvParameter::Src1Rgb, currentEnv.src1Rgb, defaultEnv.src1Rgb);
2621     capEnum(gl::TextureEnvParameter::Src2Rgb, currentEnv.src2Rgb, defaultEnv.src2Rgb);
2622 
2623     capEnum(gl::TextureEnvParameter::Src0Alpha, currentEnv.src0Alpha, defaultEnv.src0Alpha);
2624     capEnum(gl::TextureEnvParameter::Src1Alpha, currentEnv.src1Alpha, defaultEnv.src1Alpha);
2625     capEnum(gl::TextureEnvParameter::Src2Alpha, currentEnv.src2Alpha, defaultEnv.src2Alpha);
2626 
2627     capEnum(gl::TextureEnvParameter::Op0Rgb, currentEnv.op0Rgb, defaultEnv.op0Rgb);
2628     capEnum(gl::TextureEnvParameter::Op1Rgb, currentEnv.op1Rgb, defaultEnv.op1Rgb);
2629     capEnum(gl::TextureEnvParameter::Op2Rgb, currentEnv.op2Rgb, defaultEnv.op2Rgb);
2630 
2631     capEnum(gl::TextureEnvParameter::Op0Alpha, currentEnv.op0Alpha, defaultEnv.op0Alpha);
2632     capEnum(gl::TextureEnvParameter::Op1Alpha, currentEnv.op1Alpha, defaultEnv.op1Alpha);
2633     capEnum(gl::TextureEnvParameter::Op2Alpha, currentEnv.op2Alpha, defaultEnv.op2Alpha);
2634 
2635     auto capFloat = [capIfNe, replayState](gl::TextureEnvParameter pname, auto currentState,
2636                                            auto defaultState) {
2637         capIfNe(currentState, defaultState,
2638                 CaptureTexEnvf(*replayState, true, gl::TextureEnvTarget::Env, pname, currentState));
2639     };
2640 
2641     capFloat(gl::TextureEnvParameter::RgbScale, currentEnv.rgbScale, defaultEnv.rgbScale);
2642     capFloat(gl::TextureEnvParameter::AlphaScale, currentEnv.alphaScale, defaultEnv.alphaScale);
2643 
2644     capIfNe(currentEnv.color, defaultEnv.color,
2645             CaptureTexEnvfv(*replayState, true, gl::TextureEnvTarget::Env,
2646                             gl::TextureEnvParameter::Color, currentEnv.color.data()));
2647 
2648     // PointCoordReplace is the only parameter that uses the PointSprite TextureEnvTarget.
2649     capIfNe(currentEnv.pointSpriteCoordReplace, defaultEnv.pointSpriteCoordReplace,
2650             CaptureTexEnvi(*replayState, true, gl::TextureEnvTarget::PointSprite,
2651                            gl::TextureEnvParameter::PointCoordReplace,
2652                            currentEnv.pointSpriteCoordReplace));
2653 
2654     // In case of non-default sampler units, the default unit must be set back here.
2655     capIfNe(currentUnit, defaultUnit, CaptureActiveTexture(*replayState, true, defaultUnit));
2656 }
2657 
VertexBindingMatchesAttribStride(const gl::VertexAttribute & attrib,const gl::VertexBinding & binding)2658 bool VertexBindingMatchesAttribStride(const gl::VertexAttribute &attrib,
2659                                       const gl::VertexBinding &binding)
2660 {
2661     if (attrib.vertexAttribArrayStride == 0 &&
2662         binding.getStride() == ComputeVertexAttributeTypeSize(attrib))
2663     {
2664         return true;
2665     }
2666 
2667     return attrib.vertexAttribArrayStride == binding.getStride();
2668 }
2669 
CaptureVertexArrayState(std::vector<CallCapture> * setupCalls,const gl::Context * context,const gl::VertexArray * vertexArray,gl::State * replayState)2670 void CaptureVertexArrayState(std::vector<CallCapture> *setupCalls,
2671                              const gl::Context *context,
2672                              const gl::VertexArray *vertexArray,
2673                              gl::State *replayState)
2674 {
2675     const std::vector<gl::VertexAttribute> &vertexAttribs = vertexArray->getVertexAttributes();
2676     const std::vector<gl::VertexBinding> &vertexBindings  = vertexArray->getVertexBindings();
2677 
2678     gl::AttributesMask vertexPointerBindings;
2679 
2680     ASSERT(vertexAttribs.size() <= vertexBindings.size());
2681     for (GLuint attribIndex = 0; attribIndex < vertexAttribs.size(); ++attribIndex)
2682     {
2683         const gl::VertexAttribute defaultAttrib(attribIndex);
2684         const gl::VertexBinding defaultBinding;
2685 
2686         const gl::VertexAttribute &attrib = vertexAttribs[attribIndex];
2687         const gl::VertexBinding &binding  = vertexBindings[attrib.bindingIndex];
2688 
2689         if (attrib.enabled != defaultAttrib.enabled)
2690         {
2691             if (context->isGLES1())
2692             {
2693                 Capture(setupCalls,
2694                         CaptureEnableClientState(*replayState, false,
2695                                                  gl::GLES1Renderer::VertexArrayType(attribIndex)));
2696             }
2697             else
2698             {
2699                 Capture(setupCalls,
2700                         CaptureEnableVertexAttribArray(*replayState, false, attribIndex));
2701             }
2702         }
2703 
2704         // Don't capture CaptureVertexAttribPointer calls when a non-default VAO is bound, the array
2705         // buffer is null and a non-null attrib pointer is used.
2706         bool skipInvalidAttrib = vertexArray->id().value != 0 &&
2707                                  binding.getBuffer().get() == nullptr && attrib.pointer != nullptr;
2708 
2709         if (!skipInvalidAttrib &&
2710             (attrib.format != defaultAttrib.format || attrib.pointer != defaultAttrib.pointer ||
2711              binding.getStride() != defaultBinding.getStride() ||
2712              attrib.bindingIndex != defaultAttrib.bindingIndex ||
2713              binding.getBuffer().get() != nullptr))
2714         {
2715             // Each attribute can pull from a separate buffer, so check the binding
2716             gl::Buffer *buffer = binding.getBuffer().get();
2717             if (buffer != replayState->getArrayBuffer())
2718             {
2719                 replayState->setBufferBinding(context, gl::BufferBinding::Array, buffer);
2720 
2721                 gl::BufferID bufferID = {0};
2722                 if (buffer)
2723                 {
2724                     bufferID = buffer->id();
2725                 }
2726                 Capture(setupCalls,
2727                         CaptureBindBuffer(*replayState, true, gl::BufferBinding::Array, bufferID));
2728             }
2729 
2730             // Establish the relationship between currently bound buffer and the VAO
2731             if (context->isGLES1())
2732             {
2733                 // Track indexes that used ES1 calls
2734                 vertexPointerBindings.set(attribIndex);
2735 
2736                 CaptureVertexPointerES1(setupCalls, replayState, attribIndex, attrib, binding);
2737             }
2738             else if (attrib.bindingIndex == attribIndex &&
2739                      VertexBindingMatchesAttribStride(attrib, binding) &&
2740                      (!buffer || binding.getOffset() == reinterpret_cast<GLintptr>(attrib.pointer)))
2741             {
2742                 // Check if we can use strictly ES2 semantics, and track indexes that do.
2743                 vertexPointerBindings.set(attribIndex);
2744 
2745                 if (attrib.format->isPureInt())
2746                 {
2747                     Capture(setupCalls, CaptureVertexAttribIPointer(*replayState, true, attribIndex,
2748                                                                     attrib.format->channelCount,
2749                                                                     attrib.format->vertexAttribType,
2750                                                                     attrib.vertexAttribArrayStride,
2751                                                                     attrib.pointer));
2752                 }
2753                 else
2754                 {
2755                     Capture(setupCalls,
2756                             CaptureVertexAttribPointer(
2757                                 *replayState, true, attribIndex, attrib.format->channelCount,
2758                                 attrib.format->vertexAttribType, attrib.format->isNorm(),
2759                                 attrib.vertexAttribArrayStride, attrib.pointer));
2760                 }
2761 
2762                 if (binding.getDivisor() != 0)
2763                 {
2764                     Capture(setupCalls, CaptureVertexAttribDivisor(*replayState, true, attribIndex,
2765                                                                    binding.getDivisor()));
2766                 }
2767             }
2768             else
2769             {
2770                 ASSERT(context->getClientVersion() >= gl::ES_3_1);
2771 
2772                 if (attrib.format->isPureInt())
2773                 {
2774                     Capture(setupCalls, CaptureVertexAttribIFormat(*replayState, true, attribIndex,
2775                                                                    attrib.format->channelCount,
2776                                                                    attrib.format->vertexAttribType,
2777                                                                    attrib.relativeOffset));
2778                 }
2779                 else
2780                 {
2781                     Capture(setupCalls, CaptureVertexAttribFormat(*replayState, true, attribIndex,
2782                                                                   attrib.format->channelCount,
2783                                                                   attrib.format->vertexAttribType,
2784                                                                   attrib.format->isNorm(),
2785                                                                   attrib.relativeOffset));
2786                 }
2787 
2788                 Capture(setupCalls, CaptureVertexAttribBinding(*replayState, true, attribIndex,
2789                                                                attrib.bindingIndex));
2790             }
2791         }
2792     }
2793 
2794     // The loop below expects attribs and bindings to have equal counts
2795     static_assert(gl::MAX_VERTEX_ATTRIBS == gl::MAX_VERTEX_ATTRIB_BINDINGS,
2796                   "Max vertex attribs and bindings count mismatch");
2797 
2798     // Loop through binding indices that weren't used by VertexAttribPointer
2799     for (size_t bindingIndex : vertexPointerBindings.flip())
2800     {
2801         const gl::VertexBinding &binding = vertexBindings[bindingIndex];
2802 
2803         if (binding.getBuffer().id().value != 0)
2804         {
2805             Capture(setupCalls,
2806                     CaptureBindVertexBuffer(*replayState, true, static_cast<GLuint>(bindingIndex),
2807                                             binding.getBuffer().id(), binding.getOffset(),
2808                                             binding.getStride()));
2809         }
2810 
2811         if (binding.getDivisor() != 0)
2812         {
2813             Capture(setupCalls, CaptureVertexBindingDivisor(*replayState, true,
2814                                                             static_cast<GLuint>(bindingIndex),
2815                                                             binding.getDivisor()));
2816         }
2817     }
2818 
2819     // The element array buffer is not per attribute, but per VAO
2820     gl::Buffer *elementArrayBuffer = vertexArray->getElementArrayBuffer();
2821     if (elementArrayBuffer)
2822     {
2823         Capture(setupCalls, CaptureBindBuffer(*replayState, true, gl::BufferBinding::ElementArray,
2824                                               elementArrayBuffer->id()));
2825     }
2826 }
2827 
CaptureTextureStorage(std::vector<CallCapture> * setupCalls,gl::State * replayState,const gl::Texture * texture)2828 void CaptureTextureStorage(std::vector<CallCapture> *setupCalls,
2829                            gl::State *replayState,
2830                            const gl::Texture *texture)
2831 {
2832     // Use mip-level 0 for the base dimensions
2833     gl::ImageIndex imageIndex = gl::ImageIndex::MakeFromType(texture->getType(), 0);
2834     const gl::ImageDesc &desc = texture->getTextureState().getImageDesc(imageIndex);
2835 
2836     switch (texture->getType())
2837     {
2838         case gl::TextureType::_2D:
2839         case gl::TextureType::CubeMap:
2840         {
2841             Capture(setupCalls, CaptureTexStorage2D(*replayState, true, texture->getType(),
2842                                                     texture->getImmutableLevels(),
2843                                                     desc.format.info->internalFormat,
2844                                                     desc.size.width, desc.size.height));
2845             break;
2846         }
2847         case gl::TextureType::_3D:
2848         case gl::TextureType::_2DArray:
2849         case gl::TextureType::CubeMapArray:
2850         {
2851             Capture(setupCalls, CaptureTexStorage3D(
2852                                     *replayState, true, texture->getType(),
2853                                     texture->getImmutableLevels(), desc.format.info->internalFormat,
2854                                     desc.size.width, desc.size.height, desc.size.depth));
2855             break;
2856         }
2857         case gl::TextureType::Buffer:
2858         {
2859             // Do nothing. This will already be captured as a buffer.
2860             break;
2861         }
2862         default:
2863             UNIMPLEMENTED();
2864             break;
2865     }
2866 }
2867 
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)2868 void CaptureTextureContents(std::vector<CallCapture> *setupCalls,
2869                             gl::State *replayState,
2870                             const gl::Texture *texture,
2871                             const gl::ImageIndex &index,
2872                             const gl::ImageDesc &desc,
2873                             GLuint size,
2874                             const void *data)
2875 {
2876     const gl::InternalFormat &format = *desc.format.info;
2877 
2878     if (index.getType() == gl::TextureType::Buffer)
2879     {
2880         // Zero binding size indicates full buffer bound
2881         if (texture->getBuffer().getSize() == 0)
2882         {
2883             Capture(setupCalls,
2884                     CaptureTexBufferEXT(*replayState, true, index.getType(), format.internalFormat,
2885                                         texture->getBuffer().get()->id()));
2886         }
2887         else
2888         {
2889             Capture(setupCalls, CaptureTexBufferRangeEXT(*replayState, true, index.getType(),
2890                                                          format.internalFormat,
2891                                                          texture->getBuffer().get()->id(),
2892                                                          texture->getBuffer().getOffset(),
2893                                                          texture->getBuffer().getSize()));
2894         }
2895 
2896         // For buffers, we're done
2897         return;
2898     }
2899 
2900     bool is3D =
2901         (index.getType() == gl::TextureType::_3D || index.getType() == gl::TextureType::_2DArray ||
2902          index.getType() == gl::TextureType::CubeMapArray);
2903 
2904     if (format.compressed || format.paletted)
2905     {
2906         if (is3D)
2907         {
2908             if (texture->getImmutableFormat())
2909             {
2910                 Capture(setupCalls,
2911                         CaptureCompressedTexSubImage3D(
2912                             *replayState, true, index.getTarget(), index.getLevelIndex(), 0, 0, 0,
2913                             desc.size.width, desc.size.height, desc.size.depth,
2914                             format.internalFormat, size, data));
2915             }
2916             else
2917             {
2918                 Capture(setupCalls,
2919                         CaptureCompressedTexImage3D(*replayState, true, index.getTarget(),
2920                                                     index.getLevelIndex(), format.internalFormat,
2921                                                     desc.size.width, desc.size.height,
2922                                                     desc.size.depth, 0, size, data));
2923             }
2924         }
2925         else
2926         {
2927             if (texture->getImmutableFormat())
2928             {
2929                 Capture(setupCalls,
2930                         CaptureCompressedTexSubImage2D(
2931                             *replayState, true, index.getTarget(), index.getLevelIndex(), 0, 0,
2932                             desc.size.width, desc.size.height, format.internalFormat, size, data));
2933             }
2934             else
2935             {
2936                 Capture(setupCalls, CaptureCompressedTexImage2D(
2937                                         *replayState, true, index.getTarget(),
2938                                         index.getLevelIndex(), format.internalFormat,
2939                                         desc.size.width, desc.size.height, 0, size, data));
2940             }
2941         }
2942     }
2943     else
2944     {
2945         if (is3D)
2946         {
2947             if (texture->getImmutableFormat())
2948             {
2949                 Capture(setupCalls,
2950                         CaptureTexSubImage3D(*replayState, true, index.getTarget(),
2951                                              index.getLevelIndex(), 0, 0, 0, desc.size.width,
2952                                              desc.size.height, desc.size.depth, format.format,
2953                                              format.type, data));
2954             }
2955             else
2956             {
2957                 Capture(
2958                     setupCalls,
2959                     CaptureTexImage3D(*replayState, true, index.getTarget(), index.getLevelIndex(),
2960                                       format.internalFormat, desc.size.width, desc.size.height,
2961                                       desc.size.depth, 0, format.format, format.type, data));
2962             }
2963         }
2964         else
2965         {
2966             if (texture->getImmutableFormat())
2967             {
2968                 Capture(setupCalls,
2969                         CaptureTexSubImage2D(*replayState, true, index.getTarget(),
2970                                              index.getLevelIndex(), 0, 0, desc.size.width,
2971                                              desc.size.height, format.format, format.type, data));
2972             }
2973             else
2974             {
2975                 Capture(setupCalls, CaptureTexImage2D(*replayState, true, index.getTarget(),
2976                                                       index.getLevelIndex(), format.internalFormat,
2977                                                       desc.size.width, desc.size.height, 0,
2978                                                       format.format, format.type, data));
2979             }
2980         }
2981     }
2982 }
2983 
CaptureCustomUniformBlockBinding(const CallCapture & callIn,std::vector<CallCapture> & callsOut)2984 void CaptureCustomUniformBlockBinding(const CallCapture &callIn, std::vector<CallCapture> &callsOut)
2985 {
2986     const ParamBuffer &paramsIn = callIn.params;
2987 
2988     const ParamCapture &programID =
2989         paramsIn.getParam("programPacked", ParamType::TShaderProgramID, 0);
2990     const ParamCapture &blockIndex =
2991         paramsIn.getParam("uniformBlockIndexPacked", ParamType::TUniformBlockIndex, 1);
2992     const ParamCapture &blockBinding =
2993         paramsIn.getParam("uniformBlockBinding", ParamType::TGLuint, 2);
2994 
2995     ParamBuffer params;
2996     params.addValueParam("program", ParamType::TGLuint, programID.value.ShaderProgramIDVal.value);
2997     params.addValueParam("uniformBlockIndex", ParamType::TGLuint,
2998                          blockIndex.value.UniformBlockIndexVal.value);
2999     params.addValueParam("uniformBlockBinding", ParamType::TGLuint, blockBinding.value.GLuintVal);
3000 
3001     callsOut.emplace_back("UniformBlockBinding", std::move(params));
3002 }
3003 
CaptureCustomMapBuffer(const char * entryPointName,CallCapture & call,std::vector<CallCapture> & callsOut,gl::BufferID mappedBufferID)3004 void CaptureCustomMapBuffer(const char *entryPointName,
3005                             CallCapture &call,
3006                             std::vector<CallCapture> &callsOut,
3007                             gl::BufferID mappedBufferID)
3008 {
3009     call.params.addValueParam("buffer", ParamType::TGLuint, mappedBufferID.value);
3010     callsOut.emplace_back(entryPointName, std::move(call.params));
3011 }
3012 
CaptureCustomShaderProgram(const char * name,CallCapture & call,std::vector<CallCapture> & callsOut)3013 void CaptureCustomShaderProgram(const char *name,
3014                                 CallCapture &call,
3015                                 std::vector<CallCapture> &callsOut)
3016 {
3017     call.params.addValueParam("shaderProgram", ParamType::TGLuint,
3018                               call.params.getReturnValue().value.GLuintVal);
3019     call.customFunctionName = name;
3020     callsOut.emplace_back(std::move(call));
3021 }
3022 
CaptureCustomFenceSync(CallCapture & call,std::vector<CallCapture> & callsOut)3023 void CaptureCustomFenceSync(CallCapture &call, std::vector<CallCapture> &callsOut)
3024 {
3025     ParamBuffer &&params = std::move(call.params);
3026     params.addValueParam("fenceSync", ParamType::TGLuint64,
3027                          params.getReturnValue().value.GLuint64Val);
3028     call.customFunctionName = "FenceSync2";
3029     call.isSyncPoint        = true;
3030     callsOut.emplace_back(std::move(call));
3031 }
3032 
GetImageFromParam(const gl::Context * context,const ParamCapture & param)3033 const egl::Image *GetImageFromParam(const gl::Context *context, const ParamCapture &param)
3034 {
3035     const egl::ImageID eglImageID = egl::PackParam<egl::ImageID>(param.value.EGLImageVal);
3036     const egl::Image *eglImage    = context->getDisplay()->getImage(eglImageID);
3037     ASSERT(eglImage != nullptr);
3038     return eglImage;
3039 }
3040 
CaptureCustomCreateEGLImage(const gl::Context * context,const char * name,size_t width,size_t height,CallCapture & call,std::vector<CallCapture> & callsOut)3041 void CaptureCustomCreateEGLImage(const gl::Context *context,
3042                                  const char *name,
3043                                  size_t width,
3044                                  size_t height,
3045                                  CallCapture &call,
3046                                  std::vector<CallCapture> &callsOut)
3047 {
3048     ParamBuffer &&params    = std::move(call.params);
3049     EGLImage returnVal      = params.getReturnValue().value.EGLImageVal;
3050     egl::ImageID imageID    = egl::PackParam<egl::ImageID>(returnVal);
3051     call.customFunctionName = name;
3052 
3053     // Clear client buffer value if it is a pointer to a hardware buffer. It is
3054     // not used by replay and will not be portable to 32-bit builds
3055     if (params.getParam("target", ParamType::TEGLenum, 2).value.EGLenumVal ==
3056         EGL_NATIVE_BUFFER_ANDROID)
3057     {
3058         params.setValueParamAtIndex("buffer", ParamType::TEGLClientBuffer,
3059                                     reinterpret_cast<EGLClientBuffer>(static_cast<uintptr_t>(0)),
3060                                     3);
3061     }
3062 
3063     // Record image dimensions in case a backing resource needs to be created during replay
3064     params.addValueParam("width", ParamType::TGLsizei, static_cast<GLsizei>(width));
3065     params.addValueParam("height", ParamType::TGLsizei, static_cast<GLsizei>(height));
3066 
3067     params.addValueParam("image", ParamType::TGLuint, imageID.value);
3068     callsOut.emplace_back(std::move(call));
3069 }
3070 
CaptureCustomDestroyEGLImage(const char * name,CallCapture & call,std::vector<CallCapture> & callsOut)3071 void CaptureCustomDestroyEGLImage(const char *name,
3072                                   CallCapture &call,
3073                                   std::vector<CallCapture> &callsOut)
3074 {
3075     call.customFunctionName = name;
3076     ParamBuffer &&params    = std::move(call.params);
3077 
3078     const ParamCapture &imageID = params.getParam("imagePacked", ParamType::TImageID, 1);
3079     params.addValueParam("imageID", ParamType::TGLuint, imageID.value.ImageIDVal.value);
3080 
3081     callsOut.emplace_back(std::move(call));
3082 }
3083 
CaptureCustomCreateEGLSync(const char * name,CallCapture & call,std::vector<CallCapture> & callsOut)3084 void CaptureCustomCreateEGLSync(const char *name,
3085                                 CallCapture &call,
3086                                 std::vector<CallCapture> &callsOut)
3087 {
3088     ParamBuffer &&params = std::move(call.params);
3089     EGLSync returnVal    = params.getReturnValue().value.EGLSyncVal;
3090     egl::SyncID syncID   = egl::PackParam<egl::SyncID>(returnVal);
3091     params.addValueParam("sync", ParamType::TGLuint, syncID.value);
3092     call.customFunctionName = name;
3093     callsOut.emplace_back(std::move(call));
3094 }
3095 
CaptureCustomCreatePbufferSurface(CallCapture & call,std::vector<CallCapture> & callsOut)3096 void CaptureCustomCreatePbufferSurface(CallCapture &call, std::vector<CallCapture> &callsOut)
3097 {
3098     ParamBuffer &&params     = std::move(call.params);
3099     EGLSurface returnVal     = params.getReturnValue().value.EGLSurfaceVal;
3100     egl::SurfaceID surfaceID = egl::PackParam<egl::SurfaceID>(returnVal);
3101 
3102     params.addValueParam("surface", ParamType::TGLuint, surfaceID.value);
3103     call.customFunctionName = "CreatePbufferSurface";
3104     callsOut.emplace_back(std::move(call));
3105 }
3106 
CaptureCustomCreateNativeClientbuffer(CallCapture & call,std::vector<CallCapture> & callsOut)3107 void CaptureCustomCreateNativeClientbuffer(CallCapture &call, std::vector<CallCapture> &callsOut)
3108 {
3109     ParamBuffer &&params = std::move(call.params);
3110     params.addValueParam("clientBuffer", ParamType::TEGLClientBuffer,
3111                          params.getReturnValue().value.EGLClientBufferVal);
3112     call.customFunctionName = "CreateNativeClientBufferANDROID";
3113     callsOut.emplace_back(std::move(call));
3114 }
3115 
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)3116 void GenerateLinkedProgram(const gl::Context *context,
3117                            const gl::State &replayState,
3118                            ResourceTracker *resourceTracker,
3119                            std::vector<CallCapture> *setupCalls,
3120                            gl::Program *program,
3121                            gl::ShaderProgramID id,
3122                            gl::ShaderProgramID tempIDStart,
3123                            const ProgramSources &linkedSources)
3124 {
3125     // A map to store the gShaderProgram map lookup index of the temp shaders we attached below. We
3126     // need this map to retrieve the lookup index to pass to CaptureDetachShader calls at the end of
3127     // GenerateLinkedProgram.
3128     PackedEnumMap<gl::ShaderType, gl::ShaderProgramID> tempShaderIDTracker;
3129 
3130     const gl::ProgramExecutable &executable = program->getExecutable();
3131 
3132     // Compile with last linked sources.
3133     for (gl::ShaderType shaderType : executable.getLinkedShaderStages())
3134     {
3135         // Bump the max shader program id for each new tempIDStart we use to create, compile, and
3136         // attach the temp shader object.
3137         resourceTracker->onShaderProgramAccess(tempIDStart);
3138         // Store the tempIDStart in the tempShaderIDTracker to retrieve for CaptureDetachShader
3139         // calls later.
3140         tempShaderIDTracker[shaderType] = tempIDStart;
3141         const std::string &sourceString = linkedSources[shaderType];
3142         const char *sourcePointer       = sourceString.c_str();
3143 
3144         if (sourceString.empty())
3145         {
3146             // If we don't have source for this shader, that means it was populated by the app
3147             // using glProgramBinary.  We need to look it up from our cached copy.
3148             const ProgramSources &cachedLinkedSources =
3149                 context->getShareGroup()->getFrameCaptureShared()->getProgramSources(id);
3150 
3151             const std::string &cachedSourceString = cachedLinkedSources[shaderType];
3152             sourcePointer                         = cachedSourceString.c_str();
3153             ASSERT(!cachedSourceString.empty());
3154         }
3155 
3156         // Compile and attach the temporary shader. Then free it immediately.
3157         CallCapture createShader =
3158             CaptureCreateShader(replayState, true, shaderType, tempIDStart.value);
3159         CaptureCustomShaderProgram("CreateShader", createShader, *setupCalls);
3160         Capture(setupCalls,
3161                 CaptureShaderSource(replayState, true, tempIDStart, 1, &sourcePointer, nullptr));
3162         Capture(setupCalls, CaptureCompileShader(replayState, true, tempIDStart));
3163         Capture(setupCalls, CaptureAttachShader(replayState, true, id, tempIDStart));
3164         // Increment tempIDStart to get a new gShaderProgram map index for the next linked stage
3165         // shader object. We can't reuse the same tempIDStart as we need to retrieve the index of
3166         // each attached shader object later to pass to CaptureDetachShader calls.
3167         tempIDStart.value += 1;
3168     }
3169 
3170     // Gather XFB varyings
3171     std::vector<std::string> xfbVaryings;
3172     for (const gl::TransformFeedbackVarying &xfbVarying :
3173          executable.getLinkedTransformFeedbackVaryings())
3174     {
3175         xfbVaryings.push_back(xfbVarying.nameWithArrayIndex());
3176     }
3177 
3178     if (!xfbVaryings.empty())
3179     {
3180         std::vector<const char *> varyingsStrings;
3181         for (const std::string &varyingString : xfbVaryings)
3182         {
3183             varyingsStrings.push_back(varyingString.data());
3184         }
3185 
3186         GLenum xfbMode = executable.getTransformFeedbackBufferMode();
3187         Capture(setupCalls, CaptureTransformFeedbackVaryings(replayState, true, id,
3188                                                              static_cast<GLint>(xfbVaryings.size()),
3189                                                              varyingsStrings.data(), xfbMode));
3190     }
3191 
3192     // Force the attributes to be bound the same way as in the existing program.
3193     // This can affect attributes that are optimized out in some implementations.
3194     for (const gl::ProgramInput &attrib : executable.getProgramInputs())
3195     {
3196         if (gl::IsBuiltInName(attrib.name))
3197         {
3198             // Don't try to bind built-in attributes
3199             continue;
3200         }
3201 
3202         // Separable programs may not have a VS, meaning it may not have attributes.
3203         if (executable.hasLinkedShaderStage(gl::ShaderType::Vertex))
3204         {
3205             ASSERT(attrib.getLocation() != -1);
3206             Capture(setupCalls, CaptureBindAttribLocation(replayState, true, id,
3207                                                           static_cast<GLuint>(attrib.getLocation()),
3208                                                           attrib.name.c_str()));
3209         }
3210     }
3211 
3212     if (program->isSeparable())
3213     {
3214         // MEC manually recreates separable programs, rather than attempting to recreate a call
3215         // to glCreateShaderProgramv(), so insert a call to mark it separable.
3216         Capture(setupCalls,
3217                 CaptureProgramParameteri(replayState, true, id, GL_PROGRAM_SEPARABLE, GL_TRUE));
3218     }
3219 
3220     Capture(setupCalls, CaptureLinkProgram(replayState, true, id));
3221     CaptureUpdateUniformLocations(program, setupCalls);
3222     CaptureUpdateUniformValues(replayState, context, program, resourceTracker, setupCalls);
3223     CaptureUpdateUniformBlockIndexes(program, setupCalls);
3224 
3225     // Capture uniform block bindings for each program
3226     for (uint32_t uniformBlockIndex = 0;
3227          uniformBlockIndex < static_cast<uint32_t>(executable.getUniformBlocks().size());
3228          uniformBlockIndex++)
3229     {
3230         GLuint blockBinding = executable.getUniformBlocks()[uniformBlockIndex].pod.inShaderBinding;
3231         CallCapture updateCallCapture =
3232             CaptureUniformBlockBinding(replayState, true, id, {uniformBlockIndex}, blockBinding);
3233         CaptureCustomUniformBlockBinding(updateCallCapture, *setupCalls);
3234     }
3235 
3236     // Add DetachShader call if that's what the app does, so that the
3237     // ResourceManagerBase::mHandleAllocator can release the ShaderProgramID handle assigned to the
3238     // shader object when glDeleteShader is called. This ensures the ShaderProgramID handles used in
3239     // SetupReplayContextShared() are consistent with the ShaderProgramID handles used by the app.
3240     for (gl::ShaderType shaderType : executable.getLinkedShaderStages())
3241     {
3242         gl::Shader *attachedShader = program->getAttachedShader(shaderType);
3243         if (attachedShader == nullptr)
3244         {
3245             Capture(setupCalls,
3246                     CaptureDetachShader(replayState, true, id, tempShaderIDTracker[shaderType]));
3247         }
3248         Capture(setupCalls,
3249                 CaptureDeleteShader(replayState, true, tempShaderIDTracker[shaderType]));
3250     }
3251 }
3252 
3253 // TODO(http://anglebug.com/42263204): Improve reset/restore call generation
3254 // There are multiple ways to track reset calls for individual resources. For now, we are tracking
3255 // separate lists of instructions that mirror the calls created during mid-execution setup. Other
3256 // methods could involve passing the original CallCaptures to this function, or tracking the
3257 // indices of original setup calls.
CaptureBufferResetCalls(const gl::Context * context,const gl::State & replayState,ResourceTracker * resourceTracker,gl::BufferID * id,const gl::Buffer * buffer)3258 void CaptureBufferResetCalls(const gl::Context *context,
3259                              const gl::State &replayState,
3260                              ResourceTracker *resourceTracker,
3261                              gl::BufferID *id,
3262                              const gl::Buffer *buffer)
3263 {
3264     GLuint bufferID = (*id).value;
3265 
3266     // Track this as a starting resource that may need to be restored.
3267     TrackedResource &trackedBuffers =
3268         resourceTracker->getTrackedResource(context->id(), ResourceIDType::Buffer);
3269 
3270     // Track calls to regenerate a given buffer
3271     ResourceCalls &bufferRegenCalls = trackedBuffers.getResourceRegenCalls();
3272     Capture(&bufferRegenCalls[bufferID], CaptureGenBuffers(replayState, true, 1, id));
3273     MaybeCaptureUpdateResourceIDs(context, resourceTracker, &bufferRegenCalls[bufferID]);
3274 
3275     // Call glBufferStorageEXT when regenerating immutable buffers,
3276     // as we can't call glBufferData on restore.
3277     if (buffer->isImmutable())
3278     {
3279         Capture(&bufferRegenCalls[bufferID],
3280                 CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, *id));
3281         Capture(
3282             &bufferRegenCalls[bufferID],
3283             CaptureBufferStorageEXT(replayState, true, gl::BufferBinding::Array,
3284                                     static_cast<GLsizeiptr>(buffer->getSize()),
3285                                     buffer->getMapPointer(), buffer->getStorageExtUsageFlags()));
3286     }
3287 
3288     // Track calls to restore a given buffer's contents
3289     ResourceCalls &bufferRestoreCalls = trackedBuffers.getResourceRestoreCalls();
3290     Capture(&bufferRestoreCalls[bufferID],
3291             CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, *id));
3292 
3293     // Mutable buffers will be restored here using glBufferData.
3294     // Immutable buffers need to be restored below, after maping.
3295     if (!buffer->isImmutable())
3296     {
3297         Capture(&bufferRestoreCalls[bufferID],
3298                 CaptureBufferData(replayState, true, gl::BufferBinding::Array,
3299                                   static_cast<GLsizeiptr>(buffer->getSize()),
3300                                   buffer->getMapPointer(), buffer->getUsage()));
3301     }
3302 
3303     if (buffer->isMapped())
3304     {
3305         // Track calls to remap a buffer that started as mapped
3306         BufferCalls &bufferMapCalls = resourceTracker->getBufferMapCalls();
3307 
3308         Capture(&bufferMapCalls[bufferID],
3309                 CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, *id));
3310 
3311         void *dontCare             = nullptr;
3312         CallCapture mapBufferRange = CaptureMapBufferRange(
3313             replayState, true, gl::BufferBinding::Array,
3314             static_cast<GLsizeiptr>(buffer->getMapOffset()),
3315             static_cast<GLsizeiptr>(buffer->getMapLength()), buffer->getAccessFlags(), dontCare);
3316         CaptureCustomMapBuffer("MapBufferRange", mapBufferRange, bufferMapCalls[bufferID],
3317                                buffer->id());
3318 
3319         // Restore immutable mapped buffers. Needs to happen after mapping.
3320         if (buffer->isImmutable())
3321         {
3322             ParamBuffer dataParamBuffer;
3323             dataParamBuffer.addValueParam("dest", ParamType::TGLuint, buffer->id().value);
3324             ParamCapture captureData("source", ParamType::TvoidConstPointer);
3325             CaptureMemory(buffer->getMapPointer(), static_cast<GLsizeiptr>(buffer->getSize()),
3326                           &captureData);
3327             dataParamBuffer.addParam(std::move(captureData));
3328             dataParamBuffer.addValueParam<GLsizeiptr>("size", ParamType::TGLsizeiptr,
3329                                                       static_cast<GLsizeiptr>(buffer->getSize()));
3330             bufferMapCalls[bufferID].emplace_back("UpdateClientBufferData",
3331                                                   std::move(dataParamBuffer));
3332         }
3333     }
3334 
3335     // Track calls unmap a buffer that started as unmapped
3336     BufferCalls &bufferUnmapCalls = resourceTracker->getBufferUnmapCalls();
3337     Capture(&bufferUnmapCalls[bufferID],
3338             CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, *id));
3339     Capture(&bufferUnmapCalls[bufferID],
3340             CaptureUnmapBuffer(replayState, true, gl::BufferBinding::Array, GL_TRUE));
3341 }
3342 
CaptureFenceSyncResetCalls(const gl::Context * context,const gl::State & replayState,ResourceTracker * resourceTracker,gl::SyncID syncID,GLsync syncObject,const gl::Sync * sync)3343 void CaptureFenceSyncResetCalls(const gl::Context *context,
3344                                 const gl::State &replayState,
3345                                 ResourceTracker *resourceTracker,
3346                                 gl::SyncID syncID,
3347                                 GLsync syncObject,
3348                                 const gl::Sync *sync)
3349 {
3350     // Track calls to regenerate a given fence sync
3351     FenceSyncCalls &fenceSyncRegenCalls = resourceTracker->getFenceSyncRegenCalls();
3352     CallCapture fenceSync =
3353         CaptureFenceSync(replayState, true, sync->getCondition(), sync->getFlags(), syncObject);
3354     CaptureCustomFenceSync(fenceSync, fenceSyncRegenCalls[syncID]);
3355     MaybeCaptureUpdateResourceIDs(context, resourceTracker, &fenceSyncRegenCalls[syncID]);
3356 }
3357 
CaptureEGLSyncResetCalls(const gl::Context * context,const gl::State & replayState,ResourceTracker * resourceTracker,egl::SyncID eglSyncID,EGLSync eglSyncObject,const egl::Sync * eglSync)3358 void CaptureEGLSyncResetCalls(const gl::Context *context,
3359                               const gl::State &replayState,
3360                               ResourceTracker *resourceTracker,
3361                               egl::SyncID eglSyncID,
3362                               EGLSync eglSyncObject,
3363                               const egl::Sync *eglSync)
3364 {
3365     // Track this as a starting resource that may need to be restored.
3366     TrackedResource &trackedEGLSyncs =
3367         resourceTracker->getTrackedResource(context->id(), ResourceIDType::egl_Sync);
3368 
3369     // Track calls to regenerate a given buffer
3370     ResourceCalls &eglSyncRegenCalls = trackedEGLSyncs.getResourceRegenCalls();
3371 
3372     CallCapture createEGLSync =
3373         CaptureCreateSyncKHR(nullptr, true, context->getDisplay(), eglSync->getType(),
3374                              eglSync->getAttributeMap(), eglSyncObject);
3375     CaptureCustomCreateEGLSync("CreateEGLSyncKHR", createEGLSync,
3376                                eglSyncRegenCalls[eglSyncID.value]);
3377     MaybeCaptureUpdateResourceIDs(context, resourceTracker, &eglSyncRegenCalls[eglSyncID.value]);
3378 }
3379 
CaptureBufferBindingResetCalls(const gl::State & replayState,ResourceTracker * resourceTracker,gl::BufferBinding binding,gl::BufferID id)3380 void CaptureBufferBindingResetCalls(const gl::State &replayState,
3381                                     ResourceTracker *resourceTracker,
3382                                     gl::BufferBinding binding,
3383                                     gl::BufferID id)
3384 {
3385     // Track the calls to reset it
3386     std::vector<CallCapture> &bufferBindingCalls = resourceTracker->getBufferBindingCalls();
3387     Capture(&bufferBindingCalls, CaptureBindBuffer(replayState, true, binding, id));
3388 }
3389 
CaptureIndexedBuffers(const gl::State & glState,const gl::BufferVector & indexedBuffers,gl::BufferBinding binding,std::vector<CallCapture> * setupCalls)3390 void CaptureIndexedBuffers(const gl::State &glState,
3391                            const gl::BufferVector &indexedBuffers,
3392                            gl::BufferBinding binding,
3393                            std::vector<CallCapture> *setupCalls)
3394 {
3395     for (unsigned int index = 0; index < indexedBuffers.size(); ++index)
3396     {
3397         const gl::OffsetBindingPointer<gl::Buffer> &buffer = indexedBuffers[index];
3398 
3399         if (buffer.get() == nullptr)
3400         {
3401             continue;
3402         }
3403 
3404         GLintptr offset       = buffer.getOffset();
3405         GLsizeiptr size       = buffer.getSize();
3406         gl::BufferID bufferID = buffer.get()->id();
3407 
3408         // Context::bindBufferBase() calls Context::bindBufferRange() with size and offset = 0.
3409         if ((offset == 0) && (size == 0))
3410         {
3411             Capture(setupCalls, CaptureBindBufferBase(glState, true, binding, index, bufferID));
3412         }
3413         else
3414         {
3415             Capture(setupCalls,
3416                     CaptureBindBufferRange(glState, true, binding, index, bufferID, offset, size));
3417         }
3418     }
3419 }
3420 
CaptureDefaultVertexAttribs(const gl::State & replayState,const gl::State & apiState,std::vector<CallCapture> * setupCalls)3421 void CaptureDefaultVertexAttribs(const gl::State &replayState,
3422                                  const gl::State &apiState,
3423                                  std::vector<CallCapture> *setupCalls)
3424 {
3425     const std::vector<gl::VertexAttribCurrentValueData> &currentValues =
3426         apiState.getVertexAttribCurrentValues();
3427 
3428     for (GLuint attribIndex = 0; attribIndex < currentValues.size(); ++attribIndex)
3429     {
3430         const gl::VertexAttribCurrentValueData &defaultValue = currentValues[attribIndex];
3431         if (!IsDefaultCurrentValue(defaultValue))
3432         {
3433             Capture(setupCalls, CaptureVertexAttrib4fv(replayState, true, attribIndex,
3434                                                        defaultValue.Values.FloatValues));
3435         }
3436     }
3437 }
3438 
CaptureBindFramebufferForContext(const gl::Context * context,std::vector<CallCapture> * calls,FramebufferCaptureFuncs & framebufferFuncs,const gl::State & glState,GLenum target,const gl::FramebufferID & id)3439 void CaptureBindFramebufferForContext(const gl::Context *context,
3440                                       std::vector<CallCapture> *calls,
3441                                       FramebufferCaptureFuncs &framebufferFuncs,
3442                                       const gl::State &glState,
3443                                       GLenum target,
3444                                       const gl::FramebufferID &id)
3445 {
3446     Capture(calls, framebufferFuncs.bindFramebuffer(glState, true, target, id));
3447 
3448     // Set current context for this CallCapture since we track these in gFramebufferMapPerContext
3449     calls->back().contextID = context->id();
3450 }
3451 
CompressPalettedTexture(angle::MemoryBuffer & data,angle::MemoryBuffer & tmp,const gl::InternalFormat & compressedFormat,const gl::Extents & extents)3452 void CompressPalettedTexture(angle::MemoryBuffer &data,
3453                              angle::MemoryBuffer &tmp,
3454                              const gl::InternalFormat &compressedFormat,
3455                              const gl::Extents &extents)
3456 {
3457     constexpr int uncompressedChannelCount = 4;
3458 
3459     uint32_t indexBits = 0, redBlueBits = 0, greenBits = 0, alphaBits = 0;
3460     switch (compressedFormat.internalFormat)
3461     {
3462         case GL_PALETTE4_RGB8_OES:
3463             indexBits   = 4;
3464             redBlueBits = 8;
3465             greenBits   = 8;
3466             alphaBits   = 0;
3467             break;
3468         case GL_PALETTE4_RGBA8_OES:
3469             indexBits   = 4;
3470             redBlueBits = 8;
3471             greenBits   = 8;
3472             alphaBits   = 8;
3473             break;
3474         case GL_PALETTE4_R5_G6_B5_OES:
3475             indexBits   = 4;
3476             redBlueBits = 5;
3477             greenBits   = 6;
3478             alphaBits   = 0;
3479             break;
3480         case GL_PALETTE4_RGBA4_OES:
3481             indexBits   = 4;
3482             redBlueBits = 4;
3483             greenBits   = 4;
3484             alphaBits   = 4;
3485             break;
3486         case GL_PALETTE4_RGB5_A1_OES:
3487             indexBits   = 4;
3488             redBlueBits = 5;
3489             greenBits   = 5;
3490             alphaBits   = 1;
3491             break;
3492         case GL_PALETTE8_RGB8_OES:
3493             indexBits   = 8;
3494             redBlueBits = 8;
3495             greenBits   = 8;
3496             alphaBits   = 0;
3497             break;
3498         case GL_PALETTE8_RGBA8_OES:
3499             indexBits   = 8;
3500             redBlueBits = 8;
3501             greenBits   = 8;
3502             alphaBits   = 8;
3503             break;
3504         case GL_PALETTE8_R5_G6_B5_OES:
3505             indexBits   = 8;
3506             redBlueBits = 5;
3507             greenBits   = 6;
3508             alphaBits   = 0;
3509             break;
3510         case GL_PALETTE8_RGBA4_OES:
3511             indexBits   = 8;
3512             redBlueBits = 4;
3513             greenBits   = 4;
3514             alphaBits   = 4;
3515             break;
3516         case GL_PALETTE8_RGB5_A1_OES:
3517             indexBits   = 8;
3518             redBlueBits = 5;
3519             greenBits   = 5;
3520             alphaBits   = 1;
3521             break;
3522 
3523         default:
3524             UNREACHABLE();
3525             break;
3526     }
3527 
3528     bool result = data.resize(
3529         // Palette size
3530         (1 << indexBits) * (2 * redBlueBits + greenBits + alphaBits) / 8 +
3531         // Texels size
3532         indexBits * extents.width * extents.height * extents.depth / 8);
3533     ASSERT(result);
3534 
3535     angle::StoreRGBA8ToPalettedImpl(
3536         extents.width, extents.height, extents.depth, indexBits, redBlueBits, greenBits, alphaBits,
3537         tmp.data(),
3538         uncompressedChannelCount * extents.width,                   // inputRowPitch
3539         uncompressedChannelCount * extents.width * extents.height,  // inputDepthPitch
3540         data.data(),                                                // output
3541         indexBits * extents.width / 8,                              // outputRowPitch
3542         indexBits * extents.width * extents.height / 8              // outputDepthPitch
3543     );
3544 }
3545 
3546 // Capture the setup of the state that's shared by all of the contexts in the share group
3547 // See IsSharedObjectResource for the list of objects covered here.
CaptureShareGroupMidExecutionSetup(gl::Context * context,std::vector<CallCapture> * setupCalls,ResourceTracker * resourceTracker,gl::State & replayState,const PackedEnumMap<ResourceIDType,uint32_t> & maxAccessedResourceIDs)3548 void CaptureShareGroupMidExecutionSetup(
3549     gl::Context *context,
3550     std::vector<CallCapture> *setupCalls,
3551     ResourceTracker *resourceTracker,
3552     gl::State &replayState,
3553     const PackedEnumMap<ResourceIDType, uint32_t> &maxAccessedResourceIDs)
3554 {
3555     FrameCaptureShared *frameCaptureShared = context->getShareGroup()->getFrameCaptureShared();
3556     const gl::State &apiState              = context->getState();
3557 
3558     // Small helper function to make the code more readable.
3559     auto cap = [setupCalls](CallCapture &&call) { setupCalls->emplace_back(std::move(call)); };
3560 
3561     // Capture Buffer data.
3562     const gl::BufferManager &buffers = apiState.getBufferManagerForCapture();
3563     for (const auto &bufferIter : gl::UnsafeResourceMapIter(buffers.getResourcesForCapture()))
3564     {
3565         gl::BufferID id    = {bufferIter.first};
3566         gl::Buffer *buffer = bufferIter.second;
3567 
3568         if (id.value == 0)
3569         {
3570             continue;
3571         }
3572 
3573         // Generate binding.
3574         cap(CaptureGenBuffers(replayState, true, 1, &id));
3575 
3576         resourceTracker->getTrackedResource(context->id(), ResourceIDType::Buffer)
3577             .getStartingResources()
3578             .insert(id.value);
3579 
3580         MaybeCaptureUpdateResourceIDs(context, resourceTracker, setupCalls);
3581 
3582         // glBufferData. Would possibly be better implemented using a getData impl method.
3583         // Saving buffers that are mapped during a swap is not yet handled.
3584         if (buffer->getSize() == 0)
3585         {
3586             resourceTracker->setStartingBufferMapped(buffer->id().value, false);
3587             continue;
3588         }
3589 
3590         // Remember if the buffer was already mapped
3591         GLboolean bufferMapped = buffer->isMapped();
3592 
3593         // If needed, map the buffer so we can capture its contents
3594         if (!bufferMapped)
3595         {
3596             (void)buffer->mapRange(context, 0, static_cast<GLsizeiptr>(buffer->getSize()),
3597                                    GL_MAP_READ_BIT);
3598         }
3599 
3600         // Always use the array buffer binding point to upload data to keep things simple.
3601         if (buffer != replayState.getArrayBuffer())
3602         {
3603             replayState.setBufferBinding(context, gl::BufferBinding::Array, buffer);
3604             cap(CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, id));
3605         }
3606 
3607         if (buffer->isImmutable())
3608         {
3609             cap(CaptureBufferStorageEXT(replayState, true, gl::BufferBinding::Array,
3610                                         static_cast<GLsizeiptr>(buffer->getSize()),
3611                                         buffer->getMapPointer(),
3612                                         buffer->getStorageExtUsageFlags()));
3613         }
3614         else
3615         {
3616             cap(CaptureBufferData(replayState, true, gl::BufferBinding::Array,
3617                                   static_cast<GLsizeiptr>(buffer->getSize()),
3618                                   buffer->getMapPointer(), buffer->getUsage()));
3619         }
3620 
3621         if (bufferMapped)
3622         {
3623             void *dontCare = nullptr;
3624             CallCapture mapBufferRange =
3625                 CaptureMapBufferRange(replayState, true, gl::BufferBinding::Array,
3626                                       static_cast<GLsizeiptr>(buffer->getMapOffset()),
3627                                       static_cast<GLsizeiptr>(buffer->getMapLength()),
3628                                       buffer->getAccessFlags(), dontCare);
3629             CaptureCustomMapBuffer("MapBufferRange", mapBufferRange, *setupCalls, buffer->id());
3630 
3631             resourceTracker->setStartingBufferMapped(buffer->id().value, true);
3632 
3633             frameCaptureShared->trackBufferMapping(
3634                 context, &setupCalls->back(), buffer->id(), buffer,
3635                 static_cast<GLsizeiptr>(buffer->getMapOffset()),
3636                 static_cast<GLsizeiptr>(buffer->getMapLength()),
3637                 (buffer->getAccessFlags() & GL_MAP_WRITE_BIT) != 0,
3638                 (buffer->getStorageExtUsageFlags() & GL_MAP_COHERENT_BIT_EXT) != 0);
3639         }
3640         else
3641         {
3642             resourceTracker->setStartingBufferMapped(buffer->id().value, false);
3643         }
3644 
3645         // Generate the calls needed to restore this buffer to original state for frame looping
3646         CaptureBufferResetCalls(context, replayState, resourceTracker, &id, buffer);
3647 
3648         // Unmap the buffer if it wasn't already mapped
3649         if (!bufferMapped)
3650         {
3651             GLboolean dontCare;
3652             (void)buffer->unmap(context, &dontCare);
3653         }
3654     }
3655 
3656     // Clear the array buffer binding.
3657     if (replayState.getTargetBuffer(gl::BufferBinding::Array))
3658     {
3659         cap(CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, {0}));
3660         replayState.setBufferBinding(context, gl::BufferBinding::Array, nullptr);
3661     }
3662 
3663     // Set a unpack alignment of 1. Otherwise, computeRowPitch() will compute the wrong value,
3664     // leading to a crash in memcpy() when capturing the texture contents.
3665     gl::PixelUnpackState &currentUnpackState = replayState.getUnpackState();
3666     if (currentUnpackState.alignment != 1)
3667     {
3668         cap(CapturePixelStorei(replayState, true, GL_UNPACK_ALIGNMENT, 1));
3669         replayState.getMutablePrivateStateForCapture()->setUnpackAlignment(1);
3670     }
3671 
3672     const egl::ImageMap eglImageMap = context->getDisplay()->getImagesForCapture();
3673     for (const auto &[eglImageID, eglImage] : eglImageMap)
3674     {
3675         // Track this as a starting resource that may need to be restored.
3676         TrackedResource &trackedImages =
3677             resourceTracker->getTrackedResource(context->id(), ResourceIDType::Image);
3678         trackedImages.getStartingResources().insert(eglImageID);
3679 
3680         ResourceCalls &imageRegenCalls = trackedImages.getResourceRegenCalls();
3681         CallVector imageGenCalls({setupCalls, &imageRegenCalls[eglImageID]});
3682 
3683         auto eglImageAttribIter = resourceTracker->getImageToAttribTable().find(
3684             reinterpret_cast<EGLImage>(static_cast<uintptr_t>(eglImageID)));
3685         ASSERT(eglImageAttribIter != resourceTracker->getImageToAttribTable().end());
3686         const egl::AttributeMap &attribs = eglImageAttribIter->second;
3687 
3688         for (std::vector<CallCapture> *calls : imageGenCalls)
3689         {
3690             // Create the image on demand with the same attrib retrieved above
3691             CallCapture eglCreateImageKHRCall = egl::CaptureCreateImageKHR(
3692                 nullptr, true, nullptr, context->id(), EGL_GL_TEXTURE_2D,
3693                 reinterpret_cast<EGLClientBuffer>(static_cast<uintptr_t>(0)), attribs,
3694                 reinterpret_cast<EGLImage>(static_cast<uintptr_t>(eglImageID)));
3695 
3696             // Convert the CaptureCreateImageKHR CallCapture to the customized CallCapture
3697             CaptureCustomCreateEGLImage(context, "CreateEGLImageKHR", eglImage->getWidth(),
3698                                         eglImage->getHeight(), eglCreateImageKHRCall, *calls);
3699         }
3700     }
3701 
3702     // Capture Texture setup and data.
3703     const gl::TextureManager &textures = apiState.getTextureManagerForCapture();
3704 
3705     for (const auto &textureIter : gl::UnsafeResourceMapIter(textures.getResourcesForCapture()))
3706     {
3707         gl::TextureID id     = {textureIter.first};
3708         gl::Texture *texture = textureIter.second;
3709 
3710         if (id.value == 0)
3711         {
3712             continue;
3713         }
3714 
3715         size_t textureSetupStart = setupCalls->size();
3716 
3717         // Track this as a starting resource that may need to be restored.
3718         TrackedResource &trackedTextures =
3719             resourceTracker->getTrackedResource(context->id(), ResourceIDType::Texture);
3720         ResourceSet &startingTextures = trackedTextures.getStartingResources();
3721         startingTextures.insert(id.value);
3722 
3723         // For the initial texture creation calls, track in the generate list
3724         ResourceCalls &textureRegenCalls = trackedTextures.getResourceRegenCalls();
3725         CallVector texGenCalls({setupCalls, &textureRegenCalls[id.value]});
3726 
3727         // Gen the Texture.
3728         for (std::vector<CallCapture> *calls : texGenCalls)
3729         {
3730             Capture(calls, CaptureGenTextures(replayState, true, 1, &id));
3731             MaybeCaptureUpdateResourceIDs(context, resourceTracker, calls);
3732         }
3733 
3734         // For the remaining texture setup calls, track in the restore list
3735         ResourceCalls &textureRestoreCalls = trackedTextures.getResourceRestoreCalls();
3736         CallVector texSetupCalls({setupCalls, &textureRestoreCalls[id.value]});
3737 
3738         // For each texture, set the correct active texture and binding
3739         // There is similar code in CaptureMidExecutionSetup for per-context setup
3740         const gl::TextureBindingMap &currentBoundTextures = apiState.getBoundTexturesForCapture();
3741         const gl::TextureBindingVector &currentBindings = currentBoundTextures[texture->getType()];
3742         const gl::TextureBindingVector &replayBindings =
3743             replayState.getBoundTexturesForCapture()[texture->getType()];
3744         ASSERT(currentBindings.size() == replayBindings.size());
3745 
3746         // Look up the replay binding
3747         size_t replayActiveTexture = replayState.getActiveSampler();
3748         // If there ends up being no binding, just use the replay binding
3749         // TODO: We may want to start using index 0 for everything, mark it dirty, and restore it
3750         size_t currentActiveTexture = replayActiveTexture;
3751 
3752         // Iterate through current bindings and find the correct index for this texture ID
3753         for (size_t bindingIndex = 0; bindingIndex < currentBindings.size(); ++bindingIndex)
3754         {
3755             gl::TextureID currentTextureID = currentBindings[bindingIndex].id();
3756             gl::TextureID replayTextureID  = replayBindings[bindingIndex].id();
3757 
3758             // Only check the texture we care about
3759             if (currentTextureID == texture->id())
3760             {
3761                 // If the binding doesn't match, track it
3762                 if (currentTextureID != replayTextureID)
3763                 {
3764                     currentActiveTexture = bindingIndex;
3765                 }
3766 
3767                 break;
3768             }
3769         }
3770 
3771         // Set the correct active texture before performing any state changes, including binding
3772         if (currentActiveTexture != replayActiveTexture)
3773         {
3774             for (std::vector<CallCapture> *calls : texSetupCalls)
3775             {
3776                 Capture(calls, CaptureActiveTexture(
3777                                    replayState, true,
3778                                    GL_TEXTURE0 + static_cast<GLenum>(currentActiveTexture)));
3779             }
3780             replayState.getMutablePrivateStateForCapture()->setActiveSampler(
3781                 static_cast<unsigned int>(currentActiveTexture));
3782         }
3783 
3784         for (std::vector<CallCapture> *calls : texSetupCalls)
3785         {
3786             Capture(calls, CaptureBindTexture(replayState, true, texture->getType(), id));
3787         }
3788         replayState.setSamplerTexture(context, texture->getType(), texture);
3789 
3790         // Capture sampler parameter states.
3791         // TODO(jmadill): More sampler / texture states. http://anglebug.com/42262323
3792         gl::SamplerState defaultSamplerState =
3793             gl::SamplerState::CreateDefaultForTarget(texture->getType());
3794         const gl::SamplerState &textureSamplerState = texture->getSamplerState();
3795 
3796         auto capTexParam = [&replayState, texture, &texSetupCalls](GLenum pname, GLint param) {
3797             for (std::vector<CallCapture> *calls : texSetupCalls)
3798             {
3799                 Capture(calls,
3800                         CaptureTexParameteri(replayState, true, texture->getType(), pname, param));
3801             }
3802         };
3803 
3804         auto capTexParamf = [&replayState, texture, &texSetupCalls](GLenum pname, GLfloat param) {
3805             for (std::vector<CallCapture> *calls : texSetupCalls)
3806             {
3807                 Capture(calls,
3808                         CaptureTexParameterf(replayState, true, texture->getType(), pname, param));
3809             }
3810         };
3811 
3812         if (textureSamplerState.getMinFilter() != defaultSamplerState.getMinFilter())
3813         {
3814             capTexParam(GL_TEXTURE_MIN_FILTER, textureSamplerState.getMinFilter());
3815         }
3816 
3817         if (textureSamplerState.getMagFilter() != defaultSamplerState.getMagFilter())
3818         {
3819             capTexParam(GL_TEXTURE_MAG_FILTER, textureSamplerState.getMagFilter());
3820         }
3821 
3822         if (textureSamplerState.getWrapR() != defaultSamplerState.getWrapR())
3823         {
3824             capTexParam(GL_TEXTURE_WRAP_R, textureSamplerState.getWrapR());
3825         }
3826 
3827         if (textureSamplerState.getWrapS() != defaultSamplerState.getWrapS())
3828         {
3829             capTexParam(GL_TEXTURE_WRAP_S, textureSamplerState.getWrapS());
3830         }
3831 
3832         if (textureSamplerState.getWrapT() != defaultSamplerState.getWrapT())
3833         {
3834             capTexParam(GL_TEXTURE_WRAP_T, textureSamplerState.getWrapT());
3835         }
3836 
3837         if (textureSamplerState.getMinLod() != defaultSamplerState.getMinLod())
3838         {
3839             capTexParamf(GL_TEXTURE_MIN_LOD, textureSamplerState.getMinLod());
3840         }
3841 
3842         if (textureSamplerState.getMaxLod() != defaultSamplerState.getMaxLod())
3843         {
3844             capTexParamf(GL_TEXTURE_MAX_LOD, textureSamplerState.getMaxLod());
3845         }
3846 
3847         if (textureSamplerState.getCompareMode() != defaultSamplerState.getCompareMode())
3848         {
3849             capTexParam(GL_TEXTURE_COMPARE_MODE, textureSamplerState.getCompareMode());
3850         }
3851 
3852         if (textureSamplerState.getCompareFunc() != defaultSamplerState.getCompareFunc())
3853         {
3854             capTexParam(GL_TEXTURE_COMPARE_FUNC, textureSamplerState.getCompareFunc());
3855         }
3856 
3857         // Texture parameters
3858         if (texture->getSwizzleRed() != GL_RED)
3859         {
3860             capTexParam(GL_TEXTURE_SWIZZLE_R, texture->getSwizzleRed());
3861         }
3862 
3863         if (texture->getSwizzleGreen() != GL_GREEN)
3864         {
3865             capTexParam(GL_TEXTURE_SWIZZLE_G, texture->getSwizzleGreen());
3866         }
3867 
3868         if (texture->getSwizzleBlue() != GL_BLUE)
3869         {
3870             capTexParam(GL_TEXTURE_SWIZZLE_B, texture->getSwizzleBlue());
3871         }
3872 
3873         if (texture->getSwizzleAlpha() != GL_ALPHA)
3874         {
3875             capTexParam(GL_TEXTURE_SWIZZLE_A, texture->getSwizzleAlpha());
3876         }
3877 
3878         if (texture->getBaseLevel() != 0)
3879         {
3880             capTexParam(GL_TEXTURE_BASE_LEVEL, texture->getBaseLevel());
3881         }
3882 
3883         if (texture->getMaxLevel() != 1000)
3884         {
3885             capTexParam(GL_TEXTURE_MAX_LEVEL, texture->getMaxLevel());
3886         }
3887 
3888         // If the texture is immutable, initialize it with TexStorage
3889         if (texture->getImmutableFormat())
3890         {
3891             // We can only call TexStorage *once* on an immutable texture, so it needs special
3892             // handling. To solve this, immutable textures will have a BindTexture and TexStorage as
3893             // part of their textureRegenCalls. The resulting regen sequence will be:
3894             //
3895             //    const GLuint glDeleteTextures_texturesPacked_0[] = { gTextureMap[52] };
3896             //    glDeleteTextures(1, glDeleteTextures_texturesPacked_0);
3897             //    glGenTextures(1, reinterpret_cast<GLuint *>(gReadBuffer));
3898             //    UpdateTextureID(52, 0);
3899             //    glBindTexture(GL_TEXTURE_2D, gTextureMap[52]);
3900             //    glTexStorage2D(GL_TEXTURE_2D, 1, GL_R8, 256, 512);
3901 
3902             // Bind the texture first just for textureRegenCalls
3903             Capture(&textureRegenCalls[id.value],
3904                     CaptureBindTexture(replayState, true, texture->getType(), id));
3905 
3906             // Then add TexStorage to texGenCalls instead of texSetupCalls
3907             for (std::vector<CallCapture> *calls : texGenCalls)
3908             {
3909                 CaptureTextureStorage(calls, &replayState, texture);
3910             }
3911         }
3912 
3913         // Iterate texture levels and layers.
3914         gl::ImageIndexIterator imageIter = gl::ImageIndexIterator::MakeGeneric(
3915             texture->getType(), 0, texture->getMipmapMaxLevel() + 1, gl::ImageIndex::kEntireLevel,
3916             gl::ImageIndex::kEntireLevel);
3917         while (imageIter.hasNext())
3918         {
3919             gl::ImageIndex index = imageIter.next();
3920 
3921             const gl::ImageDesc &desc = texture->getTextureState().getImageDesc(index);
3922 
3923             if (desc.size.empty())
3924             {
3925                 continue;
3926             }
3927 
3928             const gl::InternalFormat &format = *desc.format.info;
3929 
3930             bool supportedType = (index.getType() == gl::TextureType::_2D ||
3931                                   index.getType() == gl::TextureType::_3D ||
3932                                   index.getType() == gl::TextureType::_2DArray ||
3933                                   index.getType() == gl::TextureType::Buffer ||
3934                                   index.getType() == gl::TextureType::CubeMap ||
3935                                   index.getType() == gl::TextureType::CubeMapArray ||
3936                                   index.getType() == gl::TextureType::External);
3937 
3938             // Check for supported textures
3939             if (!supportedType)
3940             {
3941                 ERR() << "Unsupported texture type: " << index.getType();
3942                 UNREACHABLE();
3943             }
3944 
3945             if (index.getType() == gl::TextureType::Buffer)
3946             {
3947                 // The buffer contents are already backed up, but we need to emit the TexBuffer
3948                 // binding calls
3949                 for (std::vector<CallCapture> *calls : texSetupCalls)
3950                 {
3951                     CaptureTextureContents(calls, &replayState, texture, index, desc, 0, 0);
3952                 }
3953                 continue;
3954             }
3955 
3956             if (index.getType() == gl::TextureType::External)
3957             {
3958                 // Lookup the eglImage ID associated with this texture when the app issued
3959                 // glEGLImageTargetTexture2DOES()
3960                 auto eglImageIter = resourceTracker->getTextureIDToImageTable().find(id.value);
3961                 egl::ImageID eglImageID;
3962                 if (eglImageIter != resourceTracker->getTextureIDToImageTable().end())
3963                 {
3964                     eglImageID = eglImageIter->second;
3965                 }
3966                 else
3967                 {
3968                     // Original image was deleted and needs to be recreated first
3969                     eglImageID = {maxAccessedResourceIDs[ResourceIDType::Image] + 1};
3970                     for (std::vector<CallCapture> *calls : texSetupCalls)
3971                     {
3972                         egl::AttributeMap attribs = egl::AttributeMap::CreateFromIntArray(nullptr);
3973                         CallCapture eglCreateImageKHRCall = egl::CaptureCreateImageKHR(
3974                             nullptr, true, nullptr, context->id(), EGL_GL_TEXTURE_2D,
3975                             reinterpret_cast<EGLClientBuffer>(static_cast<uintptr_t>(0)), attribs,
3976                             reinterpret_cast<EGLImage>(static_cast<uintptr_t>(eglImageID.value)));
3977                         CaptureCustomCreateEGLImage(context, "CreateEGLImageKHR", desc.size.width,
3978                                                     desc.size.height, eglCreateImageKHRCall,
3979                                                     *calls);
3980                     }
3981                 }
3982                 // Pass the eglImage to the texture that is bound to GL_TEXTURE_EXTERNAL_OES target
3983                 for (std::vector<CallCapture> *calls : texSetupCalls)
3984                 {
3985                     Capture(calls, CaptureEGLImageTargetTexture2DOES(
3986                                        replayState, true, gl::TextureType::External, eglImageID));
3987                 }
3988             }
3989             else if (context->getExtensions().getImageANGLE)
3990             {
3991                 // Use ANGLE_get_image to read back pixel data.
3992                 angle::MemoryBuffer data;
3993 
3994                 const gl::Extents extents(desc.size.width, desc.size.height, desc.size.depth);
3995 
3996                 gl::PixelPackState packState;
3997                 packState.alignment = 1;
3998 
3999                 if (format.paletted)
4000                 {
4001                     // Read back the uncompressed texture, then re-compress it
4002                     // to store in the trace.
4003 
4004                     angle::MemoryBuffer tmp;
4005 
4006                     // The uncompressed format (R8G8B8A8) is 4 bytes per texel
4007                     bool result = tmp.resize(4 * extents.width * extents.height * extents.depth);
4008                     ASSERT(result);
4009 
4010                     (void)texture->getTexImage(context, packState, nullptr, index.getTarget(),
4011                                                index.getLevelIndex(), GL_RGBA, GL_UNSIGNED_BYTE,
4012                                                tmp.data());
4013 
4014                     CompressPalettedTexture(data, tmp, format, extents);
4015                 }
4016                 else if (format.compressed)
4017                 {
4018                     // Calculate the size needed to store the compressed level
4019                     GLuint sizeInBytes;
4020                     bool result = format.computeCompressedImageSize(extents, &sizeInBytes);
4021                     ASSERT(result);
4022 
4023                     result = data.resize(sizeInBytes);
4024                     ASSERT(result);
4025 
4026                     (void)texture->getCompressedTexImage(context, packState, nullptr,
4027                                                          index.getTarget(), index.getLevelIndex(),
4028                                                          data.data());
4029                 }
4030                 else
4031                 {
4032                     GLenum getFormat = format.format;
4033                     GLenum getType   = format.type;
4034 
4035                     const gl::PixelUnpackState &unpack = apiState.getUnpackState();
4036 
4037                     GLuint endByte = 0;
4038                     bool unpackSize =
4039                         format.computePackUnpackEndByte(getType, extents, unpack, true, &endByte);
4040                     ASSERT(unpackSize);
4041 
4042                     bool result = data.resize(endByte);
4043                     ASSERT(result);
4044 
4045                     (void)texture->getTexImage(context, packState, nullptr, index.getTarget(),
4046                                                index.getLevelIndex(), getFormat, getType,
4047                                                data.data());
4048                 }
4049 
4050                 for (std::vector<CallCapture> *calls : texSetupCalls)
4051                 {
4052                     CaptureTextureContents(calls, &replayState, texture, index, desc,
4053                                            static_cast<GLuint>(data.size()), data.data());
4054                 }
4055             }
4056             else
4057             {
4058                 for (std::vector<CallCapture> *calls : texSetupCalls)
4059                 {
4060                     CaptureTextureContents(calls, &replayState, texture, index, desc, 0, nullptr);
4061                 }
4062             }
4063         }
4064 
4065         size_t textureSetupEnd = setupCalls->size();
4066 
4067         // Mark the range of calls used to setup this texture
4068         frameCaptureShared->markResourceSetupCallsInactive(
4069             setupCalls, ResourceIDType::Texture, id.value,
4070             gl::Range<size_t>(textureSetupStart, textureSetupEnd));
4071     }
4072 
4073     // Capture Renderbuffers.
4074     const gl::RenderbufferManager &renderbuffers = apiState.getRenderbufferManagerForCapture();
4075     FramebufferCaptureFuncs framebufferFuncs(context->isGLES1());
4076 
4077     for (const auto &renderbufIter :
4078          gl::UnsafeResourceMapIter(renderbuffers.getResourcesForCapture()))
4079     {
4080         gl::RenderbufferID id                = {renderbufIter.first};
4081         const gl::Renderbuffer *renderbuffer = renderbufIter.second;
4082 
4083         // Track this as a starting resource that may need to be restored.
4084         TrackedResource &trackedRenderbuffers =
4085             resourceTracker->getTrackedResource(context->id(), ResourceIDType::Renderbuffer);
4086         ResourceSet &startingRenderbuffers = trackedRenderbuffers.getStartingResources();
4087         startingRenderbuffers.insert(id.value);
4088 
4089         // For the initial renderbuffer creation calls, track in the generate list
4090         ResourceCalls &renderbufferRegenCalls = trackedRenderbuffers.getResourceRegenCalls();
4091         CallVector rbGenCalls({setupCalls, &renderbufferRegenCalls[id.value]});
4092 
4093         // Generate renderbuffer id.
4094         for (std::vector<CallCapture> *calls : rbGenCalls)
4095         {
4096             Capture(calls, framebufferFuncs.genRenderbuffers(replayState, true, 1, &id));
4097             MaybeCaptureUpdateResourceIDs(context, resourceTracker, calls);
4098             Capture(calls,
4099                     framebufferFuncs.bindRenderbuffer(replayState, true, GL_RENDERBUFFER, id));
4100         }
4101 
4102         GLenum internalformat = renderbuffer->getFormat().info->internalFormat;
4103 
4104         if (renderbuffer->getSamples() > 0)
4105         {
4106             // Note: We could also use extensions if available.
4107             for (std::vector<CallCapture> *calls : rbGenCalls)
4108             {
4109                 Capture(calls,
4110                         CaptureRenderbufferStorageMultisample(
4111                             replayState, true, GL_RENDERBUFFER, renderbuffer->getSamples(),
4112                             internalformat, renderbuffer->getWidth(), renderbuffer->getHeight()));
4113             }
4114         }
4115         else
4116         {
4117             for (std::vector<CallCapture> *calls : rbGenCalls)
4118             {
4119                 Capture(calls, framebufferFuncs.renderbufferStorage(
4120                                    replayState, true, GL_RENDERBUFFER, internalformat,
4121                                    renderbuffer->getWidth(), renderbuffer->getHeight()));
4122             }
4123         }
4124 
4125         // TODO: Capture renderbuffer contents. http://anglebug.com/42262323
4126     }
4127 
4128     // Capture Shaders and Programs.
4129     const gl::ShaderProgramManager &shadersAndPrograms =
4130         apiState.getShaderProgramManagerForCapture();
4131     const gl::ResourceMap<gl::Shader, gl::ShaderProgramID> &shaders =
4132         shadersAndPrograms.getShadersForCapture();
4133     const gl::ResourceMap<gl::Program, gl::ShaderProgramID> &programs =
4134         shadersAndPrograms.getProgramsForCaptureAndPerf();
4135 
4136     TrackedResource &trackedShaderPrograms =
4137         resourceTracker->getTrackedResource(context->id(), ResourceIDType::ShaderProgram);
4138 
4139     // Capture Program binary state.
4140     gl::ShaderProgramID tempShaderStartID = {resourceTracker->getMaxShaderPrograms()};
4141     std::map<gl::ShaderProgramID, std::vector<gl::ShaderProgramID>> deferredAttachCalls;
4142     for (const auto &programIter : gl::UnsafeResourceMapIter(programs))
4143     {
4144         gl::ShaderProgramID id = {programIter.first};
4145         gl::Program *program   = programIter.second;
4146 
4147         // Unlinked programs don't have an executable so track in case linking is deferred
4148         // Programs are shared by contexts in the share group and only need to be captured once.
4149         if (!program->isLinked())
4150         {
4151             frameCaptureShared->setDeferredLinkProgram(id);
4152 
4153             if (program->getAttachedShadersCount() > 0)
4154             {
4155                 // AttachShader calls will be generated at shader-handling time
4156                 for (gl::ShaderType shaderType : gl::AllShaderTypes())
4157                 {
4158                     gl::Shader *shader = program->getAttachedShader(shaderType);
4159                     if (shader != nullptr)
4160                     {
4161                         deferredAttachCalls[shader->getHandle()].push_back(id);
4162                     }
4163                 }
4164             }
4165             else
4166             {
4167                 WARN() << "Deferred attachment of shaders is not yet supported";
4168             }
4169         }
4170 
4171         size_t programSetupStart = setupCalls->size();
4172 
4173         // Create two lists for program regen calls
4174         ResourceCalls &shaderProgramRegenCalls = trackedShaderPrograms.getResourceRegenCalls();
4175         CallVector programRegenCalls({setupCalls, &shaderProgramRegenCalls[id.value]});
4176 
4177         for (std::vector<CallCapture> *calls : programRegenCalls)
4178         {
4179             CallCapture createProgram = CaptureCreateProgram(replayState, true, id.value);
4180             CaptureCustomShaderProgram("CreateProgram", createProgram, *calls);
4181         }
4182 
4183         if (program->isLinked())
4184         {
4185             // Get last linked shader source.
4186             const ProgramSources &linkedSources =
4187                 context->getShareGroup()->getFrameCaptureShared()->getProgramSources(id);
4188 
4189             // Create two lists for program restore calls
4190             ResourceCalls &shaderProgramRestoreCalls =
4191                 trackedShaderPrograms.getResourceRestoreCalls();
4192             CallVector programRestoreCalls({setupCalls, &shaderProgramRestoreCalls[id.value]});
4193 
4194             for (std::vector<CallCapture> *calls : programRestoreCalls)
4195             {
4196                 GenerateLinkedProgram(context, replayState, resourceTracker, calls, program, id,
4197                                       tempShaderStartID, linkedSources);
4198             }
4199 
4200             // Update the program in replayState
4201             if (!replayState.getProgram() || replayState.getProgram()->id() != program->id())
4202             {
4203                 // Note: We don't do this in GenerateLinkedProgram because it can't modify state
4204                 (void)replayState.setProgram(context, program);
4205             }
4206         }
4207 
4208         resourceTracker->getTrackedResource(context->id(), ResourceIDType::ShaderProgram)
4209             .getStartingResources()
4210             .insert(id.value);
4211         resourceTracker->setShaderProgramType(id, ShaderProgramType::ProgramType);
4212 
4213         // Mark linked programs/shaders as inactive, leaving deferred-linked programs/shaders marked
4214         // as active
4215         if (!frameCaptureShared->isDeferredLinkProgram(id))
4216         {
4217             size_t programSetupEnd = setupCalls->size();
4218 
4219             // Mark the range of calls used to setup this program
4220             frameCaptureShared->markResourceSetupCallsInactive(
4221                 setupCalls, ResourceIDType::ShaderProgram, id.value,
4222                 gl::Range<size_t>(programSetupStart, programSetupEnd));
4223         }
4224     }
4225 
4226     // Handle shaders.
4227     for (const auto &shaderIter : gl::UnsafeResourceMapIter(shaders))
4228     {
4229         gl::ShaderProgramID id = {shaderIter.first};
4230         gl::Shader *shader     = shaderIter.second;
4231 
4232         // Skip shaders scheduled for deletion.
4233         // Shaders are shared by contexts in the share group and only need to be captured once.
4234         if (shader->hasBeenDeleted())
4235         {
4236             continue;
4237         }
4238 
4239         size_t shaderSetupStart = setupCalls->size();
4240 
4241         // Create two lists for shader regen calls
4242         ResourceCalls &shaderProgramRegenCalls = trackedShaderPrograms.getResourceRegenCalls();
4243         CallVector shaderRegenCalls({setupCalls, &shaderProgramRegenCalls[id.value]});
4244 
4245         for (std::vector<CallCapture> *calls : shaderRegenCalls)
4246         {
4247             CallCapture createShader =
4248                 CaptureCreateShader(replayState, true, shader->getType(), id.value);
4249             CaptureCustomShaderProgram("CreateShader", createShader, *calls);
4250 
4251             // If unlinked programs have been created which reference this shader emit corresponding
4252             // attach calls
4253             for (const auto deferredAttachedProgramID : deferredAttachCalls[id])
4254             {
4255                 CallCapture attachShader =
4256                     CaptureAttachShader(replayState, true, deferredAttachedProgramID, id);
4257                 calls->emplace_back(std::move(attachShader));
4258             }
4259         }
4260 
4261         std::string shaderSource  = shader->getSourceString();
4262         const char *sourcePointer = shaderSource.empty() ? nullptr : shaderSource.c_str();
4263 
4264         // Create two lists for shader restore calls
4265         ResourceCalls &shaderProgramRestoreCalls = trackedShaderPrograms.getResourceRestoreCalls();
4266         CallVector shaderRestoreCalls({setupCalls, &shaderProgramRestoreCalls[id.value]});
4267 
4268         // This does not handle some more tricky situations like attaching and then deleting a
4269         // shader.
4270         // TODO(jmadill): Handle trickier program uses. http://anglebug.com/42262323
4271         if (shader->isCompiled(context))
4272         {
4273             const std::string &capturedSource =
4274                 context->getShareGroup()->getFrameCaptureShared()->getShaderSource(id);
4275             if (capturedSource != shaderSource)
4276             {
4277                 ASSERT(!capturedSource.empty());
4278                 sourcePointer = capturedSource.c_str();
4279             }
4280 
4281             for (std::vector<CallCapture> *calls : shaderRestoreCalls)
4282             {
4283                 Capture(calls,
4284                         CaptureShaderSource(replayState, true, id, 1, &sourcePointer, nullptr));
4285                 Capture(calls, CaptureCompileShader(replayState, true, id));
4286             }
4287         }
4288 
4289         if (sourcePointer &&
4290             (!shader->isCompiled(context) || sourcePointer != shaderSource.c_str()))
4291         {
4292             for (std::vector<CallCapture> *calls : shaderRestoreCalls)
4293             {
4294                 Capture(calls,
4295                         CaptureShaderSource(replayState, true, id, 1, &sourcePointer, nullptr));
4296             }
4297         }
4298 
4299         // Deferred-linked programs/shaders must be left marked as active
4300         if (deferredAttachCalls[id].empty())
4301         {
4302             // Mark the range of calls used to setup this shader
4303             frameCaptureShared->markResourceSetupCallsInactive(
4304                 setupCalls, ResourceIDType::ShaderProgram, id.value,
4305                 gl::Range<size_t>(shaderSetupStart, setupCalls->size()));
4306         }
4307 
4308         resourceTracker->getTrackedResource(context->id(), ResourceIDType::ShaderProgram)
4309             .getStartingResources()
4310             .insert(id.value);
4311         resourceTracker->setShaderProgramType(id, ShaderProgramType::ShaderType);
4312     }
4313 
4314     // Capture Sampler Objects
4315     const gl::SamplerManager &samplers = apiState.getSamplerManagerForCapture();
4316     for (const auto &samplerIter : gl::UnsafeResourceMapIter(samplers.getResourcesForCapture()))
4317     {
4318         gl::SamplerID samplerID = {samplerIter.first};
4319 
4320         // Don't gen the sampler if we've seen it before, since they are shared across the context
4321         // share group.
4322         cap(CaptureGenSamplers(replayState, true, 1, &samplerID));
4323         MaybeCaptureUpdateResourceIDs(context, resourceTracker, setupCalls);
4324 
4325         gl::Sampler *sampler = samplerIter.second;
4326         if (!sampler)
4327         {
4328             continue;
4329         }
4330 
4331         gl::SamplerState defaultSamplerState;
4332         if (sampler->getMinFilter() != defaultSamplerState.getMinFilter())
4333         {
4334             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_MIN_FILTER,
4335                                          sampler->getMinFilter()));
4336         }
4337         if (sampler->getMagFilter() != defaultSamplerState.getMagFilter())
4338         {
4339             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_MAG_FILTER,
4340                                          sampler->getMagFilter()));
4341         }
4342         if (sampler->getWrapS() != defaultSamplerState.getWrapS())
4343         {
4344             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_WRAP_S,
4345                                          sampler->getWrapS()));
4346         }
4347         if (sampler->getWrapR() != defaultSamplerState.getWrapR())
4348         {
4349             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_WRAP_R,
4350                                          sampler->getWrapR()));
4351         }
4352         if (sampler->getWrapT() != defaultSamplerState.getWrapT())
4353         {
4354             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_WRAP_T,
4355                                          sampler->getWrapT()));
4356         }
4357         if (sampler->getMinLod() != defaultSamplerState.getMinLod())
4358         {
4359             cap(CaptureSamplerParameterf(replayState, true, samplerID, GL_TEXTURE_MIN_LOD,
4360                                          sampler->getMinLod()));
4361         }
4362         if (sampler->getMaxLod() != defaultSamplerState.getMaxLod())
4363         {
4364             cap(CaptureSamplerParameterf(replayState, true, samplerID, GL_TEXTURE_MAX_LOD,
4365                                          sampler->getMaxLod()));
4366         }
4367         if (sampler->getCompareMode() != defaultSamplerState.getCompareMode())
4368         {
4369             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_COMPARE_MODE,
4370                                          sampler->getCompareMode()));
4371         }
4372         if (sampler->getCompareFunc() != defaultSamplerState.getCompareFunc())
4373         {
4374             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_COMPARE_FUNC,
4375                                          sampler->getCompareFunc()));
4376         }
4377     }
4378 
4379     // Capture Sync Objects
4380     const gl::SyncManager &syncs = apiState.getSyncManagerForCapture();
4381     for (const auto &syncIter : gl::UnsafeResourceMapIter(syncs.getResourcesForCapture()))
4382     {
4383         gl::SyncID syncID    = {syncIter.first};
4384         const gl::Sync *sync = syncIter.second;
4385         GLsync syncObject    = gl::unsafe_int_to_pointer_cast<GLsync>(syncID.value);
4386 
4387         if (!sync)
4388         {
4389             continue;
4390         }
4391         CallCapture fenceSync =
4392             CaptureFenceSync(replayState, true, sync->getCondition(), sync->getFlags(), syncObject);
4393         CaptureCustomFenceSync(fenceSync, *setupCalls);
4394         CaptureFenceSyncResetCalls(context, replayState, resourceTracker, syncID, syncObject, sync);
4395         resourceTracker->getStartingFenceSyncs().insert(syncID);
4396     }
4397 
4398     // Capture EGL Sync Objects
4399     const egl::SyncMap &eglSyncMap = context->getDisplay()->getSyncsForCapture();
4400     for (const auto &eglSyncIter : eglSyncMap)
4401     {
4402         egl::SyncID eglSyncID    = {eglSyncIter.first};
4403         const egl::Sync *eglSync = eglSyncIter.second.get();
4404         EGLSync eglSyncObject    = gl::unsafe_int_to_pointer_cast<EGLSync>(eglSyncID.value);
4405 
4406         if (!eglSync)
4407         {
4408             continue;
4409         }
4410         CallCapture createEGLSync =
4411             CaptureCreateSync(nullptr, true, context->getDisplay(), eglSync->getType(),
4412                               eglSync->getAttributeMap(), eglSyncObject);
4413         CaptureCustomCreateEGLSync("CreateEGLSyncKHR", createEGLSync, *setupCalls);
4414         CaptureEGLSyncResetCalls(context, replayState, resourceTracker, eglSyncID, eglSyncObject,
4415                                  eglSync);
4416         resourceTracker->getTrackedResource(context->id(), ResourceIDType::egl_Sync)
4417             .getStartingResources()
4418             .insert(eglSyncID.value);
4419     }
4420 
4421     GLint contextUnpackAlignment = context->getState().getUnpackState().alignment;
4422     if (currentUnpackState.alignment != contextUnpackAlignment)
4423     {
4424         cap(CapturePixelStorei(replayState, true, GL_UNPACK_ALIGNMENT, contextUnpackAlignment));
4425         replayState.getMutablePrivateStateForCapture()->setUnpackAlignment(contextUnpackAlignment);
4426     }
4427 }
4428 
CaptureMidExecutionSetup(const gl::Context * context,std::vector<CallCapture> * setupCalls,StateResetHelper & resetHelper,std::vector<CallCapture> * shareGroupSetupCalls,ResourceIDToSetupCallsMap * resourceIDToSetupCalls,ResourceTracker * resourceTracker,gl::State & replayState,bool validationEnabled)4429 void CaptureMidExecutionSetup(const gl::Context *context,
4430                               std::vector<CallCapture> *setupCalls,
4431                               StateResetHelper &resetHelper,
4432                               std::vector<CallCapture> *shareGroupSetupCalls,
4433                               ResourceIDToSetupCallsMap *resourceIDToSetupCalls,
4434                               ResourceTracker *resourceTracker,
4435                               gl::State &replayState,
4436                               bool validationEnabled)
4437 {
4438     const gl::State &apiState = context->getState();
4439 
4440     // Small helper function to make the code more readable.
4441     auto cap = [setupCalls](CallCapture &&call) { setupCalls->emplace_back(std::move(call)); };
4442 
4443     cap(egl::CaptureMakeCurrent(nullptr, true, nullptr, {0}, {0}, context->id(), EGL_TRUE));
4444 
4445     // Vertex input states. Must happen after buffer data initialization. Do not capture on GLES1.
4446     if (!context->isGLES1())
4447     {
4448         CaptureDefaultVertexAttribs(replayState, apiState, setupCalls);
4449     }
4450 
4451     // Capture vertex array objects
4452     VertexArrayCaptureFuncs vertexArrayFuncs(context->isGLES1());
4453 
4454     const gl::VertexArrayMap &vertexArrayMap = context->getVertexArraysForCapture();
4455     gl::VertexArrayID boundVertexArrayID     = {0};
4456     for (const auto &vertexArrayIter : gl::UnsafeResourceMapIter(vertexArrayMap))
4457     {
4458         TrackedResource &trackedVertexArrays =
4459             resourceTracker->getTrackedResource(context->id(), ResourceIDType::VertexArray);
4460 
4461         gl::VertexArrayID vertexArrayID = {vertexArrayIter.first};
4462 
4463         // Track this as a starting resource that may need to be restored
4464         resourceTracker->getTrackedResource(context->id(), ResourceIDType::VertexArray)
4465             .getStartingResources()
4466             .insert(vertexArrayID.value);
4467 
4468         // Create two lists of calls for initial setup
4469         ResourceCalls &vertexArrayRegenCalls = trackedVertexArrays.getResourceRegenCalls();
4470         CallVector vertexArrayGenCalls({setupCalls, &vertexArrayRegenCalls[vertexArrayID.value]});
4471 
4472         if (vertexArrayID.value != 0)
4473         {
4474             // Gen the vertex array
4475             for (std::vector<CallCapture> *calls : vertexArrayGenCalls)
4476             {
4477                 Capture(calls,
4478                         vertexArrayFuncs.genVertexArrays(replayState, true, 1, &vertexArrayID));
4479                 MaybeCaptureUpdateResourceIDs(context, resourceTracker, calls);
4480             }
4481         }
4482 
4483         // Create two lists of calls for populating the vertex array
4484         ResourceCalls &vertexArrayRestoreCalls = trackedVertexArrays.getResourceRestoreCalls();
4485         CallVector vertexArraySetupCalls(
4486             {setupCalls, &vertexArrayRestoreCalls[vertexArrayID.value]});
4487 
4488         if (vertexArrayIter.second)
4489         {
4490             const gl::VertexArray *vertexArray = vertexArrayIter.second;
4491 
4492             // Populate the vertex array
4493             for (std::vector<CallCapture> *calls : vertexArraySetupCalls)
4494             {
4495                 // Bind the vertexArray (if needed) and populate it
4496                 if (vertexArrayID != boundVertexArrayID)
4497                 {
4498                     Capture(calls,
4499                             vertexArrayFuncs.bindVertexArray(replayState, true, vertexArrayID));
4500                 }
4501                 CaptureVertexArrayState(calls, context, vertexArray, &replayState);
4502             }
4503             boundVertexArrayID = vertexArrayID;
4504         }
4505     }
4506 
4507     // Bind the current vertex array
4508     const gl::VertexArray *currentVertexArray = apiState.getVertexArray();
4509     if (currentVertexArray->id() != boundVertexArrayID)
4510     {
4511         cap(vertexArrayFuncs.bindVertexArray(replayState, true, currentVertexArray->id()));
4512     }
4513 
4514     // Track the calls necessary to bind the vertex array back to initial state
4515     CallResetMap &resetCalls = resetHelper.getResetCalls();
4516     Capture(&resetCalls[angle::EntryPoint::GLBindVertexArray],
4517             vertexArrayFuncs.bindVertexArray(replayState, true, currentVertexArray->id()));
4518 
4519     // Capture indexed buffer bindings.
4520     const gl::BufferVector &uniformIndexedBuffers =
4521         apiState.getOffsetBindingPointerUniformBuffers();
4522     const gl::BufferVector &atomicCounterIndexedBuffers =
4523         apiState.getOffsetBindingPointerAtomicCounterBuffers();
4524     const gl::BufferVector &shaderStorageIndexedBuffers =
4525         apiState.getOffsetBindingPointerShaderStorageBuffers();
4526     CaptureIndexedBuffers(replayState, uniformIndexedBuffers, gl::BufferBinding::Uniform,
4527                           setupCalls);
4528     CaptureIndexedBuffers(replayState, atomicCounterIndexedBuffers,
4529                           gl::BufferBinding::AtomicCounter, setupCalls);
4530     CaptureIndexedBuffers(replayState, shaderStorageIndexedBuffers,
4531                           gl::BufferBinding::ShaderStorage, setupCalls);
4532 
4533     // Capture Buffer bindings.
4534     const gl::BoundBufferMap &boundBuffers = apiState.getBoundBuffersForCapture();
4535     for (gl::BufferBinding binding : angle::AllEnums<gl::BufferBinding>())
4536     {
4537         gl::BufferID bufferID = boundBuffers[binding].id();
4538 
4539         // Filter out redundant buffer binding commands. Note that the code in the previous section
4540         // only binds to ARRAY_BUFFER. Therefore we only check the array binding against the binding
4541         // we set earlier.
4542         const gl::Buffer *arrayBuffer = replayState.getArrayBuffer();
4543         bool isArray                  = binding == gl::BufferBinding::Array;
4544         bool isArrayBufferChanging    = isArray && arrayBuffer && arrayBuffer->id() != bufferID;
4545         if (isArrayBufferChanging || (!isArray && bufferID.value != 0))
4546         {
4547             cap(CaptureBindBuffer(replayState, true, binding, bufferID));
4548             replayState.setBufferBinding(context, binding, boundBuffers[binding].get());
4549         }
4550 
4551         // Restore all buffer bindings for Reset
4552         if (bufferID.value != 0 || isArrayBufferChanging)
4553         {
4554             CaptureBufferBindingResetCalls(replayState, resourceTracker, binding, bufferID);
4555 
4556             // Track this as a starting binding
4557             resetHelper.setStartingBufferBinding(binding, bufferID);
4558         }
4559     }
4560 
4561     // Set a unpack alignment of 1. Otherwise, computeRowPitch() will compute the wrong value,
4562     // leading to a crash in memcpy() when capturing the texture contents.
4563     gl::PixelUnpackState &currentUnpackState = replayState.getUnpackState();
4564     if (currentUnpackState.alignment != 1)
4565     {
4566         cap(CapturePixelStorei(replayState, true, GL_UNPACK_ALIGNMENT, 1));
4567         replayState.getMutablePrivateStateForCapture()->setUnpackAlignment(1);
4568     }
4569 
4570     // Capture Texture setup and data.
4571     const gl::TextureBindingMap &apiBoundTextures = apiState.getBoundTexturesForCapture();
4572     resetHelper.setResetActiveTexture(apiState.getActiveSampler());
4573 
4574     // Set Texture bindings.
4575     for (gl::TextureType textureType : angle::AllEnums<gl::TextureType>())
4576     {
4577         const gl::TextureBindingVector &apiBindings = apiBoundTextures[textureType];
4578         const gl::TextureBindingVector &replayBindings =
4579             replayState.getBoundTexturesForCapture()[textureType];
4580         ASSERT(apiBindings.size() == replayBindings.size());
4581         for (size_t bindingIndex = 0; bindingIndex < apiBindings.size(); ++bindingIndex)
4582         {
4583             gl::TextureID apiTextureID    = apiBindings[bindingIndex].id();
4584             gl::TextureID replayTextureID = replayBindings[bindingIndex].id();
4585 
4586             if (apiTextureID != replayTextureID)
4587             {
4588                 if (replayState.getActiveSampler() != bindingIndex)
4589                 {
4590                     cap(CaptureActiveTexture(replayState, true,
4591                                              GL_TEXTURE0 + static_cast<GLenum>(bindingIndex)));
4592                     replayState.getMutablePrivateStateForCapture()->setActiveSampler(
4593                         static_cast<unsigned int>(bindingIndex));
4594                 }
4595 
4596                 cap(CaptureBindTexture(replayState, true, textureType, apiTextureID));
4597                 replayState.setSamplerTexture(context, textureType,
4598                                               apiBindings[bindingIndex].get());
4599             }
4600 
4601             if (apiTextureID.value)
4602             {
4603                 // Set this texture as active so it will be generated in Setup
4604                 MarkResourceIDActive(ResourceIDType::Texture, apiTextureID.value,
4605                                      shareGroupSetupCalls, resourceIDToSetupCalls);
4606                 // Save currently bound textures for reset
4607                 resetHelper.getResetTextureBindings().emplace(
4608                     std::make_pair(bindingIndex, textureType), apiTextureID);
4609             }
4610         }
4611     }
4612 
4613     // Capture Texture Environment
4614     if (context->isGLES1())
4615     {
4616         const gl::Caps &caps = context->getCaps();
4617         for (GLuint unit = 0; unit < caps.maxMultitextureUnits; ++unit)
4618         {
4619             CaptureTextureEnvironmentState(setupCalls, &replayState, &apiState, unit);
4620         }
4621     }
4622 
4623     // Set active Texture.
4624     if (replayState.getActiveSampler() != apiState.getActiveSampler())
4625     {
4626         cap(CaptureActiveTexture(replayState, true,
4627                                  GL_TEXTURE0 + static_cast<GLenum>(apiState.getActiveSampler())));
4628         replayState.getMutablePrivateStateForCapture()->setActiveSampler(
4629             apiState.getActiveSampler());
4630     }
4631 
4632     // Set Renderbuffer binding.
4633     FramebufferCaptureFuncs framebufferFuncs(context->isGLES1());
4634 
4635     const gl::RenderbufferManager &renderbuffers = apiState.getRenderbufferManagerForCapture();
4636     gl::RenderbufferID currentRenderbuffer       = {0};
4637     for (const auto &renderbufIter :
4638          gl::UnsafeResourceMapIter(renderbuffers.getResourcesForCapture()))
4639     {
4640         currentRenderbuffer = renderbufIter.second->id();
4641     }
4642 
4643     if (currentRenderbuffer != apiState.getRenderbufferId())
4644     {
4645         cap(framebufferFuncs.bindRenderbuffer(replayState, true, GL_RENDERBUFFER,
4646                                               apiState.getRenderbufferId()));
4647     }
4648 
4649     // Capture Framebuffers.
4650     const gl::FramebufferManager &framebuffers = apiState.getFramebufferManagerForCapture();
4651 
4652     gl::FramebufferID currentDrawFramebuffer = {0};
4653     gl::FramebufferID currentReadFramebuffer = {0};
4654 
4655     for (const auto &framebufferIter :
4656          gl::UnsafeResourceMapIter(framebuffers.getResourcesForCapture()))
4657     {
4658         gl::FramebufferID id               = {framebufferIter.first};
4659         const gl::Framebuffer *framebuffer = framebufferIter.second;
4660 
4661         // The default Framebuffer exists (by default).
4662         if (framebuffer->isDefault())
4663         {
4664             continue;
4665         }
4666 
4667         // Track this as a starting resource that may need to be restored
4668         TrackedResource &trackedFramebuffers =
4669             resourceTracker->getTrackedResource(context->id(), ResourceIDType::Framebuffer);
4670         ResourceSet &startingFramebuffers = trackedFramebuffers.getStartingResources();
4671         startingFramebuffers.insert(id.value);
4672 
4673         // Create two lists of calls for initial setup
4674         ResourceCalls &framebufferRegenCalls = trackedFramebuffers.getResourceRegenCalls();
4675         CallVector framebufferGenCalls({setupCalls, &framebufferRegenCalls[id.value]});
4676 
4677         // Gen the framebuffer
4678         for (std::vector<CallCapture> *calls : framebufferGenCalls)
4679         {
4680             Capture(calls, framebufferFuncs.genFramebuffers(replayState, true, 1, &id));
4681             MaybeCaptureUpdateResourceIDs(context, resourceTracker, calls);
4682         }
4683 
4684         // Create two lists of calls for remaining setup calls.  One for setup, and one for restore
4685         // during reset.
4686         ResourceCalls &framebufferRestoreCalls = trackedFramebuffers.getResourceRestoreCalls();
4687         CallVector framebufferSetupCalls({setupCalls, &framebufferRestoreCalls[id.value]});
4688 
4689         for (std::vector<CallCapture> *calls : framebufferSetupCalls)
4690         {
4691             CaptureBindFramebufferForContext(context, calls, framebufferFuncs, replayState,
4692                                              GL_FRAMEBUFFER, id);
4693         }
4694         currentDrawFramebuffer = currentReadFramebuffer = id;
4695 
4696         // Color Attachments.
4697         for (const gl::FramebufferAttachment &colorAttachment : framebuffer->getColorAttachments())
4698         {
4699             if (!colorAttachment.isAttached())
4700             {
4701                 continue;
4702             }
4703 
4704             for (std::vector<CallCapture> *calls : framebufferSetupCalls)
4705             {
4706                 CaptureFramebufferAttachment(calls, replayState, framebufferFuncs, colorAttachment,
4707                                              shareGroupSetupCalls, resourceIDToSetupCalls);
4708             }
4709         }
4710 
4711         const gl::FramebufferAttachment *depthAttachment = framebuffer->getDepthAttachment();
4712         if (depthAttachment)
4713         {
4714             ASSERT(depthAttachment->getBinding() == GL_DEPTH_ATTACHMENT ||
4715                    depthAttachment->getBinding() == GL_DEPTH_STENCIL_ATTACHMENT);
4716             for (std::vector<CallCapture> *calls : framebufferSetupCalls)
4717             {
4718                 CaptureFramebufferAttachment(calls, replayState, framebufferFuncs, *depthAttachment,
4719                                              shareGroupSetupCalls, resourceIDToSetupCalls);
4720             }
4721         }
4722 
4723         const gl::FramebufferAttachment *stencilAttachment = framebuffer->getStencilAttachment();
4724         if (stencilAttachment)
4725         {
4726             ASSERT(stencilAttachment->getBinding() == GL_STENCIL_ATTACHMENT ||
4727                    depthAttachment->getBinding() == GL_DEPTH_STENCIL_ATTACHMENT);
4728             for (std::vector<CallCapture> *calls : framebufferSetupCalls)
4729             {
4730                 CaptureFramebufferAttachment(calls, replayState, framebufferFuncs,
4731                                              *stencilAttachment, shareGroupSetupCalls,
4732                                              resourceIDToSetupCalls);
4733             }
4734         }
4735 
4736         gl::FramebufferState defaultFramebufferState(
4737             context->getCaps(), framebuffer->getState().id(),
4738             framebuffer->getState().getFramebufferSerial());
4739         const gl::DrawBuffersVector<GLenum> &defaultDrawBufferStates =
4740             defaultFramebufferState.getDrawBufferStates();
4741         const gl::DrawBuffersVector<GLenum> &drawBufferStates = framebuffer->getDrawBufferStates();
4742 
4743         if (drawBufferStates != defaultDrawBufferStates)
4744         {
4745             for (std::vector<CallCapture> *calls : framebufferSetupCalls)
4746             {
4747                 Capture(calls, CaptureDrawBuffers(replayState, true,
4748                                                   static_cast<GLsizei>(drawBufferStates.size()),
4749                                                   drawBufferStates.data()));
4750             }
4751         }
4752     }
4753 
4754     // Capture framebuffer bindings.
4755     if (apiState.getDrawFramebuffer())
4756     {
4757         ASSERT(apiState.getReadFramebuffer());
4758         gl::FramebufferID stateReadFramebuffer = apiState.getReadFramebuffer()->id();
4759         gl::FramebufferID stateDrawFramebuffer = apiState.getDrawFramebuffer()->id();
4760         if (stateDrawFramebuffer == stateReadFramebuffer)
4761         {
4762             if (currentDrawFramebuffer != stateDrawFramebuffer ||
4763                 currentReadFramebuffer != stateReadFramebuffer)
4764             {
4765                 CaptureBindFramebufferForContext(context, setupCalls, framebufferFuncs, replayState,
4766                                                  GL_FRAMEBUFFER, stateDrawFramebuffer);
4767                 currentDrawFramebuffer = currentReadFramebuffer = stateDrawFramebuffer;
4768             }
4769         }
4770         else
4771         {
4772             if (currentDrawFramebuffer != stateDrawFramebuffer)
4773             {
4774                 CaptureBindFramebufferForContext(context, setupCalls, framebufferFuncs, replayState,
4775                                                  GL_DRAW_FRAMEBUFFER, stateDrawFramebuffer);
4776                 currentDrawFramebuffer = stateDrawFramebuffer;
4777             }
4778 
4779             if (currentReadFramebuffer != stateReadFramebuffer)
4780             {
4781                 CaptureBindFramebufferForContext(context, setupCalls, framebufferFuncs, replayState,
4782                                                  GL_READ_FRAMEBUFFER, stateReadFramebuffer);
4783                 currentReadFramebuffer = stateReadFramebuffer;
4784             }
4785         }
4786     }
4787 
4788     // Capture Program Pipelines
4789     const gl::ProgramPipelineManager *programPipelineManager =
4790         apiState.getProgramPipelineManagerForCapture();
4791 
4792     for (const auto &ppoIterator :
4793          gl::UnsafeResourceMapIter(programPipelineManager->getResourcesForCapture()))
4794     {
4795         gl::ProgramPipeline *pipeline = ppoIterator.second;
4796         gl::ProgramPipelineID id      = {ppoIterator.first};
4797         cap(CaptureGenProgramPipelines(replayState, true, 1, &id));
4798         MaybeCaptureUpdateResourceIDs(context, resourceTracker, setupCalls);
4799 
4800         // PPOs can contain graphics and compute programs, so loop through all shader types rather
4801         // than just the linked ones since getLinkedShaderStages() will return either only graphics
4802         // or compute stages.
4803         for (gl::ShaderType shaderType : gl::AllShaderTypes())
4804         {
4805             const gl::Program *program = pipeline->getShaderProgram(shaderType);
4806             if (!program)
4807             {
4808                 continue;
4809             }
4810             ASSERT(program->isLinked());
4811             GLbitfield gLbitfield = GetBitfieldFromShaderType(shaderType);
4812             cap(CaptureUseProgramStages(replayState, true, pipeline->id(), gLbitfield,
4813                                         program->id()));
4814 
4815             // Set this program as active so it will be generated in Setup
4816             // Note: We aren't filtering ProgramPipelines, so this could be setting programs
4817             // active that aren't actually used.
4818             MarkResourceIDActive(ResourceIDType::ShaderProgram, program->id().value,
4819                                  shareGroupSetupCalls, resourceIDToSetupCalls);
4820         }
4821 
4822         gl::Program *program = pipeline->getActiveShaderProgram();
4823         if (program)
4824         {
4825             cap(CaptureActiveShaderProgram(replayState, true, id, program->id()));
4826         }
4827     }
4828 
4829     // For now we assume the installed program executable is the same as the current program.
4830     // TODO(jmadill): Handle installed program executable. http://anglebug.com/42262323
4831     if (!context->isGLES1())
4832     {
4833         // If we have a program bound in the API, or if there is no program bound to the API at
4834         // time of capture and we bound a program for uniform updates during MEC, we must add
4835         // a set program call to replay the correct states.
4836         GLuint currentProgram = 0;
4837         if (apiState.getProgram())
4838         {
4839             cap(CaptureUseProgram(replayState, true, apiState.getProgram()->id()));
4840             CaptureUpdateCurrentProgram(setupCalls->back(), 0, setupCalls);
4841             (void)replayState.setProgram(context, apiState.getProgram());
4842 
4843             // Set this program as active so it will be generated in Setup
4844             MarkResourceIDActive(ResourceIDType::ShaderProgram, apiState.getProgram()->id().value,
4845                                  shareGroupSetupCalls, resourceIDToSetupCalls);
4846 
4847             currentProgram = apiState.getProgram()->id().value;
4848         }
4849         else if (replayState.getProgram())
4850         {
4851             cap(CaptureUseProgram(replayState, true, {0}));
4852             CaptureUpdateCurrentProgram(setupCalls->back(), 0, setupCalls);
4853             (void)replayState.setProgram(context, nullptr);
4854         }
4855 
4856         // Track the calls necessary to reset active program back to initial state
4857         Capture(&resetCalls[angle::EntryPoint::GLUseProgram],
4858                 CaptureUseProgram(replayState, true, {currentProgram}));
4859         CaptureUpdateCurrentProgram((&resetCalls[angle::EntryPoint::GLUseProgram])->back(), 0,
4860                                     &resetCalls[angle::EntryPoint::GLUseProgram]);
4861 
4862         // Same for program pipelines as for programs, see comment above.
4863         if (apiState.getProgramPipeline())
4864         {
4865             cap(CaptureBindProgramPipeline(replayState, true, apiState.getProgramPipeline()->id()));
4866         }
4867         else if (replayState.getProgramPipeline())
4868         {
4869             cap(CaptureBindProgramPipeline(replayState, true, {0}));
4870         }
4871     }
4872 
4873     // Capture Queries
4874     const gl::QueryMap &queryMap = context->getQueriesForCapture();
4875 
4876     // Create existing queries. Note that queries may be genned and not yet started. In that
4877     // case the queries will exist in the query map as nullptr entries.
4878     // If any queries are active between frames, we want to defer creation and do them last,
4879     // otherwise you'll get GL errors about starting a query while one is already active.
4880     for (gl::QueryMap::Iterator queryIter = gl::UnsafeResourceMapIter(queryMap).beginWithNull(),
4881                                 endIter   = gl::UnsafeResourceMapIter(queryMap).endWithNull();
4882          queryIter != endIter; ++queryIter)
4883     {
4884         ASSERT(queryIter->first);
4885         gl::QueryID queryID = {queryIter->first};
4886 
4887         cap(CaptureGenQueries(replayState, true, 1, &queryID));
4888         MaybeCaptureUpdateResourceIDs(context, resourceTracker, setupCalls);
4889 
4890         gl::Query *query = queryIter->second;
4891         if (query)
4892         {
4893             gl::QueryType queryType = query->getType();
4894 
4895             // Defer active queries until we've created them all
4896             if (IsQueryActive(apiState, queryID))
4897             {
4898                 continue;
4899             }
4900 
4901             // Begin the query to generate the object
4902             cap(CaptureBeginQuery(replayState, true, queryType, queryID));
4903 
4904             // End the query if it was not active
4905             cap(CaptureEndQuery(replayState, true, queryType));
4906         }
4907     }
4908 
4909     const gl::ActiveQueryMap &activeQueries = apiState.getActiveQueriesForCapture();
4910     for (const auto &activeQueryIter : activeQueries)
4911     {
4912         const gl::Query *activeQuery = activeQueryIter.get();
4913         if (activeQuery)
4914         {
4915             cap(CaptureBeginQuery(replayState, true, activeQuery->getType(), activeQuery->id()));
4916         }
4917     }
4918 
4919     // Transform Feedback
4920     const gl::TransformFeedbackMap &xfbMap = context->getTransformFeedbacksForCapture();
4921     for (const auto &xfbIter : gl::UnsafeResourceMapIter(xfbMap))
4922     {
4923         gl::TransformFeedbackID xfbID = {xfbIter.first};
4924 
4925         // Do not capture the default XFB object.
4926         if (xfbID.value == 0)
4927         {
4928             continue;
4929         }
4930 
4931         cap(CaptureGenTransformFeedbacks(replayState, true, 1, &xfbID));
4932         MaybeCaptureUpdateResourceIDs(context, resourceTracker, setupCalls);
4933 
4934         gl::TransformFeedback *xfb = xfbIter.second;
4935         if (!xfb)
4936         {
4937             // The object was never created
4938             continue;
4939         }
4940 
4941         // Bind XFB to create the object
4942         cap(CaptureBindTransformFeedback(replayState, true, GL_TRANSFORM_FEEDBACK, xfbID));
4943 
4944         // Bind the buffers associated with this XFB object
4945         for (size_t i = 0; i < xfb->getIndexedBufferCount(); ++i)
4946         {
4947             const gl::OffsetBindingPointer<gl::Buffer> &xfbBuffer = xfb->getIndexedBuffer(i);
4948 
4949             // Note: Buffers bound with BindBufferBase can be used with BindBuffer
4950             cap(CaptureBindBufferRange(replayState, true, gl::BufferBinding::TransformFeedback, 0,
4951                                        xfbBuffer.id(), xfbBuffer.getOffset(), xfbBuffer.getSize()));
4952         }
4953 
4954         if (xfb->isActive() || xfb->isPaused())
4955         {
4956             // We don't support active XFB in MEC yet
4957             UNIMPLEMENTED();
4958         }
4959     }
4960 
4961     // Bind the current XFB buffer after populating XFB objects
4962     gl::TransformFeedback *currentXFB = apiState.getCurrentTransformFeedback();
4963     if (currentXFB)
4964     {
4965         cap(CaptureBindTransformFeedback(replayState, true, GL_TRANSFORM_FEEDBACK,
4966                                          currentXFB->id()));
4967     }
4968 
4969     // Bind samplers
4970     const gl::SamplerBindingVector &samplerBindings = apiState.getSamplers();
4971     for (GLuint bindingIndex = 0; bindingIndex < static_cast<GLuint>(samplerBindings.size());
4972          ++bindingIndex)
4973     {
4974         gl::SamplerID samplerID = samplerBindings[bindingIndex].id();
4975         if (samplerID.value != 0)
4976         {
4977             cap(CaptureBindSampler(replayState, true, bindingIndex, samplerID));
4978         }
4979     }
4980 
4981     // Capture Image Texture bindings
4982     const std::vector<gl::ImageUnit> &imageUnits = apiState.getImageUnits();
4983     for (GLuint bindingIndex = 0; bindingIndex < static_cast<GLuint>(imageUnits.size());
4984          ++bindingIndex)
4985     {
4986         const gl::ImageUnit &imageUnit = imageUnits[bindingIndex];
4987 
4988         if (imageUnit.texture == 0)
4989         {
4990             continue;
4991         }
4992 
4993         cap(CaptureBindImageTexture(replayState, true, bindingIndex, imageUnit.texture.id(),
4994                                     imageUnit.level, imageUnit.layered, imageUnit.layer,
4995                                     imageUnit.access, imageUnit.format));
4996     }
4997 
4998     // Capture GL Context states.
4999     auto capCap = [cap, &replayState](GLenum capEnum, bool capValue) {
5000         if (capValue)
5001         {
5002             cap(CaptureEnable(replayState, true, capEnum));
5003         }
5004         else
5005         {
5006             cap(CaptureDisable(replayState, true, capEnum));
5007         }
5008     };
5009 
5010     // Capture GLES1 context states.
5011     if (context->isGLES1())
5012     {
5013         const bool currentTextureState = apiState.getEnableFeature(GL_TEXTURE_2D);
5014         const bool defaultTextureState = replayState.getEnableFeature(GL_TEXTURE_2D);
5015         if (currentTextureState != defaultTextureState)
5016         {
5017             capCap(GL_TEXTURE_2D, currentTextureState);
5018         }
5019 
5020         cap(CaptureMatrixMode(replayState, true, gl::MatrixType::Projection));
5021         for (angle::Mat4 projectionMatrix :
5022              apiState.gles1().getMatrixStack(gl::MatrixType::Projection))
5023         {
5024             cap(CapturePushMatrix(replayState, true));
5025             cap(CaptureLoadMatrixf(replayState, true, projectionMatrix.elements().data()));
5026         }
5027 
5028         cap(CaptureMatrixMode(replayState, true, gl::MatrixType::Modelview));
5029         for (angle::Mat4 modelViewMatrix :
5030              apiState.gles1().getMatrixStack(gl::MatrixType::Modelview))
5031         {
5032             cap(CapturePushMatrix(replayState, true));
5033             cap(CaptureLoadMatrixf(replayState, true, modelViewMatrix.elements().data()));
5034         }
5035 
5036         gl::MatrixType currentMatrixMode = apiState.gles1().getMatrixMode();
5037         if (currentMatrixMode != gl::MatrixType::Modelview)
5038         {
5039             cap(CaptureMatrixMode(replayState, true, currentMatrixMode));
5040         }
5041 
5042         // Alpha Test state
5043         const bool currentAlphaTestState = apiState.getEnableFeature(GL_ALPHA_TEST);
5044         const bool defaultAlphaTestState = replayState.getEnableFeature(GL_ALPHA_TEST);
5045 
5046         if (currentAlphaTestState != defaultAlphaTestState)
5047         {
5048             capCap(GL_ALPHA_TEST, currentAlphaTestState);
5049         }
5050 
5051         const gl::AlphaTestParameters currentAlphaTestParameters =
5052             apiState.gles1().getAlphaTestParameters();
5053         const gl::AlphaTestParameters defaultAlphaTestParameters =
5054             replayState.gles1().getAlphaTestParameters();
5055 
5056         if (currentAlphaTestParameters != defaultAlphaTestParameters)
5057         {
5058             cap(CaptureAlphaFunc(replayState, true, currentAlphaTestParameters.func,
5059                                  currentAlphaTestParameters.ref));
5060         }
5061     }
5062 
5063     // Rasterizer state. Missing ES 3.x features.
5064     const gl::RasterizerState &defaultRasterState = replayState.getRasterizerState();
5065     const gl::RasterizerState &currentRasterState = apiState.getRasterizerState();
5066     if (currentRasterState.cullFace != defaultRasterState.cullFace)
5067     {
5068         capCap(GL_CULL_FACE, currentRasterState.cullFace);
5069     }
5070 
5071     if (currentRasterState.cullMode != defaultRasterState.cullMode)
5072     {
5073         cap(CaptureCullFace(replayState, true, currentRasterState.cullMode));
5074     }
5075 
5076     if (currentRasterState.frontFace != defaultRasterState.frontFace)
5077     {
5078         cap(CaptureFrontFace(replayState, true, currentRasterState.frontFace));
5079     }
5080 
5081     if (currentRasterState.polygonMode != defaultRasterState.polygonMode)
5082     {
5083         if (context->getExtensions().polygonModeNV)
5084         {
5085             cap(CapturePolygonModeNV(replayState, true, GL_FRONT_AND_BACK,
5086                                      currentRasterState.polygonMode));
5087         }
5088         else if (context->getExtensions().polygonModeANGLE)
5089         {
5090             cap(CapturePolygonModeANGLE(replayState, true, GL_FRONT_AND_BACK,
5091                                         currentRasterState.polygonMode));
5092         }
5093         else
5094         {
5095             UNREACHABLE();
5096         }
5097     }
5098 
5099     if (currentRasterState.polygonOffsetPoint != defaultRasterState.polygonOffsetPoint)
5100     {
5101         capCap(GL_POLYGON_OFFSET_POINT_NV, currentRasterState.polygonOffsetPoint);
5102     }
5103 
5104     if (currentRasterState.polygonOffsetLine != defaultRasterState.polygonOffsetLine)
5105     {
5106         capCap(GL_POLYGON_OFFSET_LINE_NV, currentRasterState.polygonOffsetLine);
5107     }
5108 
5109     if (currentRasterState.polygonOffsetFill != defaultRasterState.polygonOffsetFill)
5110     {
5111         capCap(GL_POLYGON_OFFSET_FILL, currentRasterState.polygonOffsetFill);
5112     }
5113 
5114     if (currentRasterState.polygonOffsetFactor != defaultRasterState.polygonOffsetFactor ||
5115         currentRasterState.polygonOffsetUnits != defaultRasterState.polygonOffsetUnits ||
5116         currentRasterState.polygonOffsetClamp != defaultRasterState.polygonOffsetClamp)
5117     {
5118         if (currentRasterState.polygonOffsetClamp == 0.0f)
5119         {
5120             cap(CapturePolygonOffset(replayState, true, currentRasterState.polygonOffsetFactor,
5121                                      currentRasterState.polygonOffsetUnits));
5122         }
5123         else
5124         {
5125             cap(CapturePolygonOffsetClampEXT(
5126                 replayState, true, currentRasterState.polygonOffsetFactor,
5127                 currentRasterState.polygonOffsetUnits, currentRasterState.polygonOffsetClamp));
5128         }
5129     }
5130 
5131     if (currentRasterState.depthClamp != defaultRasterState.depthClamp)
5132     {
5133         capCap(GL_DEPTH_CLAMP_EXT, currentRasterState.depthClamp);
5134     }
5135 
5136     // pointDrawMode/multiSample are only used in the D3D back-end right now.
5137 
5138     if (currentRasterState.rasterizerDiscard != defaultRasterState.rasterizerDiscard)
5139     {
5140         capCap(GL_RASTERIZER_DISCARD, currentRasterState.rasterizerDiscard);
5141     }
5142 
5143     if (currentRasterState.dither != defaultRasterState.dither)
5144     {
5145         capCap(GL_DITHER, currentRasterState.dither);
5146     }
5147 
5148     // Depth/stencil state.
5149     const gl::DepthStencilState &defaultDSState = replayState.getDepthStencilState();
5150     const gl::DepthStencilState &currentDSState = apiState.getDepthStencilState();
5151     if (defaultDSState.depthFunc != currentDSState.depthFunc)
5152     {
5153         cap(CaptureDepthFunc(replayState, true, currentDSState.depthFunc));
5154     }
5155 
5156     if (defaultDSState.depthMask != currentDSState.depthMask)
5157     {
5158         cap(CaptureDepthMask(replayState, true, gl::ConvertToGLBoolean(currentDSState.depthMask)));
5159     }
5160 
5161     if (defaultDSState.depthTest != currentDSState.depthTest)
5162     {
5163         capCap(GL_DEPTH_TEST, currentDSState.depthTest);
5164     }
5165 
5166     if (defaultDSState.stencilTest != currentDSState.stencilTest)
5167     {
5168         capCap(GL_STENCIL_TEST, currentDSState.stencilTest);
5169     }
5170 
5171     if (currentDSState.stencilFunc == currentDSState.stencilBackFunc &&
5172         currentDSState.stencilMask == currentDSState.stencilBackMask)
5173     {
5174         // Front and back are equal
5175         if (defaultDSState.stencilFunc != currentDSState.stencilFunc ||
5176             defaultDSState.stencilMask != currentDSState.stencilMask ||
5177             apiState.getStencilRef() != 0)
5178         {
5179             cap(CaptureStencilFunc(replayState, true, currentDSState.stencilFunc,
5180                                    apiState.getStencilRef(), currentDSState.stencilMask));
5181         }
5182     }
5183     else
5184     {
5185         // Front and back are separate
5186         if (defaultDSState.stencilFunc != currentDSState.stencilFunc ||
5187             defaultDSState.stencilMask != currentDSState.stencilMask ||
5188             apiState.getStencilRef() != 0)
5189         {
5190             cap(CaptureStencilFuncSeparate(replayState, true, GL_FRONT, currentDSState.stencilFunc,
5191                                            apiState.getStencilRef(), currentDSState.stencilMask));
5192         }
5193 
5194         if (defaultDSState.stencilBackFunc != currentDSState.stencilBackFunc ||
5195             defaultDSState.stencilBackMask != currentDSState.stencilBackMask ||
5196             apiState.getStencilBackRef() != 0)
5197         {
5198             cap(CaptureStencilFuncSeparate(
5199                 replayState, true, GL_BACK, currentDSState.stencilBackFunc,
5200                 apiState.getStencilBackRef(), currentDSState.stencilBackMask));
5201         }
5202     }
5203 
5204     if (currentDSState.stencilFail == currentDSState.stencilBackFail &&
5205         currentDSState.stencilPassDepthFail == currentDSState.stencilBackPassDepthFail &&
5206         currentDSState.stencilPassDepthPass == currentDSState.stencilBackPassDepthPass)
5207     {
5208         // Front and back are equal
5209         if (defaultDSState.stencilFail != currentDSState.stencilFail ||
5210             defaultDSState.stencilPassDepthFail != currentDSState.stencilPassDepthFail ||
5211             defaultDSState.stencilPassDepthPass != currentDSState.stencilPassDepthPass)
5212         {
5213             cap(CaptureStencilOp(replayState, true, currentDSState.stencilFail,
5214                                  currentDSState.stencilPassDepthFail,
5215                                  currentDSState.stencilPassDepthPass));
5216         }
5217     }
5218     else
5219     {
5220         // Front and back are separate
5221         if (defaultDSState.stencilFail != currentDSState.stencilFail ||
5222             defaultDSState.stencilPassDepthFail != currentDSState.stencilPassDepthFail ||
5223             defaultDSState.stencilPassDepthPass != currentDSState.stencilPassDepthPass)
5224         {
5225             cap(CaptureStencilOpSeparate(replayState, true, GL_FRONT, currentDSState.stencilFail,
5226                                          currentDSState.stencilPassDepthFail,
5227                                          currentDSState.stencilPassDepthPass));
5228         }
5229 
5230         if (defaultDSState.stencilBackFail != currentDSState.stencilBackFail ||
5231             defaultDSState.stencilBackPassDepthFail != currentDSState.stencilBackPassDepthFail ||
5232             defaultDSState.stencilBackPassDepthPass != currentDSState.stencilBackPassDepthPass)
5233         {
5234             cap(CaptureStencilOpSeparate(replayState, true, GL_BACK, currentDSState.stencilBackFail,
5235                                          currentDSState.stencilBackPassDepthFail,
5236                                          currentDSState.stencilBackPassDepthPass));
5237         }
5238     }
5239 
5240     if (currentDSState.stencilWritemask == currentDSState.stencilBackWritemask)
5241     {
5242         // Front and back are equal
5243         if (defaultDSState.stencilWritemask != currentDSState.stencilWritemask)
5244         {
5245             cap(CaptureStencilMask(replayState, true, currentDSState.stencilWritemask));
5246         }
5247     }
5248     else
5249     {
5250         // Front and back are separate
5251         if (defaultDSState.stencilWritemask != currentDSState.stencilWritemask)
5252         {
5253             cap(CaptureStencilMaskSeparate(replayState, true, GL_FRONT,
5254                                            currentDSState.stencilWritemask));
5255         }
5256 
5257         if (defaultDSState.stencilBackWritemask != currentDSState.stencilBackWritemask)
5258         {
5259             cap(CaptureStencilMaskSeparate(replayState, true, GL_BACK,
5260                                            currentDSState.stencilBackWritemask));
5261         }
5262     }
5263 
5264     // Blend state.
5265     const gl::BlendState &defaultBlendState = replayState.getBlendState();
5266     const gl::BlendState &currentBlendState = apiState.getBlendState();
5267 
5268     if (currentBlendState.blend != defaultBlendState.blend)
5269     {
5270         capCap(GL_BLEND, currentBlendState.blend);
5271     }
5272 
5273     if (currentBlendState.sourceBlendRGB != defaultBlendState.sourceBlendRGB ||
5274         currentBlendState.destBlendRGB != defaultBlendState.destBlendRGB ||
5275         currentBlendState.sourceBlendAlpha != defaultBlendState.sourceBlendAlpha ||
5276         currentBlendState.destBlendAlpha != defaultBlendState.destBlendAlpha)
5277     {
5278         if (context->isGLES1())
5279         {
5280             // Even though their states are tracked independently, in GLES1 blendAlpha
5281             // and blendRGB cannot be set separately and are always equal
5282             cap(CaptureBlendFunc(replayState, true, currentBlendState.sourceBlendRGB,
5283                                  currentBlendState.destBlendRGB));
5284             Capture(&resetCalls[angle::EntryPoint::GLBlendFunc],
5285                     CaptureBlendFunc(replayState, true, currentBlendState.sourceBlendRGB,
5286                                      currentBlendState.destBlendRGB));
5287         }
5288         else
5289         {
5290             // Always use BlendFuncSeparate for non-GLES1 as it covers all cases
5291             cap(CaptureBlendFuncSeparate(
5292                 replayState, true, currentBlendState.sourceBlendRGB, currentBlendState.destBlendRGB,
5293                 currentBlendState.sourceBlendAlpha, currentBlendState.destBlendAlpha));
5294             Capture(&resetCalls[angle::EntryPoint::GLBlendFuncSeparate],
5295                     CaptureBlendFuncSeparate(replayState, true, currentBlendState.sourceBlendRGB,
5296                                              currentBlendState.destBlendRGB,
5297                                              currentBlendState.sourceBlendAlpha,
5298                                              currentBlendState.destBlendAlpha));
5299         }
5300     }
5301 
5302     if (currentBlendState.blendEquationRGB != defaultBlendState.blendEquationRGB ||
5303         currentBlendState.blendEquationAlpha != defaultBlendState.blendEquationAlpha)
5304     {
5305         // Similarly to BlendFunc, using BlendEquation in some cases complicates Reset.
5306         cap(CaptureBlendEquationSeparate(replayState, true, currentBlendState.blendEquationRGB,
5307                                          currentBlendState.blendEquationAlpha));
5308         Capture(&resetCalls[angle::EntryPoint::GLBlendEquationSeparate],
5309                 CaptureBlendEquationSeparate(replayState, true, currentBlendState.blendEquationRGB,
5310                                              currentBlendState.blendEquationAlpha));
5311     }
5312 
5313     if (currentBlendState.colorMaskRed != defaultBlendState.colorMaskRed ||
5314         currentBlendState.colorMaskGreen != defaultBlendState.colorMaskGreen ||
5315         currentBlendState.colorMaskBlue != defaultBlendState.colorMaskBlue ||
5316         currentBlendState.colorMaskAlpha != defaultBlendState.colorMaskAlpha)
5317     {
5318         cap(CaptureColorMask(replayState, true,
5319                              gl::ConvertToGLBoolean(currentBlendState.colorMaskRed),
5320                              gl::ConvertToGLBoolean(currentBlendState.colorMaskGreen),
5321                              gl::ConvertToGLBoolean(currentBlendState.colorMaskBlue),
5322                              gl::ConvertToGLBoolean(currentBlendState.colorMaskAlpha)));
5323         Capture(&resetCalls[angle::EntryPoint::GLColorMask],
5324                 CaptureColorMask(replayState, true,
5325                                  gl::ConvertToGLBoolean(currentBlendState.colorMaskRed),
5326                                  gl::ConvertToGLBoolean(currentBlendState.colorMaskGreen),
5327                                  gl::ConvertToGLBoolean(currentBlendState.colorMaskBlue),
5328                                  gl::ConvertToGLBoolean(currentBlendState.colorMaskAlpha)));
5329     }
5330 
5331     const gl::ColorF &currentBlendColor = apiState.getBlendColor();
5332     if (currentBlendColor != gl::ColorF())
5333     {
5334         cap(CaptureBlendColor(replayState, true, currentBlendColor.red, currentBlendColor.green,
5335                               currentBlendColor.blue, currentBlendColor.alpha));
5336         Capture(&resetCalls[angle::EntryPoint::GLBlendColor],
5337                 CaptureBlendColor(replayState, true, currentBlendColor.red, currentBlendColor.green,
5338                                   currentBlendColor.blue, currentBlendColor.alpha));
5339     }
5340 
5341     // Pixel storage states.
5342     gl::PixelPackState &currentPackState = replayState.getPackState();
5343     if (currentPackState.alignment != apiState.getPackAlignment())
5344     {
5345         cap(CapturePixelStorei(replayState, true, GL_PACK_ALIGNMENT, apiState.getPackAlignment()));
5346         currentPackState.alignment = apiState.getPackAlignment();
5347     }
5348 
5349     if (currentPackState.rowLength != apiState.getPackRowLength())
5350     {
5351         cap(CapturePixelStorei(replayState, true, GL_PACK_ROW_LENGTH, apiState.getPackRowLength()));
5352         currentPackState.rowLength = apiState.getPackRowLength();
5353     }
5354 
5355     if (currentPackState.skipRows != apiState.getPackSkipRows())
5356     {
5357         cap(CapturePixelStorei(replayState, true, GL_PACK_SKIP_ROWS, apiState.getPackSkipRows()));
5358         currentPackState.skipRows = apiState.getPackSkipRows();
5359     }
5360 
5361     if (currentPackState.skipPixels != apiState.getPackSkipPixels())
5362     {
5363         cap(CapturePixelStorei(replayState, true, GL_PACK_SKIP_PIXELS,
5364                                apiState.getPackSkipPixels()));
5365         currentPackState.skipPixels = apiState.getPackSkipPixels();
5366     }
5367 
5368     // We set unpack alignment above, no need to change it here
5369     ASSERT(currentUnpackState.alignment == 1);
5370     if (currentUnpackState.rowLength != apiState.getUnpackRowLength())
5371     {
5372         cap(CapturePixelStorei(replayState, true, GL_UNPACK_ROW_LENGTH,
5373                                apiState.getUnpackRowLength()));
5374         currentUnpackState.rowLength = apiState.getUnpackRowLength();
5375     }
5376 
5377     if (currentUnpackState.skipRows != apiState.getUnpackSkipRows())
5378     {
5379         cap(CapturePixelStorei(replayState, true, GL_UNPACK_SKIP_ROWS,
5380                                apiState.getUnpackSkipRows()));
5381         currentUnpackState.skipRows = apiState.getUnpackSkipRows();
5382     }
5383 
5384     if (currentUnpackState.skipPixels != apiState.getUnpackSkipPixels())
5385     {
5386         cap(CapturePixelStorei(replayState, true, GL_UNPACK_SKIP_PIXELS,
5387                                apiState.getUnpackSkipPixels()));
5388         currentUnpackState.skipPixels = apiState.getUnpackSkipPixels();
5389     }
5390 
5391     if (currentUnpackState.imageHeight != apiState.getUnpackImageHeight())
5392     {
5393         cap(CapturePixelStorei(replayState, true, GL_UNPACK_IMAGE_HEIGHT,
5394                                apiState.getUnpackImageHeight()));
5395         currentUnpackState.imageHeight = apiState.getUnpackImageHeight();
5396     }
5397 
5398     if (currentUnpackState.skipImages != apiState.getUnpackSkipImages())
5399     {
5400         cap(CapturePixelStorei(replayState, true, GL_UNPACK_SKIP_IMAGES,
5401                                apiState.getUnpackSkipImages()));
5402         currentUnpackState.skipImages = apiState.getUnpackSkipImages();
5403     }
5404 
5405     // Clear state. Missing ES 3.x features.
5406     // TODO(http://anglebug.com/42262323): Complete state capture.
5407     const gl::ColorF &currentClearColor = apiState.getColorClearValue();
5408     if (currentClearColor != gl::ColorF())
5409     {
5410         cap(CaptureClearColor(replayState, true, currentClearColor.red, currentClearColor.green,
5411                               currentClearColor.blue, currentClearColor.alpha));
5412     }
5413 
5414     if (apiState.getDepthClearValue() != 1.0f)
5415     {
5416         cap(CaptureClearDepthf(replayState, true, apiState.getDepthClearValue()));
5417     }
5418 
5419     if (apiState.getStencilClearValue() != 0)
5420     {
5421         cap(CaptureClearStencil(replayState, true, apiState.getStencilClearValue()));
5422     }
5423 
5424     // Viewport / scissor / clipping planes.
5425     const gl::Rectangle &currentViewport = apiState.getViewport();
5426     if (currentViewport != gl::Rectangle())
5427     {
5428         cap(CaptureViewport(replayState, true, currentViewport.x, currentViewport.y,
5429                             currentViewport.width, currentViewport.height));
5430     }
5431 
5432     if (apiState.getNearPlane() != 0.0f || apiState.getFarPlane() != 1.0f)
5433     {
5434         cap(CaptureDepthRangef(replayState, true, apiState.getNearPlane(), apiState.getFarPlane()));
5435     }
5436 
5437     if (apiState.getClipOrigin() != gl::ClipOrigin::LowerLeft ||
5438         apiState.getClipDepthMode() != gl::ClipDepthMode::NegativeOneToOne)
5439     {
5440         cap(CaptureClipControlEXT(replayState, true, apiState.getClipOrigin(),
5441                                   apiState.getClipDepthMode()));
5442     }
5443 
5444     if (apiState.isScissorTestEnabled())
5445     {
5446         capCap(GL_SCISSOR_TEST, apiState.isScissorTestEnabled());
5447     }
5448 
5449     const gl::Rectangle &currentScissor = apiState.getScissor();
5450     if (currentScissor != gl::Rectangle())
5451     {
5452         cap(CaptureScissor(replayState, true, currentScissor.x, currentScissor.y,
5453                            currentScissor.width, currentScissor.height));
5454     }
5455 
5456     // Allow the replayState object to be destroyed conveniently.
5457     replayState.setBufferBinding(context, gl::BufferBinding::Array, nullptr);
5458 
5459     // Clean up the replay state.
5460     replayState.reset(context);
5461 
5462     GLint contextUnpackAlignment = context->getState().getUnpackState().alignment;
5463     if (currentUnpackState.alignment != contextUnpackAlignment)
5464     {
5465         cap(CapturePixelStorei(replayState, true, GL_UNPACK_ALIGNMENT, contextUnpackAlignment));
5466         replayState.getMutablePrivateStateForCapture()->setUnpackAlignment(contextUnpackAlignment);
5467     }
5468 
5469     if (validationEnabled)
5470     {
5471         CaptureValidateSerializedState(context, setupCalls);
5472     }
5473 }
5474 
SkipCall(EntryPoint entryPoint)5475 bool SkipCall(EntryPoint entryPoint)
5476 {
5477     switch (entryPoint)
5478     {
5479         case EntryPoint::GLDebugMessageCallback:
5480         case EntryPoint::GLDebugMessageCallbackKHR:
5481         case EntryPoint::GLDebugMessageControl:
5482         case EntryPoint::GLDebugMessageControlKHR:
5483         case EntryPoint::GLDebugMessageInsert:
5484         case EntryPoint::GLDebugMessageInsertKHR:
5485         case EntryPoint::GLGetDebugMessageLog:
5486         case EntryPoint::GLGetDebugMessageLogKHR:
5487         case EntryPoint::GLGetObjectLabel:
5488         case EntryPoint::GLGetObjectLabelEXT:
5489         case EntryPoint::GLGetObjectLabelKHR:
5490         case EntryPoint::GLGetObjectPtrLabelKHR:
5491         case EntryPoint::GLGetPointervKHR:
5492         case EntryPoint::GLInsertEventMarkerEXT:
5493         case EntryPoint::GLLabelObjectEXT:
5494         case EntryPoint::GLObjectLabel:
5495         case EntryPoint::GLObjectLabelKHR:
5496         case EntryPoint::GLObjectPtrLabelKHR:
5497         case EntryPoint::GLPopDebugGroupKHR:
5498         case EntryPoint::GLPopGroupMarkerEXT:
5499         case EntryPoint::GLPushDebugGroupKHR:
5500         case EntryPoint::GLPushGroupMarkerEXT:
5501             // Purposefully skip entry points from:
5502             // - KHR_debug
5503             // - EXT_debug_label
5504             // - EXT_debug_marker
5505             // There is no need to capture these for replaying a trace in our harness
5506             return true;
5507 
5508         case EntryPoint::GLGetActiveUniform:
5509         case EntryPoint::GLGetActiveUniformsiv:
5510             // Skip these calls because:
5511             // - We don't use the return values.
5512             // - Active uniform counts can vary between platforms due to cross stage optimizations
5513             //   and asking about uniforms above GL_ACTIVE_UNIFORMS triggers errors.
5514             return true;
5515 
5516         case EntryPoint::GLGetActiveAttrib:
5517             // Skip these calls because:
5518             // - We don't use the return values.
5519             // - Same as uniforms, the value can vary, asking above GL_ACTIVE_ATTRIBUTES is an error
5520             return true;
5521 
5522         case EntryPoint::GLGetActiveUniformBlockiv:
5523         case EntryPoint::GLGetActiveUniformBlockName:
5524             // Skip these calls because:
5525             // - We don't use the return values.
5526             // - It reduces the number of references to the uniform block index map.
5527             return true;
5528 
5529         case EntryPoint::EGLChooseConfig:
5530         case EntryPoint::EGLGetProcAddress:
5531         case EntryPoint::EGLGetConfigAttrib:
5532         case EntryPoint::EGLGetConfigs:
5533         case EntryPoint::EGLGetSyncAttrib:
5534         case EntryPoint::EGLGetSyncAttribKHR:
5535         case EntryPoint::EGLQueryContext:
5536         case EntryPoint::EGLQuerySurface:
5537             // Skip these calls because:
5538             // - We don't use the return values.
5539             // - Some EGL types and pointer parameters aren't yet implemented in EGL capture.
5540             return true;
5541 
5542         case EntryPoint::EGLPrepareSwapBuffersANGLE:
5543             // Skip this call because:
5544             // - eglPrepareSwapBuffersANGLE is automatically called by eglSwapBuffers
5545             return true;
5546 
5547         case EntryPoint::EGLSwapBuffers:
5548             // Skip these calls because:
5549             // - Swap is handled specially by the trace harness.
5550             return true;
5551 
5552         default:
5553             break;
5554     }
5555 
5556     return false;
5557 }
5558 
PageRange(size_t start,size_t end)5559 PageRange::PageRange(size_t start, size_t end) : start(start), end(end) {}
5560 PageRange::~PageRange() = default;
5561 
AddressRange()5562 AddressRange::AddressRange() {}
AddressRange(uintptr_t start,size_t size)5563 AddressRange::AddressRange(uintptr_t start, size_t size) : start(start), size(size) {}
5564 AddressRange::~AddressRange() = default;
5565 
end()5566 uintptr_t AddressRange::end()
5567 {
5568     return start + size;
5569 }
5570 
IsTrackedPerContext(ResourceIDType type)5571 bool IsTrackedPerContext(ResourceIDType type)
5572 {
5573     // This helper function informs us which context-local (not shared) objects are tracked
5574     // with per-context object maps.
5575     if (IsSharedObjectResource(type))
5576     {
5577         return false;
5578     }
5579 
5580     // TODO (https://issuetracker.google.com/169868803): Remaining context-local resources (VAOs,
5581     // PPOs, Transform Feedback Objects, and Query Objects) must also tracked per-context. Once all
5582     // per-context resource handling is correctly updated then this function can be replaced with
5583     // !IsSharedObjectResource().
5584     switch (type)
5585     {
5586         case ResourceIDType::Framebuffer:
5587             return true;
5588 
5589         default:
5590             return false;
5591     }
5592 }
5593 
CoherentBuffer(uintptr_t start,size_t size,size_t pageSize,bool isShadowMemoryEnabled)5594 CoherentBuffer::CoherentBuffer(uintptr_t start,
5595                                size_t size,
5596                                size_t pageSize,
5597                                bool isShadowMemoryEnabled)
5598     : mPageSize(pageSize),
5599       mShadowMemoryEnabled(isShadowMemoryEnabled),
5600       mBufferStart(start),
5601       mShadowMemory(nullptr),
5602       mShadowDirty(false)
5603 {
5604     if (mShadowMemoryEnabled)
5605     {
5606         // Shadow memory needs to have at least the size of one page, to not protect outside.
5607         size_t numShadowPages = (size / pageSize) + 1;
5608         mShadowMemory         = AlignedAlloc(numShadowPages * pageSize, pageSize);
5609         ASSERT(mShadowMemory != nullptr);
5610         start = reinterpret_cast<uintptr_t>(mShadowMemory);
5611     }
5612 
5613     mRange.start           = start;
5614     mRange.size            = size;
5615     mProtectionRange.start = rx::roundDownPow2(start, pageSize);
5616 
5617     uintptr_t protectionEnd = rx::roundUpPow2(start + size, pageSize);
5618 
5619     mProtectionRange.size = protectionEnd - mProtectionRange.start;
5620     mPageCount            = mProtectionRange.size / pageSize;
5621 
5622     mProtectionStartPage = mProtectionRange.start / mPageSize;
5623     mProtectionEndPage   = mProtectionStartPage + mPageCount;
5624 
5625     mDirtyPages = std::vector<bool>(mPageCount);
5626     mDirtyPages.assign(mPageCount, true);
5627 }
5628 
getDirtyPageRanges()5629 std::vector<PageRange> CoherentBuffer::getDirtyPageRanges()
5630 {
5631     std::vector<PageRange> dirtyPageRanges;
5632 
5633     bool inDirty = false;
5634     for (size_t i = 0; i < mPageCount; i++)
5635     {
5636         if (!inDirty && mDirtyPages[i])
5637         {
5638             // Found start of a dirty range
5639             inDirty = true;
5640             // Set end page as last page initially
5641             dirtyPageRanges.push_back(PageRange(i, mPageCount));
5642         }
5643         else if (inDirty && !mDirtyPages[i])
5644         {
5645             // Found end of a dirty range
5646             inDirty                    = false;
5647             dirtyPageRanges.back().end = i;
5648         }
5649     }
5650 
5651     return dirtyPageRanges;
5652 }
5653 
getRange()5654 AddressRange CoherentBuffer::getRange()
5655 {
5656     return mRange;
5657 }
5658 
getDirtyAddressRange(const PageRange & dirtyPageRange)5659 AddressRange CoherentBuffer::getDirtyAddressRange(const PageRange &dirtyPageRange)
5660 {
5661     AddressRange range;
5662 
5663     if (dirtyPageRange.start == 0)
5664     {
5665         // First page, use non page aligned buffer start.
5666         range.start = mRange.start;
5667     }
5668     else
5669     {
5670         range.start = mProtectionRange.start + dirtyPageRange.start * mPageSize;
5671     }
5672 
5673     if (dirtyPageRange.end == mPageCount)
5674     {
5675         // Last page, use non page aligned buffer end.
5676         range.size = mRange.end() - range.start;
5677     }
5678     else
5679     {
5680         range.size = (dirtyPageRange.end - dirtyPageRange.start) * mPageSize;
5681         // This occurs when a buffer occupies 2 pages, but is smaller than a page.
5682         if (mRange.end() < range.end())
5683         {
5684             range.size = mRange.end() - range.start;
5685         }
5686     }
5687 
5688     // Dirty range must be in buffer
5689     ASSERT(range.start >= mRange.start && mRange.end() >= range.end());
5690 
5691     return range;
5692 }
5693 
~CoherentBuffer()5694 CoherentBuffer::~CoherentBuffer()
5695 {
5696     if (mShadowMemory != nullptr)
5697     {
5698         AlignedFree(mShadowMemory);
5699     }
5700 }
5701 
isDirty()5702 bool CoherentBuffer::isDirty()
5703 {
5704     return std::find(mDirtyPages.begin(), mDirtyPages.end(), true) != mDirtyPages.end();
5705 }
5706 
contains(size_t page,size_t * relativePage)5707 bool CoherentBuffer::contains(size_t page, size_t *relativePage)
5708 {
5709     bool isInProtectionRange = page >= mProtectionStartPage && page < mProtectionEndPage;
5710     if (!isInProtectionRange)
5711     {
5712         return false;
5713     }
5714 
5715     *relativePage = page - mProtectionStartPage;
5716 
5717     ASSERT(page >= mProtectionStartPage);
5718 
5719     return true;
5720 }
5721 
protectPageRange(const PageRange & pageRange)5722 void CoherentBuffer::protectPageRange(const PageRange &pageRange)
5723 {
5724     for (size_t i = pageRange.start; i < pageRange.end; i++)
5725     {
5726         setDirty(i, false);
5727     }
5728 }
5729 
protectAll()5730 void CoherentBuffer::protectAll()
5731 {
5732     for (size_t i = 0; i < mPageCount; i++)
5733     {
5734         setDirty(i, false);
5735     }
5736 }
5737 
updateBufferMemory()5738 void CoherentBuffer::updateBufferMemory()
5739 {
5740     memcpy(reinterpret_cast<void *>(mBufferStart), reinterpret_cast<void *>(mRange.start),
5741            mRange.size);
5742 }
5743 
updateShadowMemory()5744 void CoherentBuffer::updateShadowMemory()
5745 {
5746     memcpy(reinterpret_cast<void *>(mRange.start), reinterpret_cast<void *>(mBufferStart),
5747            mRange.size);
5748     mShadowDirty = false;
5749 }
5750 
setDirty(size_t relativePage,bool dirty)5751 void CoherentBuffer::setDirty(size_t relativePage, bool dirty)
5752 {
5753     if (mDirtyPages[relativePage] == dirty)
5754     {
5755         // The page is already set.
5756         // This can happen when tracked buffers overlap in a page.
5757         return;
5758     }
5759 
5760     uintptr_t pageStart = mProtectionRange.start + relativePage * mPageSize;
5761 
5762     // Last page end must be the same as protection end
5763     if (relativePage + 1 == mPageCount)
5764     {
5765         ASSERT(mProtectionRange.end() == pageStart + mPageSize);
5766     }
5767 
5768     bool ret;
5769     if (dirty)
5770     {
5771         ret = UnprotectMemory(pageStart, mPageSize);
5772     }
5773     else
5774     {
5775         ret = ProtectMemory(pageStart, mPageSize);
5776     }
5777 
5778     if (!ret)
5779     {
5780         ERR() << "Could not set protection for buffer page " << relativePage << " at "
5781               << reinterpret_cast<void *>(pageStart) << " with size " << mPageSize;
5782     }
5783     mDirtyPages[relativePage] = dirty;
5784 }
5785 
removeProtection(PageSharingType sharingType)5786 void CoherentBuffer::removeProtection(PageSharingType sharingType)
5787 {
5788     uintptr_t start = mProtectionRange.start;
5789     size_t size     = mProtectionRange.size;
5790 
5791     switch (sharingType)
5792     {
5793         case PageSharingType::FirstShared:
5794         case PageSharingType::FirstAndLastShared:
5795             start += mPageSize;
5796             break;
5797         default:
5798             break;
5799     }
5800 
5801     switch (sharingType)
5802     {
5803         case PageSharingType::FirstShared:
5804         case PageSharingType::LastShared:
5805             size -= mPageSize;
5806             break;
5807         case PageSharingType::FirstAndLastShared:
5808             size -= (2 * mPageSize);
5809             break;
5810         default:
5811             break;
5812     }
5813 
5814     if (size == 0)
5815     {
5816         return;
5817     }
5818 
5819     if (!UnprotectMemory(start, size))
5820     {
5821         ERR() << "Could not remove protection for buffer at " << start << " with size " << size;
5822     }
5823 }
5824 
canProtectDirectly(gl::Context * context)5825 bool CoherentBufferTracker::canProtectDirectly(gl::Context *context)
5826 {
5827     gl::BufferID bufferId = context->createBuffer();
5828 
5829     gl::BufferBinding targetPacked = gl::BufferBinding::Array;
5830     context->bindBuffer(targetPacked, bufferId);
5831 
5832     // Allocate 2 pages so we will always have a full aligned page to protect
5833     GLsizei size = static_cast<GLsizei>(mPageSize * 2);
5834 
5835     context->bufferStorage(targetPacked, size, nullptr,
5836                            GL_DYNAMIC_STORAGE_BIT_EXT | GL_MAP_WRITE_BIT |
5837                                GL_MAP_PERSISTENT_BIT_EXT | GL_MAP_COHERENT_BIT_EXT);
5838 
5839     gl::Buffer *buffer = context->getBuffer(bufferId);
5840 
5841     angle::Result result = buffer->mapRange(
5842         context, 0, size, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT_EXT | GL_MAP_COHERENT_BIT_EXT);
5843     if (result != angle::Result::Continue)
5844     {
5845         ERR() << "Failed to mapRange of buffer.";
5846     }
5847 
5848     void *map = buffer->getMapPointer();
5849     if (map == nullptr)
5850     {
5851         ERR() << "Failed to getMapPointer of buffer.";
5852     }
5853 
5854     // Test mprotect
5855     auto start = reinterpret_cast<uintptr_t>(map);
5856 
5857     // Only protect a whole page inside the allocated memory
5858     uintptr_t protectionStart = rx::roundUpPow2(start, mPageSize);
5859     uintptr_t protectionEnd   = protectionStart + mPageSize;
5860 
5861     ASSERT(protectionStart < protectionEnd);
5862 
5863     angle::PageFaultCallback callback = [](uintptr_t address) {
5864         return angle::PageFaultHandlerRangeType::InRange;
5865     };
5866 
5867     std::unique_ptr<angle::PageFaultHandler> handler(CreatePageFaultHandler(callback));
5868 
5869     if (!handler->enable())
5870     {
5871         GLboolean unmapResult;
5872         if (buffer->unmap(context, &unmapResult) != angle::Result::Continue)
5873         {
5874             ERR() << "Could not unmap buffer.";
5875         }
5876         context->bindBuffer(targetPacked, {0});
5877 
5878         // Page fault handler could not be enabled, memory can't be protected directly.
5879         return false;
5880     }
5881 
5882     size_t protectionSize = protectionEnd - protectionStart;
5883 
5884     ASSERT(protectionSize == mPageSize);
5885 
5886     bool canProtect = angle::ProtectMemory(protectionStart, protectionSize);
5887     if (canProtect)
5888     {
5889         angle::UnprotectMemory(protectionStart, protectionSize);
5890     }
5891 
5892     // Clean up
5893     handler->disable();
5894 
5895     GLboolean unmapResult;
5896     if (buffer->unmap(context, &unmapResult) != angle::Result::Continue)
5897     {
5898         ERR() << "Could not unmap buffer.";
5899     }
5900     context->bindBuffer(targetPacked, {0});
5901     context->deleteBuffer(buffer->id());
5902 
5903     return canProtect;
5904 }
5905 
handleWrite(uintptr_t address)5906 PageFaultHandlerRangeType CoherentBufferTracker::handleWrite(uintptr_t address)
5907 {
5908     std::lock_guard<angle::SimpleMutex> lock(mMutex);
5909     auto pagesInBuffers = getBufferPagesForAddress(address);
5910 
5911     if (pagesInBuffers.empty())
5912     {
5913         ERR() << "Didn't find a tracked buffer containing " << reinterpret_cast<void *>(address);
5914     }
5915 
5916     for (const auto &page : pagesInBuffers)
5917     {
5918         std::shared_ptr<CoherentBuffer> buffer = page.first;
5919         size_t relativePage                    = page.second;
5920         buffer->setDirty(relativePage, true);
5921     }
5922 
5923     return pagesInBuffers.empty() ? PageFaultHandlerRangeType::OutOfRange
5924                                   : PageFaultHandlerRangeType::InRange;
5925 }
5926 
getBufferPagesForAddress(uintptr_t address)5927 HashMap<std::shared_ptr<CoherentBuffer>, size_t> CoherentBufferTracker::getBufferPagesForAddress(
5928     uintptr_t address)
5929 {
5930     HashMap<std::shared_ptr<CoherentBuffer>, size_t> foundPages;
5931 
5932 #if defined(ANGLE_PLATFORM_ANDROID)
5933     size_t page;
5934     if (mShadowMemoryEnabled)
5935     {
5936         // Starting with Android 11 heap pointers get a tag which is stripped by the POSIX mprotect
5937         // callback. We need to add this tag manually to the untagged pointer in order to determine
5938         // the corresponding page.
5939         // See: https://source.android.com/docs/security/test/tagged-pointers
5940         // TODO(http://anglebug.com/42265874): Determine when heap pointer tagging is not enabled.
5941         constexpr unsigned long long POINTER_TAG = 0xb400000000000000;
5942         unsigned long long taggedAddress         = address | POINTER_TAG;
5943         page                                     = static_cast<size_t>(taggedAddress / mPageSize);
5944     }
5945     else
5946     {
5947         // VMA allocated memory pointers are not tagged.
5948         page = address / mPageSize;
5949     }
5950 #else
5951     size_t page = address / mPageSize;
5952 #endif
5953 
5954     for (const auto &pair : mBuffers)
5955     {
5956         std::shared_ptr<CoherentBuffer> buffer = pair.second;
5957         size_t relativePage;
5958         if (buffer->contains(page, &relativePage))
5959         {
5960             foundPages.insert(std::make_pair(buffer, relativePage));
5961         }
5962     }
5963 
5964     return foundPages;
5965 }
5966 
isDirty(gl::BufferID id)5967 bool CoherentBufferTracker::isDirty(gl::BufferID id)
5968 {
5969     return mBuffers[id.value]->isDirty();
5970 }
5971 
enable()5972 void CoherentBufferTracker::enable()
5973 {
5974     if (mEnabled)
5975     {
5976         return;
5977     }
5978 
5979     PageFaultCallback callback = [this](uintptr_t address) { return handleWrite(address); };
5980 
5981     // This needs to be initialized after canProtectDirectly ran and can only be initialized once.
5982     if (!mPageFaultHandler)
5983     {
5984         mPageFaultHandler = std::unique_ptr<PageFaultHandler>(CreatePageFaultHandler(callback));
5985     }
5986 
5987     bool ret = mPageFaultHandler->enable();
5988     if (ret)
5989     {
5990         mEnabled = true;
5991     }
5992     else
5993     {
5994         ERR() << "Could not enable page fault handler.";
5995     }
5996 }
5997 
haveBuffer(gl::BufferID id)5998 bool CoherentBufferTracker::haveBuffer(gl::BufferID id)
5999 {
6000     return mBuffers.find(id.value) != mBuffers.end();
6001 }
6002 
onEndFrame()6003 void CoherentBufferTracker::onEndFrame()
6004 {
6005     std::lock_guard<angle::SimpleMutex> lock(mMutex);
6006 
6007     if (!mEnabled)
6008     {
6009         return;
6010     }
6011 
6012     mHasBeenReset = true;
6013 
6014     // Remove protection from all buffers
6015     for (const auto &pair : mBuffers)
6016     {
6017         std::shared_ptr<CoherentBuffer> buffer = pair.second;
6018         buffer->removeProtection(PageSharingType::NoneShared);
6019     }
6020 
6021     disable();
6022 }
6023 
addBuffer(gl::BufferID id,uintptr_t start,size_t size)6024 uintptr_t CoherentBufferTracker::addBuffer(gl::BufferID id, uintptr_t start, size_t size)
6025 {
6026     std::lock_guard<angle::SimpleMutex> lock(mMutex);
6027 
6028     if (haveBuffer(id))
6029     {
6030         auto buffer = mBuffers[id.value];
6031         return buffer->getRange().start;
6032     }
6033 
6034     auto buffer = std::make_shared<CoherentBuffer>(start, size, mPageSize, mShadowMemoryEnabled);
6035     uintptr_t realOrShadowStart = buffer->getRange().start;
6036 
6037     mBuffers.insert(std::make_pair(id.value, std::move(buffer)));
6038 
6039     return realOrShadowStart;
6040 }
6041 
maybeUpdateShadowMemory()6042 void CoherentBufferTracker::maybeUpdateShadowMemory()
6043 {
6044     for (const auto &pair : mBuffers)
6045     {
6046         std::shared_ptr<CoherentBuffer> cb = pair.second;
6047         if (cb->isShadowDirty())
6048         {
6049             cb->removeProtection(PageSharingType::NoneShared);
6050             cb->updateShadowMemory();
6051             cb->protectAll();
6052         }
6053     }
6054 }
6055 
markAllShadowDirty()6056 void CoherentBufferTracker::markAllShadowDirty()
6057 {
6058     for (const auto &pair : mBuffers)
6059     {
6060         std::shared_ptr<CoherentBuffer> cb = pair.second;
6061         cb->markShadowDirty();
6062     }
6063 }
6064 
doesBufferSharePage(gl::BufferID id)6065 PageSharingType CoherentBufferTracker::doesBufferSharePage(gl::BufferID id)
6066 {
6067     bool firstPageShared = false;
6068     bool lastPageShared  = false;
6069 
6070     std::shared_ptr<CoherentBuffer> buffer = mBuffers[id.value];
6071 
6072     AddressRange range = buffer->getRange();
6073 
6074     size_t firstPage = range.start / mPageSize;
6075     size_t lastPage  = range.end() / mPageSize;
6076 
6077     for (const auto &pair : mBuffers)
6078     {
6079         gl::BufferID otherId = {pair.first};
6080         if (otherId != id)
6081         {
6082             std::shared_ptr<CoherentBuffer> otherBuffer = pair.second;
6083             size_t relativePage;
6084             if (otherBuffer->contains(firstPage, &relativePage))
6085             {
6086                 firstPageShared = true;
6087             }
6088             else if (otherBuffer->contains(lastPage, &relativePage))
6089             {
6090                 lastPageShared = true;
6091             }
6092         }
6093     }
6094 
6095     if (firstPageShared && !lastPageShared)
6096     {
6097         return PageSharingType::FirstShared;
6098     }
6099     else if (!firstPageShared && lastPageShared)
6100     {
6101         return PageSharingType::LastShared;
6102     }
6103     else if (firstPageShared && lastPageShared)
6104     {
6105         return PageSharingType::FirstAndLastShared;
6106     }
6107     else
6108     {
6109         return PageSharingType::NoneShared;
6110     }
6111 }
6112 
removeBuffer(gl::BufferID id)6113 void CoherentBufferTracker::removeBuffer(gl::BufferID id)
6114 {
6115     std::lock_guard<angle::SimpleMutex> lock(mMutex);
6116 
6117     if (!haveBuffer(id))
6118     {
6119         return;
6120     }
6121 
6122     // Synchronize graphics buffer memory before the buffer is removed from the tracker.
6123     if (mShadowMemoryEnabled)
6124     {
6125         mBuffers[id.value]->updateBufferMemory();
6126     }
6127 
6128     // If the buffer shares pages with other tracked buffers,
6129     // don't unprotect the overlapping pages.
6130     PageSharingType sharingType = doesBufferSharePage(id);
6131     mBuffers[id.value]->removeProtection(sharingType);
6132     mBuffers.erase(id.value);
6133 }
6134 
maybeGetShadowMemoryPointer(gl::Buffer * buffer,GLsizeiptr length,GLbitfield access)6135 void *FrameCaptureShared::maybeGetShadowMemoryPointer(gl::Buffer *buffer,
6136                                                       GLsizeiptr length,
6137                                                       GLbitfield access)
6138 {
6139     if (!(access & GL_MAP_COHERENT_BIT_EXT) || !mCoherentBufferTracker.isShadowMemoryEnabled())
6140     {
6141         return buffer->getMapPointer();
6142     }
6143 
6144     mCoherentBufferTracker.enable();
6145     uintptr_t realMapPointer = reinterpret_cast<uintptr_t>(buffer->getMapPointer());
6146     return (void *)mCoherentBufferTracker.addBuffer(buffer->id(), realMapPointer, length);
6147 }
6148 
determineMemoryProtectionSupport(gl::Context * context)6149 void FrameCaptureShared::determineMemoryProtectionSupport(gl::Context *context)
6150 {
6151     // Skip this test if shadow memory was force enabled or shadow memory requirement was detected
6152     // previously
6153     if (mCoherentBufferTracker.isShadowMemoryEnabled())
6154     {
6155         return;
6156     }
6157 
6158     // These known devices must use shadow memory
6159     HashMap<std::string, std::vector<std::string>> denyList = {
6160         {"Google", {"Pixel 6", "Pixel 6 Pro", "Pixel 6a", "Pixel 7", "Pixel 7 Pro"}},
6161     };
6162 
6163     angle::SystemInfo info;
6164     angle::GetSystemInfo(&info);
6165     bool isDeviceDenyListed = false;
6166 
6167     if (rx::GetAndroidSDKVersion() < 34)
6168     {
6169         // Before Android 14, there was a bug in Mali based Pixel preventing mprotect
6170         // on Vulkan surfaces. (https://b.corp.google.com/issues/269535398)
6171         // Check the denylist in this case.
6172         if (denyList.find(info.machineManufacturer) != denyList.end())
6173         {
6174             const std::vector<std::string> &models = denyList[info.machineManufacturer];
6175             isDeviceDenyListed =
6176                 std::find(models.begin(), models.end(), info.machineModelName) != models.end();
6177         }
6178     }
6179 
6180     if (isDeviceDenyListed)
6181     {
6182         WARN() << "Direct memory protection not possible on deny listed device '"
6183                << info.machineModelName
6184                << "', enabling shadow memory for coherent buffer tracking.";
6185         mCoherentBufferTracker.enableShadowMemory();
6186     }
6187     else
6188     {
6189         // Device is not on deny listed. Run a test if we actually can protect directly. Do this
6190         // only on assertion enabled builds.
6191         ASSERT(mCoherentBufferTracker.canProtectDirectly(context));
6192     }
6193 }
6194 
trackBufferMapping(const gl::Context * context,CallCapture * call,gl::BufferID id,gl::Buffer * buffer,GLintptr offset,GLsizeiptr length,bool writable,bool coherent)6195 void FrameCaptureShared::trackBufferMapping(const gl::Context *context,
6196                                             CallCapture *call,
6197                                             gl::BufferID id,
6198                                             gl::Buffer *buffer,
6199                                             GLintptr offset,
6200                                             GLsizeiptr length,
6201                                             bool writable,
6202                                             bool coherent)
6203 {
6204     // Track that the buffer was mapped
6205     mResourceTracker.setBufferMapped(context->id(), id.value);
6206 
6207     if (writable)
6208     {
6209         // If this buffer was mapped writable, we don't have any visibility into what
6210         // happens to it. Therefore, remember the details about it, and we'll read it back
6211         // on Unmap to repopulate it during replay.
6212         mBufferDataMap[id] = std::make_pair(offset, length);
6213 
6214         // Track that this buffer was potentially modified
6215         mResourceTracker.getTrackedResource(context->id(), ResourceIDType::Buffer)
6216             .setModifiedResource(id.value);
6217 
6218         // Track coherent buffer
6219         // Check if capture is active to not initialize the coherent buffer tracker on the
6220         // first coherent glMapBufferRange call.
6221         if (coherent && isCaptureActive())
6222         {
6223             if (mCoherentBufferTracker.hasBeenReset())
6224             {
6225                 FATAL() << "Multi-capture not supprted for apps using persistent coherent memory";
6226             }
6227 
6228             mCoherentBufferTracker.enable();
6229             // When not using shadow memory, adding buffers to the tracking happens here instead of
6230             // during mapping
6231             if (!mCoherentBufferTracker.isShadowMemoryEnabled())
6232             {
6233                 uintptr_t data = reinterpret_cast<uintptr_t>(buffer->getMapPointer());
6234                 mCoherentBufferTracker.addBuffer(id, data, length);
6235             }
6236         }
6237     }
6238 }
6239 
trackTextureUpdate(const gl::Context * context,const CallCapture & call)6240 void FrameCaptureShared::trackTextureUpdate(const gl::Context *context, const CallCapture &call)
6241 {
6242     int index             = 0;
6243     std::string paramName = "targetPacked";
6244     ParamType paramType   = ParamType::TTextureTarget;
6245 
6246     // Some calls provide the textureID directly
6247     // For the rest, look it up based on the currently bound texture
6248     switch (call.entryPoint)
6249     {
6250         case EntryPoint::GLCompressedCopyTextureCHROMIUM:
6251             index     = 1;
6252             paramName = "destIdPacked";
6253             paramType = ParamType::TTextureID;
6254             break;
6255         case EntryPoint::GLCopyTextureCHROMIUM:
6256         case EntryPoint::GLCopySubTextureCHROMIUM:
6257         case EntryPoint::GLCopyTexture3DANGLE:
6258             index     = 3;
6259             paramName = "destIdPacked";
6260             paramType = ParamType::TTextureID;
6261             break;
6262         case EntryPoint::GLCopyImageSubData:
6263         case EntryPoint::GLCopyImageSubDataEXT:
6264         case EntryPoint::GLCopyImageSubDataOES:
6265             index     = 7;
6266             paramName = "dstTarget";
6267             paramType = ParamType::TGLenum;
6268             break;
6269         default:
6270             break;
6271     }
6272 
6273     GLuint id = 0;
6274     switch (paramType)
6275     {
6276         case ParamType::TTextureTarget:
6277         {
6278             gl::TextureTarget targetPacked =
6279                 call.params.getParam(paramName.c_str(), ParamType::TTextureTarget, index)
6280                     .value.TextureTargetVal;
6281             gl::TextureType textureType = gl::TextureTargetToType(targetPacked);
6282             gl::Texture *texture        = context->getState().getTargetTexture(textureType);
6283             id                          = texture->id().value;
6284             break;
6285         }
6286         case ParamType::TTextureID:
6287         {
6288             gl::TextureID destIDPacked =
6289                 call.params.getParam(paramName.c_str(), ParamType::TTextureID, index)
6290                     .value.TextureIDVal;
6291             id = destIDPacked.value;
6292             break;
6293         }
6294         case ParamType::TGLenum:
6295         {
6296             GLenum target =
6297                 call.params.getParam(paramName.c_str(), ParamType::TGLenum, index).value.GLenumVal;
6298 
6299             if (target == GL_TEXTURE_CUBE_MAP)
6300             {
6301                 // CopyImageSubData doesn't support cube faces, but PackedParams requires one
6302                 target = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
6303             }
6304 
6305             gl::TextureTarget targetPacked = gl::PackParam<gl::TextureTarget>(target);
6306             gl::TextureType textureType    = gl::TextureTargetToType(targetPacked);
6307             gl::Texture *texture           = context->getState().getTargetTexture(textureType);
6308             id                             = texture->id().value;
6309             break;
6310         }
6311         default:
6312             ERR() << "Unhandled paramType= " << static_cast<int>(paramType);
6313             UNREACHABLE();
6314             break;
6315     }
6316 
6317     // Mark it as modified
6318     mResourceTracker.getTrackedResource(context->id(), ResourceIDType::Texture)
6319         .setModifiedResource(id);
6320 }
6321 
6322 // Identify and mark writeable shader image textures as modified
trackImageUpdate(const gl::Context * context,const CallCapture & call)6323 void FrameCaptureShared::trackImageUpdate(const gl::Context *context, const CallCapture &call)
6324 {
6325     const gl::ProgramExecutable *executable = context->getState().getProgramExecutable();
6326     for (const gl::ImageBinding &imageBinding : executable->getImageBindings())
6327     {
6328         for (GLuint binding : imageBinding.boundImageUnits)
6329         {
6330             const gl::ImageUnit &imageUnit = context->getState().getImageUnit(binding);
6331             if (imageUnit.access != GL_READ_ONLY)
6332             {
6333                 // Get image binding texture id and mark it as modified
6334                 GLuint id = imageUnit.texture.id().value;
6335                 mResourceTracker.getTrackedResource(context->id(), ResourceIDType::Texture)
6336                     .setModifiedResource(id);
6337             }
6338         }
6339     }
6340 }
6341 
trackDefaultUniformUpdate(const gl::Context * context,const CallCapture & call)6342 void FrameCaptureShared::trackDefaultUniformUpdate(const gl::Context *context,
6343                                                    const CallCapture &call)
6344 {
6345     DefaultUniformType defaultUniformType = GetDefaultUniformType(call);
6346 
6347     GLuint programID = 0;
6348     int location     = 0;
6349 
6350     // We track default uniform updates by program and location, so look them up in parameters
6351     if (defaultUniformType == DefaultUniformType::CurrentProgram)
6352     {
6353         programID = context->getActiveLinkedProgram()->id().value;
6354 
6355         location = call.params.getParam("locationPacked", ParamType::TUniformLocation, 0)
6356                        .value.UniformLocationVal.value;
6357     }
6358     else
6359     {
6360         ASSERT(defaultUniformType == DefaultUniformType::SpecifiedProgram);
6361 
6362         programID = call.params.getParam("programPacked", ParamType::TShaderProgramID, 0)
6363                         .value.ShaderProgramIDVal.value;
6364 
6365         location = call.params.getParam("locationPacked", ParamType::TUniformLocation, 1)
6366                        .value.UniformLocationVal.value;
6367     }
6368 
6369     const TrackedResource &trackedShaderProgram =
6370         mResourceTracker.getTrackedResource(context->id(), ResourceIDType::ShaderProgram);
6371     const ResourceSet &startingPrograms = trackedShaderProgram.getStartingResources();
6372     const ResourceSet &programsToRegen  = trackedShaderProgram.getResourcesToRegen();
6373 
6374     // If this program was in our starting set, track its uniform updates. Unless it was deleted,
6375     // then its uniforms will all be regenned along wih with the program.
6376     if (startingPrograms.find(programID) != startingPrograms.end() &&
6377         programsToRegen.find(programID) == programsToRegen.end())
6378     {
6379         // Track that we need to set this default uniform value again
6380         mResourceTracker.setModifiedDefaultUniform({programID}, {location});
6381     }
6382 }
6383 
trackVertexArrayUpdate(const gl::Context * context,const CallCapture & call)6384 void FrameCaptureShared::trackVertexArrayUpdate(const gl::Context *context, const CallCapture &call)
6385 {
6386     // Look up the currently bound vertex array
6387     gl::VertexArrayID id = context->getState().getVertexArray()->id();
6388 
6389     // Mark it as modified
6390     mResourceTracker.getTrackedResource(context->id(), ResourceIDType::VertexArray)
6391         .setModifiedResource(id.value);
6392 }
6393 
updateCopyImageSubData(CallCapture & call)6394 void FrameCaptureShared::updateCopyImageSubData(CallCapture &call)
6395 {
6396     // This call modifies srcName and dstName to no longer be object IDs (GLuint), but actual
6397     // packed types that can remapped using gTextureMap and gRenderbufferMap
6398 
6399     GLint srcName    = call.params.getParam("srcName", ParamType::TGLuint, 0).value.GLuintVal;
6400     GLenum srcTarget = call.params.getParam("srcTarget", ParamType::TGLenum, 1).value.GLenumVal;
6401     switch (srcTarget)
6402     {
6403         case GL_RENDERBUFFER:
6404         {
6405             // Convert the GLuint to RenderbufferID
6406             gl::RenderbufferID srcRenderbufferID = {static_cast<GLuint>(srcName)};
6407             call.params.setValueParamAtIndex("srcName", ParamType::TRenderbufferID,
6408                                              srcRenderbufferID, 0);
6409             break;
6410         }
6411         case GL_TEXTURE_2D:
6412         case GL_TEXTURE_2D_ARRAY:
6413         case GL_TEXTURE_3D:
6414         case GL_TEXTURE_CUBE_MAP:
6415         case GL_TEXTURE_EXTERNAL_OES:
6416         case GL_TEXTURE_2D_MULTISAMPLE:
6417         case GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES:
6418         {
6419             // Convert the GLuint to TextureID
6420             gl::TextureID srcTextureID = {static_cast<GLuint>(srcName)};
6421             call.params.setValueParamAtIndex("srcName", ParamType::TTextureID, srcTextureID, 0);
6422             break;
6423         }
6424         default:
6425             ERR() << "Unhandled srcTarget = " << srcTarget;
6426             UNREACHABLE();
6427             break;
6428     }
6429 
6430     // Change dstName to the appropriate type based on dstTarget
6431     GLint dstName    = call.params.getParam("dstName", ParamType::TGLuint, 6).value.GLuintVal;
6432     GLenum dstTarget = call.params.getParam("dstTarget", ParamType::TGLenum, 7).value.GLenumVal;
6433     switch (dstTarget)
6434     {
6435         case GL_RENDERBUFFER:
6436         {
6437             // Convert the GLuint to RenderbufferID
6438             gl::RenderbufferID dstRenderbufferID = {static_cast<GLuint>(dstName)};
6439             call.params.setValueParamAtIndex("dstName", ParamType::TRenderbufferID,
6440                                              dstRenderbufferID, 6);
6441             break;
6442         }
6443         case GL_TEXTURE_2D:
6444         case GL_TEXTURE_2D_ARRAY:
6445         case GL_TEXTURE_3D:
6446         case GL_TEXTURE_CUBE_MAP:
6447         case GL_TEXTURE_EXTERNAL_OES:
6448         case GL_TEXTURE_2D_MULTISAMPLE:
6449         case GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES:
6450         {
6451             // Convert the GLuint to TextureID
6452             gl::TextureID dstTextureID = {static_cast<GLuint>(dstName)};
6453             call.params.setValueParamAtIndex("dstName", ParamType::TTextureID, dstTextureID, 6);
6454             break;
6455         }
6456         default:
6457             ERR() << "Unhandled dstTarget = " << dstTarget;
6458             UNREACHABLE();
6459             break;
6460     }
6461 }
6462 
overrideProgramBinary(const gl::Context * context,CallCapture & inCall,std::vector<CallCapture> & outCalls)6463 void FrameCaptureShared::overrideProgramBinary(const gl::Context *context,
6464                                                CallCapture &inCall,
6465                                                std::vector<CallCapture> &outCalls)
6466 {
6467     // Program binaries are inherently non-portable, even between two ANGLE builds.
6468     // If an application is using glProgramBinary in the middle of a trace, we need to replace
6469     // those calls with an equivalent sequence of portable calls.
6470     //
6471     // For example, here is a sequence an app could use for glProgramBinary:
6472     //
6473     //   gShaderProgramMap[42] = glCreateProgram();
6474     //   glProgramBinary(gShaderProgramMap[42], GL_PROGRAM_BINARY_ANGLE, gBinaryData[x], 1000);
6475     //   glGetProgramiv(gShaderProgramMap[42], GL_LINK_STATUS, gReadBuffer);
6476     //   glGetProgramiv(gShaderProgramMap[42], GL_PROGRAM_BINARY_LENGTH, gReadBuffer);
6477     //
6478     // With this override, the glProgramBinary call will be replaced like so:
6479     //
6480     //   gShaderProgramMap[42] = glCreateProgram();
6481     //   === Begin override ===
6482     //   gShaderProgramMap[43] = glCreateShader(GL_VERTEX_SHADER);
6483     //   glShaderSource(gShaderProgramMap[43], 1, string_0, &gBinaryData[100]);
6484     //   glCompileShader(gShaderProgramMap[43]);
6485     //   glAttachShader(gShaderProgramMap[42], gShaderProgramMap[43]);
6486     //   glDeleteShader(gShaderProgramMap[43]);
6487     //   gShaderProgramMap[43] = glCreateShader(GL_FRAGMENT_SHADER);
6488     //   glShaderSource(gShaderProgramMap[43], 1, string_1, &gBinaryData[200]);
6489     //   glCompileShader(gShaderProgramMap[43]);
6490     //   glAttachShader(gShaderProgramMap[42], gShaderProgramMap[43]);
6491     //   glDeleteShader(gShaderProgramMap[43]);
6492     //   glBindAttribLocation(gShaderProgramMap[42], 0, "attrib1");
6493     //   glBindAttribLocation(gShaderProgramMap[42], 1, "attrib2");
6494     //   glLinkProgram(gShaderProgramMap[42]);
6495     //   UpdateUniformLocation(gShaderProgramMap[42], "foo", 0, 20);
6496     //   UpdateUniformLocation(gShaderProgramMap[42], "bar", 72, 1);
6497     //   glUseProgram(gShaderProgramMap[42]);
6498     //   UpdateCurrentProgram(gShaderProgramMap[42]);
6499     //   glUniform4fv(gUniformLocations[gCurrentProgram][0], 20, &gBinaryData[300]);
6500     //   glUniform1iv(gUniformLocations[gCurrentProgram][72], 1, &gBinaryData[400]);
6501     //   === End override ===
6502     //   glGetProgramiv(gShaderProgramMap[42], GL_LINK_STATUS, gReadBuffer);
6503     //   glGetProgramiv(gShaderProgramMap[42], GL_PROGRAM_BINARY_LENGTH, gReadBuffer);
6504     //
6505     // To facilitate this override, we are serializing each shader stage source into the binary
6506     // itself.  See Program::serialize and Program::deserialize.  Once extracted from the binary,
6507     // they will be available via getProgramSources.
6508 
6509     gl::ShaderProgramID id = inCall.params.getParam("programPacked", ParamType::TShaderProgramID, 0)
6510                                  .value.ShaderProgramIDVal;
6511 
6512     gl::Program *program = context->getProgramResolveLink(id);
6513     ASSERT(program);
6514 
6515     mResourceTracker.onShaderProgramAccess(id);
6516     gl::ShaderProgramID tempShaderStartID = {mResourceTracker.getMaxShaderPrograms()};
6517     GenerateLinkedProgram(context, context->getState(), &mResourceTracker, &outCalls, program, id,
6518                           tempShaderStartID, getProgramSources(id));
6519 }
6520 
captureCustomMapBufferFromContext(const gl::Context * context,const char * entryPointName,CallCapture & call,std::vector<CallCapture> & callsOut)6521 void FrameCaptureShared::captureCustomMapBufferFromContext(const gl::Context *context,
6522                                                            const char *entryPointName,
6523                                                            CallCapture &call,
6524                                                            std::vector<CallCapture> &callsOut)
6525 {
6526     gl::BufferBinding binding =
6527         call.params.getParam("targetPacked", ParamType::TBufferBinding, 0).value.BufferBindingVal;
6528     gl::Buffer *buffer = context->getState().getTargetBuffer(binding);
6529 
6530     if (call.entryPoint == EntryPoint::GLMapBufferRange ||
6531         call.entryPoint == EntryPoint::GLMapBufferRangeEXT)
6532     {
6533         GLintptr offset = call.params.getParam("offset", ParamType::TGLintptr, 1).value.GLintptrVal;
6534         GLsizeiptr length =
6535             call.params.getParam("length", ParamType::TGLsizeiptr, 2).value.GLsizeiptrVal;
6536         GLbitfield access =
6537             call.params.getParam("access", ParamType::TGLbitfield, 3).value.GLbitfieldVal;
6538 
6539         trackBufferMapping(context, &call, buffer->id(), buffer, offset, length,
6540                            access & GL_MAP_WRITE_BIT, access & GL_MAP_COHERENT_BIT_EXT);
6541     }
6542     else
6543     {
6544         ASSERT(call.entryPoint == EntryPoint::GLMapBufferOES);
6545         GLenum access = call.params.getParam("access", ParamType::TGLenum, 1).value.GLenumVal;
6546         bool writeAccess =
6547             (access == GL_WRITE_ONLY_OES || access == GL_WRITE_ONLY || access == GL_READ_WRITE);
6548         trackBufferMapping(context, &call, buffer->id(), buffer, 0,
6549                            static_cast<GLsizeiptr>(buffer->getSize()), writeAccess, false);
6550     }
6551 
6552     CaptureCustomMapBuffer(entryPointName, call, callsOut, buffer->id());
6553 }
6554 
maybeOverrideEntryPoint(const gl::Context * context,CallCapture & inCall,std::vector<CallCapture> & outCalls)6555 void FrameCaptureShared::maybeOverrideEntryPoint(const gl::Context *context,
6556                                                  CallCapture &inCall,
6557                                                  std::vector<CallCapture> &outCalls)
6558 {
6559     switch (inCall.entryPoint)
6560     {
6561         case EntryPoint::GLCopyImageSubData:
6562         case EntryPoint::GLCopyImageSubDataEXT:
6563         case EntryPoint::GLCopyImageSubDataOES:
6564         {
6565             // We must look at the src and dst target types to determine which remap table to use
6566             updateCopyImageSubData(inCall);
6567             outCalls.emplace_back(std::move(inCall));
6568             break;
6569         }
6570         case EntryPoint::GLProgramBinary:
6571         case EntryPoint::GLProgramBinaryOES:
6572         {
6573             // Binary formats are not portable at all, so replace the calls with full linking
6574             // sequence
6575             overrideProgramBinary(context, inCall, outCalls);
6576             break;
6577         }
6578         case EntryPoint::GLUniformBlockBinding:
6579         {
6580             CaptureCustomUniformBlockBinding(inCall, outCalls);
6581             break;
6582         }
6583         case EntryPoint::GLMapBufferRange:
6584         {
6585             captureCustomMapBufferFromContext(context, "MapBufferRange", inCall, outCalls);
6586             break;
6587         }
6588         case EntryPoint::GLMapBufferRangeEXT:
6589         {
6590             captureCustomMapBufferFromContext(context, "MapBufferRangeEXT", inCall, outCalls);
6591             break;
6592         }
6593         case EntryPoint::GLMapBufferOES:
6594         {
6595             captureCustomMapBufferFromContext(context, "MapBufferOES", inCall, outCalls);
6596             break;
6597         }
6598         case EntryPoint::GLCreateShader:
6599         {
6600             CaptureCustomShaderProgram("CreateShader", inCall, outCalls);
6601             break;
6602         }
6603         case EntryPoint::GLCreateProgram:
6604         {
6605             CaptureCustomShaderProgram("CreateProgram", inCall, outCalls);
6606             break;
6607         }
6608         case EntryPoint::GLCreateShaderProgramv:
6609         {
6610             CaptureCustomShaderProgram("CreateShaderProgramv", inCall, outCalls);
6611             break;
6612         }
6613         case EntryPoint::GLFenceSync:
6614         {
6615             CaptureCustomFenceSync(inCall, outCalls);
6616             break;
6617         }
6618         case EntryPoint::EGLCreateImage:
6619         {
6620             const egl::Image *eglImage = GetImageFromParam(context, inCall.params.getReturnValue());
6621             CaptureCustomCreateEGLImage(context, "CreateEGLImage", eglImage->getWidth(),
6622                                         eglImage->getHeight(), inCall, outCalls);
6623             break;
6624         }
6625         case EntryPoint::EGLCreateImageKHR:
6626         {
6627             const egl::Image *eglImage = GetImageFromParam(context, inCall.params.getReturnValue());
6628             CaptureCustomCreateEGLImage(context, "CreateEGLImageKHR", eglImage->getWidth(),
6629                                         eglImage->getHeight(), inCall, outCalls);
6630             break;
6631         }
6632         case EntryPoint::EGLDestroyImage:
6633         {
6634             CaptureCustomDestroyEGLImage("DestroyEGLImage", inCall, outCalls);
6635             break;
6636         }
6637         case EntryPoint::EGLDestroyImageKHR:
6638         {
6639             CaptureCustomDestroyEGLImage("DestroyEGLImageKHR", inCall, outCalls);
6640             break;
6641         }
6642         case EntryPoint::EGLCreateSync:
6643         {
6644             CaptureCustomCreateEGLSync("CreateEGLSync", inCall, outCalls);
6645             break;
6646         }
6647         case EntryPoint::EGLCreateSyncKHR:
6648         {
6649             CaptureCustomCreateEGLSync("CreateEGLSyncKHR", inCall, outCalls);
6650             break;
6651         }
6652         case EntryPoint::EGLCreatePbufferSurface:
6653         {
6654             CaptureCustomCreatePbufferSurface(inCall, outCalls);
6655             break;
6656         }
6657         case EntryPoint::EGLCreateNativeClientBufferANDROID:
6658         {
6659             CaptureCustomCreateNativeClientbuffer(inCall, outCalls);
6660             break;
6661         }
6662 
6663         default:
6664         {
6665             // Pass the single call through
6666             outCalls.emplace_back(std::move(inCall));
6667             break;
6668         }
6669     }
6670 }
6671 
maybeCaptureCoherentBuffers(const gl::Context * context)6672 void FrameCaptureShared::maybeCaptureCoherentBuffers(const gl::Context *context)
6673 {
6674     if (!isCaptureActive())
6675     {
6676         return;
6677     }
6678 
6679     std::lock_guard<angle::SimpleMutex> lock(mCoherentBufferTracker.mMutex);
6680 
6681     for (const auto &pair : mCoherentBufferTracker.mBuffers)
6682     {
6683         gl::BufferID id = {pair.first};
6684         if (mCoherentBufferTracker.isDirty(id))
6685         {
6686             captureCoherentBufferSnapshot(context, id);
6687         }
6688     }
6689 }
6690 
maybeCaptureDrawArraysClientData(const gl::Context * context,CallCapture & call,size_t instanceCount)6691 void FrameCaptureShared::maybeCaptureDrawArraysClientData(const gl::Context *context,
6692                                                           CallCapture &call,
6693                                                           size_t instanceCount)
6694 {
6695     if (!context->getStateCache().hasAnyActiveClientAttrib())
6696     {
6697         return;
6698     }
6699 
6700     // Get counts from paramBuffer.
6701     GLint firstVertex =
6702         call.params.getParamFlexName("first", "start", ParamType::TGLint, 1).value.GLintVal;
6703     GLsizei drawCount = call.params.getParam("count", ParamType::TGLsizei, 2).value.GLsizeiVal;
6704     captureClientArraySnapshot(context, firstVertex + drawCount, instanceCount);
6705 }
6706 
maybeCaptureDrawElementsClientData(const gl::Context * context,CallCapture & call,size_t instanceCount)6707 void FrameCaptureShared::maybeCaptureDrawElementsClientData(const gl::Context *context,
6708                                                             CallCapture &call,
6709                                                             size_t instanceCount)
6710 {
6711     if (!context->getStateCache().hasAnyActiveClientAttrib())
6712     {
6713         return;
6714     }
6715 
6716     // if the count is zero then the index evaluation is not valid and we wouldn't be drawing
6717     // anything anyway, so skip capturing
6718     GLsizei count = call.params.getParam("count", ParamType::TGLsizei, 1).value.GLsizeiVal;
6719     if (count == 0)
6720     {
6721         return;
6722     }
6723 
6724     gl::DrawElementsType drawElementsType =
6725         call.params.getParam("typePacked", ParamType::TDrawElementsType, 2)
6726             .value.DrawElementsTypeVal;
6727     const void *indices =
6728         call.params.getParam("indices", ParamType::TvoidConstPointer, 3).value.voidConstPointerVal;
6729 
6730     gl::IndexRange indexRange;
6731 
6732     bool restart = context->getState().isPrimitiveRestartEnabled();
6733 
6734     gl::Buffer *elementArrayBuffer = context->getState().getVertexArray()->getElementArrayBuffer();
6735     if (elementArrayBuffer)
6736     {
6737         size_t offset = reinterpret_cast<size_t>(indices);
6738         (void)elementArrayBuffer->getIndexRange(context, drawElementsType, offset, count, restart,
6739                                                 &indexRange);
6740     }
6741     else
6742     {
6743         ASSERT(indices);
6744         indexRange = gl::ComputeIndexRange(drawElementsType, indices, count, restart);
6745     }
6746 
6747     // index starts from 0
6748     captureClientArraySnapshot(context, indexRange.end + 1, instanceCount);
6749 }
6750 
6751 template <typename AttribT, typename FactoryT>
CreateEGLImagePreCallUpdate(const CallCapture & call,ResourceTracker & resourceTracker,ParamType paramType,FactoryT factory)6752 void CreateEGLImagePreCallUpdate(const CallCapture &call,
6753                                  ResourceTracker &resourceTracker,
6754                                  ParamType paramType,
6755                                  FactoryT factory)
6756 {
6757     EGLImage image            = call.params.getReturnValue().value.EGLImageVal;
6758     const ParamCapture &param = call.params.getParam("attrib_list", paramType, 4);
6759     const AttribT *attribs =
6760         param.data.empty() ? nullptr : reinterpret_cast<const AttribT *>(param.data[0].data());
6761     egl::AttributeMap attributeMap = factory(attribs);
6762     attributeMap.initializeWithoutValidation();
6763     resourceTracker.getImageToAttribTable().insert(
6764         std::pair<EGLImage, egl::AttributeMap>(image, attributeMap));
6765 }
6766 
maybeCapturePreCallUpdates(const gl::Context * context,CallCapture & call,std::vector<CallCapture> * shareGroupSetupCalls,ResourceIDToSetupCallsMap * resourceIDToSetupCalls)6767 void FrameCaptureShared::maybeCapturePreCallUpdates(
6768     const gl::Context *context,
6769     CallCapture &call,
6770     std::vector<CallCapture> *shareGroupSetupCalls,
6771     ResourceIDToSetupCallsMap *resourceIDToSetupCalls)
6772 {
6773     switch (call.entryPoint)
6774     {
6775         case EntryPoint::GLVertexAttribPointer:
6776         case EntryPoint::GLVertexPointer:
6777         case EntryPoint::GLColorPointer:
6778         case EntryPoint::GLTexCoordPointer:
6779         case EntryPoint::GLNormalPointer:
6780         case EntryPoint::GLPointSizePointerOES:
6781         {
6782             // Get array location
6783             GLuint index = 0;
6784             if (call.entryPoint == EntryPoint::GLVertexAttribPointer)
6785             {
6786                 index = call.params.getParam("index", ParamType::TGLuint, 0).value.GLuintVal;
6787             }
6788             else
6789             {
6790                 gl::ClientVertexArrayType type;
6791                 switch (call.entryPoint)
6792                 {
6793                     case EntryPoint::GLVertexPointer:
6794                         type = gl::ClientVertexArrayType::Vertex;
6795                         break;
6796                     case EntryPoint::GLColorPointer:
6797                         type = gl::ClientVertexArrayType::Color;
6798                         break;
6799                     case EntryPoint::GLTexCoordPointer:
6800                         type = gl::ClientVertexArrayType::TextureCoord;
6801                         break;
6802                     case EntryPoint::GLNormalPointer:
6803                         type = gl::ClientVertexArrayType::Normal;
6804                         break;
6805                     case EntryPoint::GLPointSizePointerOES:
6806                         type = gl::ClientVertexArrayType::PointSize;
6807                         break;
6808                     default:
6809                         UNREACHABLE();
6810                         type = gl::ClientVertexArrayType::InvalidEnum;
6811                 }
6812                 index = gl::GLES1Renderer::VertexArrayIndex(type, context->getState().gles1());
6813             }
6814 
6815             if (call.params.hasClientArrayData())
6816             {
6817                 mClientVertexArrayMap[index] = static_cast<int>(mFrameCalls.size());
6818             }
6819             else
6820             {
6821                 mClientVertexArrayMap[index] = -1;
6822             }
6823             break;
6824         }
6825 
6826         case EntryPoint::GLGenFramebuffers:
6827         case EntryPoint::GLGenFramebuffersOES:
6828         {
6829             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
6830             const gl::FramebufferID *framebufferIDs =
6831                 call.params.getParam("framebuffersPacked", ParamType::TFramebufferIDPointer, 1)
6832                     .value.FramebufferIDPointerVal;
6833             for (GLsizei i = 0; i < count; i++)
6834             {
6835                 handleGennedResource(context, framebufferIDs[i]);
6836             }
6837             break;
6838         }
6839 
6840         case EntryPoint::GLBindFramebuffer:
6841         case EntryPoint::GLBindFramebufferOES:
6842             maybeGenResourceOnBind<gl::FramebufferID>(context, call);
6843             break;
6844 
6845         case EntryPoint::GLGenRenderbuffers:
6846         case EntryPoint::GLGenRenderbuffersOES:
6847         {
6848             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
6849             const gl::RenderbufferID *renderbufferIDs =
6850                 call.params.getParam("renderbuffersPacked", ParamType::TRenderbufferIDPointer, 1)
6851                     .value.RenderbufferIDPointerVal;
6852             for (GLsizei i = 0; i < count; i++)
6853             {
6854                 handleGennedResource(context, renderbufferIDs[i]);
6855             }
6856             break;
6857         }
6858 
6859         case EntryPoint::GLBindRenderbuffer:
6860         case EntryPoint::GLBindRenderbufferOES:
6861             maybeGenResourceOnBind<gl::RenderbufferID>(context, call);
6862             break;
6863 
6864         case EntryPoint::GLDeleteRenderbuffers:
6865         case EntryPoint::GLDeleteRenderbuffersOES:
6866         {
6867             // Look up how many renderbuffers are being deleted
6868             GLsizei n = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
6869 
6870             // Look up the pointer to list of renderbuffers
6871             const gl::RenderbufferID *renderbufferIDs =
6872                 call.params
6873                     .getParam("renderbuffersPacked", ParamType::TRenderbufferIDConstPointer, 1)
6874                     .value.RenderbufferIDConstPointerVal;
6875 
6876             // For each renderbuffer listed for deletion
6877             for (int32_t i = 0; i < n; ++i)
6878             {
6879                 // If we're capturing, track what renderbuffers have been deleted
6880                 handleDeletedResource(context, renderbufferIDs[i]);
6881             }
6882             break;
6883         }
6884 
6885         case EntryPoint::GLGenTextures:
6886         {
6887             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
6888             const gl::TextureID *textureIDs =
6889                 call.params.getParam("texturesPacked", ParamType::TTextureIDPointer, 1)
6890                     .value.TextureIDPointerVal;
6891             for (GLsizei i = 0; i < count; i++)
6892             {
6893                 // If we're capturing, track what new textures have been genned
6894                 handleGennedResource(context, textureIDs[i]);
6895             }
6896             break;
6897         }
6898 
6899         case EntryPoint::GLBindTexture:
6900             maybeGenResourceOnBind<gl::TextureID>(context, call);
6901             if (isCaptureActive())
6902             {
6903                 gl::TextureType target =
6904                     call.params.getParam("targetPacked", ParamType::TTextureType, 0)
6905                         .value.TextureTypeVal;
6906                 context->getFrameCapture()->getStateResetHelper().setTextureBindingDirty(
6907                     context->getState().getActiveSampler(), target);
6908             }
6909             break;
6910 
6911         case EntryPoint::GLDeleteBuffers:
6912         {
6913             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
6914             const gl::BufferID *bufferIDs =
6915                 call.params.getParam("buffersPacked", ParamType::TBufferIDConstPointer, 1)
6916                     .value.BufferIDConstPointerVal;
6917             for (GLsizei i = 0; i < count; i++)
6918             {
6919                 // For each buffer being deleted, check our backup of data and remove it
6920                 const auto &bufferDataInfo = mBufferDataMap.find(bufferIDs[i]);
6921                 if (bufferDataInfo != mBufferDataMap.end())
6922                 {
6923                     mBufferDataMap.erase(bufferDataInfo);
6924                 }
6925                 // If we're capturing, track what buffers have been deleted
6926                 handleDeletedResource(context, bufferIDs[i]);
6927             }
6928             break;
6929         }
6930 
6931         case EntryPoint::GLGenBuffers:
6932         {
6933             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
6934             const gl::BufferID *bufferIDs =
6935                 call.params.getParam("buffersPacked", ParamType::TBufferIDPointer, 1)
6936                     .value.BufferIDPointerVal;
6937             for (GLsizei i = 0; i < count; i++)
6938             {
6939                 handleGennedResource(context, bufferIDs[i]);
6940             }
6941             break;
6942         }
6943 
6944         case EntryPoint::GLBindBuffer:
6945             maybeGenResourceOnBind<gl::BufferID>(context, call);
6946             if (isCaptureActive())
6947             {
6948                 gl::BufferBinding binding =
6949                     call.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
6950                         .value.BufferBindingVal;
6951 
6952                 context->getFrameCapture()->getStateResetHelper().setBufferBindingDirty(binding);
6953             }
6954             break;
6955 
6956         case EntryPoint::GLBindBufferBase:
6957         case EntryPoint::GLBindBufferRange:
6958             if (isCaptureActive())
6959             {
6960                 WARN() << "Indexed buffer binding changed during capture, Reset doesn't handle it "
6961                           "yet.";
6962             }
6963             break;
6964 
6965         case EntryPoint::GLDeleteProgramPipelines:
6966         case EntryPoint::GLDeleteProgramPipelinesEXT:
6967         {
6968             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
6969             const gl::ProgramPipelineID *pipelineIDs =
6970                 call.params
6971                     .getParam("pipelinesPacked", ParamType::TProgramPipelineIDConstPointer, 1)
6972                     .value.ProgramPipelineIDPointerVal;
6973             for (GLsizei i = 0; i < count; i++)
6974             {
6975                 handleDeletedResource(context, pipelineIDs[i]);
6976             }
6977             break;
6978         }
6979 
6980         case EntryPoint::GLGenProgramPipelines:
6981         case EntryPoint::GLGenProgramPipelinesEXT:
6982         {
6983             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
6984             const gl::ProgramPipelineID *pipelineIDs =
6985                 call.params.getParam("pipelinesPacked", ParamType::TProgramPipelineIDPointer, 1)
6986                     .value.ProgramPipelineIDPointerVal;
6987             for (GLsizei i = 0; i < count; i++)
6988             {
6989                 handleGennedResource(context, pipelineIDs[i]);
6990             }
6991             break;
6992         }
6993 
6994         case EntryPoint::GLDeleteSync:
6995         {
6996             gl::SyncID sync =
6997                 call.params.getParam("syncPacked", ParamType::TSyncID, 0).value.SyncIDVal;
6998             FrameCaptureShared *frameCaptureShared =
6999                 context->getShareGroup()->getFrameCaptureShared();
7000             // If we're capturing, track which fence sync has been deleted
7001             if (frameCaptureShared->isCaptureActive())
7002             {
7003                 mResourceTracker.setDeletedFenceSync(sync);
7004             }
7005             break;
7006         }
7007 
7008         case EntryPoint::GLDrawArrays:
7009         {
7010             maybeCaptureDrawArraysClientData(context, call, 1);
7011             maybeCaptureCoherentBuffers(context);
7012             break;
7013         }
7014 
7015         case EntryPoint::GLDrawArraysInstanced:
7016         case EntryPoint::GLDrawArraysInstancedANGLE:
7017         case EntryPoint::GLDrawArraysInstancedEXT:
7018         {
7019             GLsizei instancecount =
7020                 call.params.getParamFlexName("instancecount", "primcount", ParamType::TGLsizei, 3)
7021                     .value.GLsizeiVal;
7022 
7023             maybeCaptureDrawArraysClientData(context, call, instancecount);
7024             maybeCaptureCoherentBuffers(context);
7025             break;
7026         }
7027 
7028         case EntryPoint::GLDrawElements:
7029         {
7030             maybeCaptureDrawElementsClientData(context, call, 1);
7031             maybeCaptureCoherentBuffers(context);
7032             break;
7033         }
7034 
7035         case EntryPoint::GLDrawElementsInstanced:
7036         case EntryPoint::GLDrawElementsInstancedANGLE:
7037         case EntryPoint::GLDrawElementsInstancedEXT:
7038         {
7039             GLsizei instancecount =
7040                 call.params.getParamFlexName("instancecount", "primcount", ParamType::TGLsizei, 4)
7041                     .value.GLsizeiVal;
7042 
7043             maybeCaptureDrawElementsClientData(context, call, instancecount);
7044             maybeCaptureCoherentBuffers(context);
7045             break;
7046         }
7047 
7048         case EntryPoint::GLCreateShaderProgramv:
7049         {
7050             // Refresh the cached shader sources.
7051             // The command CreateShaderProgramv() creates a stand-alone program from an array of
7052             // null-terminated source code strings for a single shader type, so we need update the
7053             // Shader and Program sources, similar to GLCompileShader + GLLinkProgram handling.
7054             gl::ShaderProgramID programID = {call.params.getReturnValue().value.GLuintVal};
7055             const ParamCapture &paramCapture =
7056                 call.params.getParam("typePacked", ParamType::TShaderType, 0);
7057             const ParamCapture &lineCount = call.params.getParam("count", ParamType::TGLsizei, 1);
7058             const ParamCapture &strings =
7059                 call.params.getParam("strings", ParamType::TGLcharConstPointerPointer, 2);
7060 
7061             std::ostringstream sourceString;
7062             for (int i = 0; i < lineCount.value.GLsizeiVal; ++i)
7063             {
7064                 sourceString << strings.value.GLcharConstPointerPointerVal[i];
7065             }
7066 
7067             gl::ShaderType shaderType = paramCapture.value.ShaderTypeVal;
7068             ProgramSources source;
7069             source[shaderType] = sourceString.str();
7070             setProgramSources(programID, source);
7071             handleGennedResource(context, programID);
7072             mResourceTracker.setShaderProgramType(programID, ShaderProgramType::ProgramType);
7073             break;
7074         }
7075 
7076         case EntryPoint::GLCreateProgram:
7077         {
7078             // If we're capturing, track which programs have been created
7079             gl::ShaderProgramID programID = {call.params.getReturnValue().value.GLuintVal};
7080             handleGennedResource(context, programID);
7081 
7082             mResourceTracker.setShaderProgramType(programID, ShaderProgramType::ProgramType);
7083             break;
7084         }
7085 
7086         case EntryPoint::GLDeleteProgram:
7087         {
7088             // If we're capturing, track which programs have been deleted
7089             const ParamCapture &param =
7090                 call.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
7091             handleDeletedResource(context, param.value.ShaderProgramIDVal);
7092 
7093             // If this assert fires, it means a ShaderProgramID has changed from program to shader
7094             // which is unsupported
7095             ASSERT(mResourceTracker.getShaderProgramType(param.value.ShaderProgramIDVal) ==
7096                    ShaderProgramType::ProgramType);
7097 
7098             break;
7099         }
7100 
7101         case EntryPoint::GLCreateShader:
7102         {
7103             // If we're capturing, track which shaders have been created
7104             gl::ShaderProgramID shaderID = {call.params.getReturnValue().value.GLuintVal};
7105             handleGennedResource(context, shaderID);
7106 
7107             mResourceTracker.setShaderProgramType(shaderID, ShaderProgramType::ShaderType);
7108             break;
7109         }
7110 
7111         case EntryPoint::GLDeleteShader:
7112         {
7113             // If we're capturing, track which shaders have been deleted
7114             const ParamCapture &param =
7115                 call.params.getParam("shaderPacked", ParamType::TShaderProgramID, 0);
7116             handleDeletedResource(context, param.value.ShaderProgramIDVal);
7117 
7118             // If this assert fires, it means a ShaderProgramID has changed from shader to program
7119             // which is unsupported
7120             ASSERT(mResourceTracker.getShaderProgramType(param.value.ShaderProgramIDVal) ==
7121                    ShaderProgramType::ShaderType);
7122             break;
7123         }
7124 
7125         case EntryPoint::GLCompileShader:
7126         {
7127             // Refresh the cached shader sources.
7128             gl::ShaderProgramID shaderID =
7129                 call.params.getParam("shaderPacked", ParamType::TShaderProgramID, 0)
7130                     .value.ShaderProgramIDVal;
7131             const gl::Shader *shader = context->getShaderNoResolveCompile(shaderID);
7132             // Shaders compiled for ProgramBinary will not have a shader created
7133             if (shader)
7134             {
7135                 setShaderSource(shaderID, shader->getSourceString());
7136             }
7137             break;
7138         }
7139 
7140         case EntryPoint::GLLinkProgram:
7141         {
7142             // Refresh the cached program sources.
7143             gl::ShaderProgramID programID =
7144                 call.params.getParam("programPacked", ParamType::TShaderProgramID, 0)
7145                     .value.ShaderProgramIDVal;
7146             const gl::Program *program = context->getProgramResolveLink(programID);
7147             // Programs linked in support of ProgramBinary will not have attached shaders
7148             if (program->getState().hasAnyAttachedShader())
7149             {
7150                 setProgramSources(programID, GetAttachedProgramSources(context, program));
7151             }
7152             break;
7153         }
7154 
7155         case EntryPoint::GLDeleteTextures:
7156         {
7157             // Free any TextureLevelDataMap entries being tracked for this texture
7158             // This is to cover the scenario where a texture has been created, its
7159             // levels cached, then texture deleted and recreated, receiving the same ID
7160 
7161             // Look up how many textures are being deleted
7162             GLsizei n = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
7163 
7164             // Look up the pointer to list of textures
7165             const gl::TextureID *textureIDs =
7166                 call.params.getParam("texturesPacked", ParamType::TTextureIDConstPointer, 1)
7167                     .value.TextureIDConstPointerVal;
7168 
7169             // For each texture listed for deletion
7170             for (int32_t i = 0; i < n; ++i)
7171             {
7172                 // If we're capturing, track what textures have been deleted
7173                 handleDeletedResource(context, textureIDs[i]);
7174             }
7175             break;
7176         }
7177 
7178         case EntryPoint::GLMapBufferOES:
7179         {
7180             gl::BufferBinding target =
7181                 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
7182                     .value.BufferBindingVal;
7183 
7184             GLbitfield access =
7185                 call.params.getParam("access", ParamType::TGLenum, 1).value.GLenumVal;
7186 
7187             gl::Buffer *buffer = context->getState().getTargetBuffer(target);
7188 
7189             GLintptr offset   = 0;
7190             GLsizeiptr length = static_cast<GLsizeiptr>(buffer->getSize());
7191 
7192             bool writable =
7193                 access == GL_WRITE_ONLY_OES || access == GL_WRITE_ONLY || access == GL_READ_WRITE;
7194 
7195             FrameCaptureShared *frameCaptureShared =
7196                 context->getShareGroup()->getFrameCaptureShared();
7197             frameCaptureShared->trackBufferMapping(context, &call, buffer->id(), buffer, offset,
7198                                                    length, writable, false);
7199             break;
7200         }
7201 
7202         case EntryPoint::GLUnmapBuffer:
7203         case EntryPoint::GLUnmapBufferOES:
7204         {
7205             // See if we need to capture the buffer contents
7206             captureMappedBufferSnapshot(context, call);
7207 
7208             // Track that the buffer was unmapped, for use during state reset
7209             gl::BufferBinding target =
7210                 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
7211                     .value.BufferBindingVal;
7212             gl::Buffer *buffer = context->getState().getTargetBuffer(target);
7213             mResourceTracker.setBufferUnmapped(context->id(), buffer->id().value);
7214 
7215             // Remove from CoherentBufferTracker
7216             mCoherentBufferTracker.removeBuffer(buffer->id());
7217             break;
7218         }
7219 
7220         case EntryPoint::GLBufferData:
7221         case EntryPoint::GLBufferSubData:
7222         {
7223             gl::BufferBinding target =
7224                 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
7225                     .value.BufferBindingVal;
7226 
7227             gl::Buffer *buffer = context->getState().getTargetBuffer(target);
7228 
7229             // Track that this buffer's contents have been modified
7230             mResourceTracker.getTrackedResource(context->id(), ResourceIDType::Buffer)
7231                 .setModifiedResource(buffer->id().value);
7232 
7233             // BufferData is equivalent to UnmapBuffer, for what we're tracking.
7234             // From the ES 3.1 spec in BufferData section:
7235             //     If any portion of the buffer object is mapped in the current context or any
7236             //     context current to another thread, it is as though UnmapBuffer (see section
7237             //     6.3.1) is executed in each such context prior to deleting the existing data
7238             //     store.
7239             // Track that the buffer was unmapped, for use during state reset
7240             mResourceTracker.setBufferUnmapped(context->id(), buffer->id().value);
7241 
7242             break;
7243         }
7244 
7245         case EntryPoint::GLCopyBufferSubData:
7246         {
7247             maybeCaptureCoherentBuffers(context);
7248             break;
7249         }
7250         case EntryPoint::GLFinish:
7251         {
7252             // When using shadow memory we might need to synchronize it here.
7253             if (mCoherentBufferTracker.isShadowMemoryEnabled())
7254             {
7255                 mCoherentBufferTracker.maybeUpdateShadowMemory();
7256             }
7257             break;
7258         }
7259         case EntryPoint::GLDeleteFramebuffers:
7260         case EntryPoint::GLDeleteFramebuffersOES:
7261         {
7262             // Look up how many framebuffers are being deleted
7263             GLsizei n = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
7264 
7265             // Look up the pointer to list of framebuffers
7266             const gl::FramebufferID *framebufferIDs =
7267                 call.params.getParam("framebuffersPacked", ParamType::TFramebufferIDConstPointer, 1)
7268                     .value.FramebufferIDConstPointerVal;
7269 
7270             // For each framebuffer listed for deletion
7271             for (int32_t i = 0; i < n; ++i)
7272             {
7273                 // If we're capturing, track what framebuffers have been deleted
7274                 handleDeletedResource(context, framebufferIDs[i]);
7275             }
7276             break;
7277         }
7278 
7279         case EntryPoint::GLUseProgram:
7280         {
7281             if (isCaptureActive())
7282             {
7283                 context->getFrameCapture()->getStateResetHelper().setEntryPointDirty(
7284                     EntryPoint::GLUseProgram);
7285             }
7286             break;
7287         }
7288 
7289         case EntryPoint::GLGenVertexArrays:
7290         case EntryPoint::GLGenVertexArraysOES:
7291         {
7292             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
7293             const gl::VertexArrayID *arrayIDs =
7294                 call.params.getParam("arraysPacked", ParamType::TVertexArrayIDPointer, 1)
7295                     .value.VertexArrayIDPointerVal;
7296             for (GLsizei i = 0; i < count; i++)
7297             {
7298                 handleGennedResource(context, arrayIDs[i]);
7299             }
7300             break;
7301         }
7302 
7303         case EntryPoint::GLDeleteVertexArrays:
7304         case EntryPoint::GLDeleteVertexArraysOES:
7305         {
7306             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
7307             const gl::VertexArrayID *arrayIDs =
7308                 call.params.getParam("arraysPacked", ParamType::TVertexArrayIDConstPointer, 1)
7309                     .value.VertexArrayIDConstPointerVal;
7310             for (GLsizei i = 0; i < count; i++)
7311             {
7312                 // If we're capturing, track which vertex arrays have been deleted
7313                 handleDeletedResource(context, arrayIDs[i]);
7314             }
7315             break;
7316         }
7317 
7318         case EntryPoint::GLBindVertexArray:
7319         case EntryPoint::GLBindVertexArrayOES:
7320         {
7321             if (isCaptureActive())
7322             {
7323                 context->getFrameCapture()->getStateResetHelper().setEntryPointDirty(
7324                     EntryPoint::GLBindVertexArray);
7325             }
7326             break;
7327         }
7328         case EntryPoint::GLBlendFunc:
7329         {
7330             if (isCaptureActive())
7331             {
7332                 context->getFrameCapture()->getStateResetHelper().setEntryPointDirty(
7333                     EntryPoint::GLBlendFunc);
7334             }
7335             break;
7336         }
7337         case EntryPoint::GLBlendFuncSeparate:
7338         {
7339             if (isCaptureActive())
7340             {
7341                 context->getFrameCapture()->getStateResetHelper().setEntryPointDirty(
7342                     EntryPoint::GLBlendFuncSeparate);
7343             }
7344             break;
7345         }
7346         case EntryPoint::GLBlendEquation:
7347         case EntryPoint::GLBlendEquationSeparate:
7348         {
7349             if (isCaptureActive())
7350             {
7351                 context->getFrameCapture()->getStateResetHelper().setEntryPointDirty(
7352                     EntryPoint::GLBlendEquationSeparate);
7353             }
7354             break;
7355         }
7356         case EntryPoint::GLColorMask:
7357         {
7358             if (isCaptureActive())
7359             {
7360                 context->getFrameCapture()->getStateResetHelper().setEntryPointDirty(
7361                     EntryPoint::GLColorMask);
7362             }
7363             break;
7364         }
7365         case EntryPoint::GLBlendColor:
7366         {
7367             if (isCaptureActive())
7368             {
7369                 context->getFrameCapture()->getStateResetHelper().setEntryPointDirty(
7370                     EntryPoint::GLBlendColor);
7371             }
7372             break;
7373         }
7374 
7375         case EntryPoint::GLEGLImageTargetTexture2DOES:
7376         {
7377             gl::TextureType target =
7378                 call.params.getParam("targetPacked", ParamType::TTextureType, 0)
7379                     .value.TextureTypeVal;
7380             egl::ImageID imageID =
7381                 call.params.getParam("imagePacked", ParamType::TImageID, 1).value.ImageIDVal;
7382             mResourceTracker.getTextureIDToImageTable().insert(std::pair<GLuint, egl::ImageID>(
7383                 context->getState().getTargetTexture(target)->getId(), imageID));
7384             break;
7385         }
7386 
7387         case EntryPoint::EGLCreateImage:
7388         {
7389             CreateEGLImagePreCallUpdate<EGLAttrib>(call, mResourceTracker,
7390                                                    ParamType::TEGLAttribPointer,
7391                                                    egl::AttributeMap::CreateFromAttribArray);
7392             if (isCaptureActive())
7393             {
7394                 EGLImage eglImage    = call.params.getReturnValue().value.EGLImageVal;
7395                 egl::ImageID imageID = egl::PackParam<egl::ImageID>(eglImage);
7396                 handleGennedResource(context, imageID);
7397             }
7398             break;
7399         }
7400         case EntryPoint::EGLCreateImageKHR:
7401         {
7402             CreateEGLImagePreCallUpdate<EGLint>(call, mResourceTracker, ParamType::TEGLintPointer,
7403                                                 egl::AttributeMap::CreateFromIntArray);
7404             if (isCaptureActive())
7405             {
7406                 EGLImageKHR eglImage = call.params.getReturnValue().value.EGLImageKHRVal;
7407                 egl::ImageID imageID = egl::PackParam<egl::ImageID>(eglImage);
7408                 handleGennedResource(context, imageID);
7409             }
7410             break;
7411         }
7412         case EntryPoint::EGLDestroyImage:
7413         case EntryPoint::EGLDestroyImageKHR:
7414         {
7415             egl::ImageID eglImageID =
7416                 call.params.getParam("imagePacked", ParamType::TImageID, 1).value.ImageIDVal;
7417 
7418             // Clear any texture->image mappings that involve this image
7419             for (auto texImageIter = mResourceTracker.getTextureIDToImageTable().begin();
7420                  texImageIter != mResourceTracker.getTextureIDToImageTable().end();)
7421             {
7422                 if (texImageIter->second == eglImageID)
7423                 {
7424                     texImageIter = mResourceTracker.getTextureIDToImageTable().erase(texImageIter);
7425                 }
7426                 else
7427                 {
7428                     ++texImageIter;
7429                 }
7430             }
7431 
7432             FrameCaptureShared *frameCaptureShared =
7433                 context->getShareGroup()->getFrameCaptureShared();
7434             if (frameCaptureShared->isCaptureActive())
7435             {
7436                 handleDeletedResource(context, eglImageID);
7437             }
7438             break;
7439         }
7440         case EntryPoint::EGLCreateSync:
7441         case EntryPoint::EGLCreateSyncKHR:
7442         {
7443             egl::SyncID eglSyncID = call.params.getReturnValue().value.egl_SyncIDVal;
7444             FrameCaptureShared *frameCaptureShared =
7445                 context->getShareGroup()->getFrameCaptureShared();
7446             // If we're capturing, track which egl sync has been created
7447             if (frameCaptureShared->isCaptureActive())
7448             {
7449                 handleGennedResource(context, eglSyncID);
7450             }
7451             break;
7452         }
7453         case EntryPoint::EGLDestroySync:
7454         case EntryPoint::EGLDestroySyncKHR:
7455         {
7456             egl::SyncID eglSyncID =
7457                 call.params.getParam("syncPacked", ParamType::Tegl_SyncID, 1).value.egl_SyncIDVal;
7458             FrameCaptureShared *frameCaptureShared =
7459                 context->getShareGroup()->getFrameCaptureShared();
7460             // If we're capturing, track which EGL sync has been deleted
7461             if (frameCaptureShared->isCaptureActive())
7462             {
7463                 handleDeletedResource(context, eglSyncID);
7464             }
7465             break;
7466         }
7467         case EntryPoint::GLDispatchCompute:
7468         {
7469             // When using shadow memory we need to update the real memory here
7470             if (mCoherentBufferTracker.isShadowMemoryEnabled())
7471             {
7472                 maybeCaptureCoherentBuffers(context);
7473             }
7474             break;
7475         }
7476         default:
7477             break;
7478     }
7479 
7480     if (IsTextureUpdate(call))
7481     {
7482         // If this call modified texture contents, track it for possible reset
7483         trackTextureUpdate(context, call);
7484     }
7485 
7486     if (IsImageUpdate(call))
7487     {
7488         // If this call modified shader image contents, track it for possible reset
7489         trackImageUpdate(context, call);
7490     }
7491 
7492     if (isCaptureActive() && GetDefaultUniformType(call) != DefaultUniformType::None)
7493     {
7494         trackDefaultUniformUpdate(context, call);
7495     }
7496 
7497     if (IsVertexArrayUpdate(call))
7498     {
7499         trackVertexArrayUpdate(context, call);
7500     }
7501 
7502     updateReadBufferSize(call.params.getReadBufferSize());
7503 
7504     std::vector<gl::ShaderProgramID> shaderProgramIDs;
7505     if (FindResourceIDsInCall<gl::ShaderProgramID>(call, shaderProgramIDs))
7506     {
7507         for (gl::ShaderProgramID shaderProgramID : shaderProgramIDs)
7508         {
7509             mResourceTracker.onShaderProgramAccess(shaderProgramID);
7510 
7511             if (isCaptureActive())
7512             {
7513                 // Track that this call referenced a ShaderProgram, setting it active for Setup
7514                 MarkResourceIDActive(ResourceIDType::ShaderProgram, shaderProgramID.value,
7515                                      shareGroupSetupCalls, resourceIDToSetupCalls);
7516             }
7517         }
7518     }
7519 
7520     std::vector<gl::TextureID> textureIDs;
7521     if (FindResourceIDsInCall<gl::TextureID>(call, textureIDs))
7522     {
7523         for (gl::TextureID textureID : textureIDs)
7524         {
7525             if (isCaptureActive())
7526             {
7527                 // Track that this call referenced a Texture, setting it active for Setup
7528                 MarkResourceIDActive(ResourceIDType::Texture, textureID.value, shareGroupSetupCalls,
7529                                      resourceIDToSetupCalls);
7530             }
7531         }
7532     }
7533 }
7534 
7535 template <typename ParamValueType>
maybeGenResourceOnBind(const gl::Context * context,CallCapture & call)7536 void FrameCaptureShared::maybeGenResourceOnBind(const gl::Context *context, CallCapture &call)
7537 {
7538     const char *paramName     = ParamValueTrait<ParamValueType>::name;
7539     const ParamType paramType = ParamValueTrait<ParamValueType>::typeID;
7540 
7541     const ParamCapture &param = call.params.getParam(paramName, paramType, 1);
7542     const ParamValueType id   = AccessParamValue<ParamValueType>(paramType, param.value);
7543 
7544     // Don't inject the default resource or resources that are already generated
7545     if (id.value != 0 && !resourceIsGenerated(context, id))
7546     {
7547         handleGennedResource(context, id);
7548 
7549         ResourceIDType resourceIDType = GetResourceIDTypeFromParamType(param.type);
7550         const char *resourceName      = GetResourceIDTypeName(resourceIDType);
7551 
7552         std::stringstream updateFuncNameStr;
7553         updateFuncNameStr << "Set" << resourceName << "ID";
7554         ParamBuffer params;
7555         if (IsTrackedPerContext(resourceIDType))
7556         {
7557             // TODO (https://issuetracker.google.com/169868803) The '2' version can be removed after
7558             // all context-local objects are tracked per-context
7559             updateFuncNameStr << "2";
7560             params.addValueParam("contextID", ParamType::TGLuint, context->id().value);
7561         }
7562         std::string updateFuncName = updateFuncNameStr.str();
7563         params.addValueParam("id", ParamType::TGLuint, id.value);
7564         mFrameCalls.emplace_back(updateFuncName, std::move(params));
7565     }
7566 }
7567 
updateResourceCountsFromParamCapture(const ParamCapture & param,ResourceIDType idType)7568 void FrameCaptureShared::updateResourceCountsFromParamCapture(const ParamCapture &param,
7569                                                               ResourceIDType idType)
7570 {
7571     if (idType != ResourceIDType::InvalidEnum)
7572     {
7573         mHasResourceType.set(idType);
7574 
7575         // Capture resource IDs for non-pointer types.
7576         if (strcmp(ParamTypeToString(param.type), "GLuint") == 0)
7577         {
7578             mMaxAccessedResourceIDs[idType] =
7579                 std::max(mMaxAccessedResourceIDs[idType], param.value.GLuintVal);
7580         }
7581         // Capture resource IDs for pointer types.
7582         if (strstr(ParamTypeToString(param.type), "GLuint *") != nullptr)
7583         {
7584             if (param.data.size() == 1u)
7585             {
7586                 const GLuint *dataPtr = reinterpret_cast<const GLuint *>(param.data[0].data());
7587                 size_t numHandles     = param.data[0].size() / sizeof(GLuint);
7588                 for (size_t handleIndex = 0; handleIndex < numHandles; ++handleIndex)
7589                 {
7590                     mMaxAccessedResourceIDs[idType] =
7591                         std::max(mMaxAccessedResourceIDs[idType], dataPtr[handleIndex]);
7592                 }
7593             }
7594         }
7595         if (idType == ResourceIDType::Sync)
7596         {
7597             mMaxAccessedResourceIDs[idType] =
7598                 std::max(mMaxAccessedResourceIDs[idType], param.value.GLuintVal);
7599         }
7600     }
7601 }
7602 
updateResourceCountsFromCallCapture(const CallCapture & call)7603 void FrameCaptureShared::updateResourceCountsFromCallCapture(const CallCapture &call)
7604 {
7605 
7606     for (const ParamCapture &param : call.params.getParamCaptures())
7607     {
7608         ResourceIDType idType = GetResourceIDTypeFromParamType(param.type);
7609         updateResourceCountsFromParamCapture(param, idType);
7610     }
7611 
7612     // Update resource IDs in the return value. Return values types are not stored as resource IDs,
7613     // but instead are stored as GLuints. Therefore we need to explicitly label the resource ID type
7614     // when we call update. Currently only shader and program creation are explicitly tracked.
7615     switch (call.entryPoint)
7616     {
7617         case EntryPoint::GLCreateShader:
7618         case EntryPoint::GLCreateProgram:
7619             updateResourceCountsFromParamCapture(call.params.getReturnValue(),
7620                                                  ResourceIDType::ShaderProgram);
7621             break;
7622 
7623         case EntryPoint::GLFenceSync:
7624             updateResourceCountsFromParamCapture(call.params.getReturnValue(),
7625                                                  ResourceIDType::Sync);
7626             break;
7627         case EntryPoint::EGLCreateSync:
7628         case EntryPoint::EGLCreateSyncKHR:
7629             updateResourceCountsFromParamCapture(call.params.getReturnValue(),
7630                                                  ResourceIDType::egl_Sync);
7631             break;
7632         default:
7633             break;
7634     }
7635 }
7636 
captureCall(gl::Context * context,CallCapture && inCall,bool isCallValid)7637 void FrameCaptureShared::captureCall(gl::Context *context, CallCapture &&inCall, bool isCallValid)
7638 {
7639     if (SkipCall(inCall.entryPoint))
7640     {
7641         return;
7642     }
7643 
7644     if (isCallValid)
7645     {
7646         // Save the call's contextID
7647         inCall.contextID = context->id();
7648 
7649         // Update resource counts before we override entry points with custom calls.
7650         updateResourceCountsFromCallCapture(inCall);
7651 
7652         size_t j = mFrameCalls.size();
7653 
7654         std::vector<CallCapture> outCalls;
7655         maybeOverrideEntryPoint(context, inCall, outCalls);
7656 
7657         // Need to loop on any new calls we added during override
7658         for (CallCapture &call : outCalls)
7659         {
7660             // During capture, consider all frame calls active
7661             if (isCaptureActive())
7662             {
7663                 call.isActive = true;
7664             }
7665 
7666             maybeCapturePreCallUpdates(context, call, &mShareGroupSetupCalls,
7667                                        &mResourceIDToSetupCalls);
7668             mFrameCalls.emplace_back(std::move(call));
7669             maybeCapturePostCallUpdates(context);
7670         }
7671 
7672         // Tag all 'added' commands with this context
7673         for (size_t k = j; k < mFrameCalls.size(); k++)
7674         {
7675             mFrameCalls[k].contextID = context->id();
7676         }
7677 
7678         // Evaluate the validation expression to determine if we insert a validation checkpoint.
7679         // This lets the user pick a subset of calls to check instead of checking every call.
7680         if (mValidateSerializedState && !mValidationExpression.empty())
7681         {
7682             // Example substitution for frame #2, call #110:
7683             // Before: (call == 2) && (frame >= 100) && (frame <= 120) && ((frame % 10) == 0)
7684             // After:  (2 == 2) && (110 >= 100) && (110 <= 120) && ((110 % 10) == 0)
7685             // Evaluates to 1.0.
7686             std::string expression = mValidationExpression;
7687 
7688             angle::ReplaceAllSubstrings(&expression, "frame", std::to_string(mFrameIndex));
7689             angle::ReplaceAllSubstrings(&expression, "call", std::to_string(mFrameCalls.size()));
7690 
7691             double result = ceval_result(expression);
7692             if (result > 0)
7693             {
7694                 CaptureValidateSerializedState(context, &mFrameCalls);
7695             }
7696         }
7697     }
7698     else
7699     {
7700         const int maxInvalidCallLogs = 3;
7701         size_t &callCount = isCaptureActive() ? mInvalidCallCountsActive[inCall.entryPoint]
7702                                               : mInvalidCallCountsInactive[inCall.entryPoint];
7703         callCount++;
7704         if (callCount <= maxInvalidCallLogs)
7705         {
7706             std::ostringstream msg;
7707             msg << "FrameCapture (capture " << (isCaptureActive() ? "active" : "inactive")
7708                 << "): Not capturing invalid call to " << GetEntryPointName(inCall.entryPoint);
7709             if (callCount == maxInvalidCallLogs)
7710             {
7711                 msg << " (will no longer repeat for this entry point)";
7712             }
7713             INFO() << msg.str();
7714         }
7715 
7716         std::stringstream skipCall;
7717         skipCall << "Skipping invalid call to " << GetEntryPointName(inCall.entryPoint)
7718                  << " with error: "
7719                  << gl::GLenumToString(gl::GLESEnum::ErrorCode, context->getErrorForCapture());
7720         AddComment(&mFrameCalls, skipCall.str());
7721     }
7722 }
7723 
maybeCapturePostCallUpdates(const gl::Context * context)7724 void FrameCaptureShared::maybeCapturePostCallUpdates(const gl::Context *context)
7725 {
7726     // Process resource ID updates.
7727     if (isCaptureActive())
7728     {
7729         MaybeCaptureUpdateResourceIDs(context, &mResourceTracker, &mFrameCalls);
7730     }
7731 
7732     CallCapture &lastCall = mFrameCalls.back();
7733     switch (lastCall.entryPoint)
7734     {
7735         case EntryPoint::GLCreateShaderProgramv:
7736         {
7737             gl::ShaderProgramID programId;
7738             programId.value            = lastCall.params.getReturnValue().value.GLuintVal;
7739             const gl::Program *program = context->getProgramResolveLink(programId);
7740             CaptureUpdateUniformLocations(program, &mFrameCalls);
7741             CaptureUpdateUniformBlockIndexes(program, &mFrameCalls);
7742             break;
7743         }
7744         case EntryPoint::GLLinkProgram:
7745         {
7746             const ParamCapture &param =
7747                 lastCall.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
7748             const gl::Program *program =
7749                 context->getProgramResolveLink(param.value.ShaderProgramIDVal);
7750             CaptureUpdateUniformLocations(program, &mFrameCalls);
7751             CaptureUpdateUniformBlockIndexes(program, &mFrameCalls);
7752             break;
7753         }
7754         case EntryPoint::GLUseProgram:
7755             CaptureUpdateCurrentProgram(lastCall, 0, &mFrameCalls);
7756             break;
7757         case EntryPoint::GLActiveShaderProgram:
7758             CaptureUpdateCurrentProgram(lastCall, 1, &mFrameCalls);
7759             break;
7760         case EntryPoint::GLDeleteProgram:
7761         {
7762             const ParamCapture &param =
7763                 lastCall.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
7764             CaptureDeleteUniformLocations(param.value.ShaderProgramIDVal, &mFrameCalls);
7765             break;
7766         }
7767         case EntryPoint::GLShaderSource:
7768         {
7769             lastCall.params.setValueParamAtIndex("count", ParamType::TGLsizei, 1, 1);
7770 
7771             ParamCapture &paramLength =
7772                 lastCall.params.getParam("length", ParamType::TGLintConstPointer, 3);
7773             paramLength.data.resize(1);
7774             // Set the length parameter to {-1} to signal that the actual string length
7775             // is to be used. Since we store the parameter blob as an array of four uint8_t
7776             // values, we have to pass the binary equivalent of -1.
7777             paramLength.data[0] = {0xff, 0xff, 0xff, 0xff};
7778             break;
7779         }
7780         case EntryPoint::GLBufferData:
7781         case EntryPoint::GLBufferSubData:
7782         {
7783             // When using shadow memory we need to update it from real memory here
7784             if (mCoherentBufferTracker.isShadowMemoryEnabled())
7785             {
7786                 gl::BufferBinding target =
7787                     lastCall.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
7788                         .value.BufferBindingVal;
7789 
7790                 gl::Buffer *buffer = context->getState().getTargetBuffer(target);
7791                 if (mCoherentBufferTracker.haveBuffer(buffer->id()))
7792                 {
7793                     std::shared_ptr<CoherentBuffer> cb =
7794                         mCoherentBufferTracker.mBuffers[buffer->id().value];
7795                     cb->removeProtection(PageSharingType::NoneShared);
7796                     cb->updateShadowMemory();
7797                     cb->protectAll();
7798                 }
7799             }
7800             break;
7801         }
7802 
7803         case EntryPoint::GLCopyBufferSubData:
7804         {
7805             // When using shadow memory, we need to mark the buffer shadowDirty bit to true
7806             // so it will be synchronized with real memory on the next glFinish call.
7807             if (mCoherentBufferTracker.isShadowMemoryEnabled())
7808             {
7809                 gl::BufferBinding target =
7810                     lastCall.params.getParam("writeTargetPacked", ParamType::TBufferBinding, 1)
7811                         .value.BufferBindingVal;
7812 
7813                 gl::Buffer *buffer = context->getState().getTargetBuffer(target);
7814                 if (mCoherentBufferTracker.haveBuffer(buffer->id()))
7815                 {
7816                     std::shared_ptr<CoherentBuffer> cb =
7817                         mCoherentBufferTracker.mBuffers[buffer->id().value];
7818                     // This needs to be synced on glFinish
7819                     cb->markShadowDirty();
7820                 }
7821             }
7822             break;
7823         }
7824         case EntryPoint::GLDispatchCompute:
7825         {
7826             // When using shadow memory, we need to mark all buffer's shadowDirty bit to true
7827             // so they will be synchronized with real memory on the next glFinish call.
7828             if (mCoherentBufferTracker.isShadowMemoryEnabled())
7829             {
7830                 mCoherentBufferTracker.markAllShadowDirty();
7831             }
7832             break;
7833         }
7834         default:
7835             break;
7836     }
7837 }
7838 
captureClientArraySnapshot(const gl::Context * context,size_t vertexCount,size_t instanceCount)7839 void FrameCaptureShared::captureClientArraySnapshot(const gl::Context *context,
7840                                                     size_t vertexCount,
7841                                                     size_t instanceCount)
7842 {
7843     if (vertexCount == 0)
7844     {
7845         // Nothing to capture
7846         return;
7847     }
7848 
7849     const gl::VertexArray *vao = context->getState().getVertexArray();
7850 
7851     // Capture client array data.
7852     for (size_t attribIndex : context->getStateCache().getActiveClientAttribsMask())
7853     {
7854         const gl::VertexAttribute &attrib = vao->getVertexAttribute(attribIndex);
7855         const gl::VertexBinding &binding  = vao->getVertexBinding(attrib.bindingIndex);
7856 
7857         int callIndex = mClientVertexArrayMap[attribIndex];
7858 
7859         if (callIndex != -1)
7860         {
7861             size_t count = vertexCount;
7862 
7863             if (binding.getDivisor() > 0)
7864             {
7865                 count = rx::UnsignedCeilDivide(static_cast<uint32_t>(instanceCount),
7866                                                binding.getDivisor());
7867             }
7868 
7869             // The last capture element doesn't take up the full stride.
7870             size_t bytesToCapture = (count - 1) * binding.getStride() + attrib.format->pixelBytes;
7871 
7872             CallCapture &call   = mFrameCalls[callIndex];
7873             ParamCapture &param = call.params.getClientArrayPointerParameter();
7874             ASSERT(param.type == ParamType::TvoidConstPointer);
7875 
7876             ParamBuffer updateParamBuffer;
7877             updateParamBuffer.addValueParam<GLint>("arrayIndex", ParamType::TGLint,
7878                                                    static_cast<uint32_t>(attribIndex));
7879 
7880             ParamCapture updateMemory("pointer", ParamType::TvoidConstPointer);
7881             CaptureMemory(param.value.voidConstPointerVal, bytesToCapture, &updateMemory);
7882             updateParamBuffer.addParam(std::move(updateMemory));
7883 
7884             updateParamBuffer.addValueParam<GLuint64>("size", ParamType::TGLuint64, bytesToCapture);
7885 
7886             mFrameCalls.emplace_back("UpdateClientArrayPointer", std::move(updateParamBuffer));
7887 
7888             mClientArraySizes[attribIndex] =
7889                 std::max(mClientArraySizes[attribIndex], bytesToCapture);
7890         }
7891     }
7892 }
7893 
captureCoherentBufferSnapshot(const gl::Context * context,gl::BufferID id)7894 void FrameCaptureShared::captureCoherentBufferSnapshot(const gl::Context *context, gl::BufferID id)
7895 {
7896     if (!hasBufferData(id))
7897     {
7898         // This buffer was not marked writable
7899         return;
7900     }
7901 
7902     const gl::State &apiState        = context->getState();
7903     const gl::BufferManager &buffers = apiState.getBufferManagerForCapture();
7904     gl::Buffer *buffer               = buffers.getBuffer(id);
7905     if (!buffer)
7906     {
7907         // Could not find buffer binding
7908         return;
7909     }
7910 
7911     ASSERT(buffer->isMapped());
7912 
7913     std::shared_ptr<angle::CoherentBuffer> coherentBuffer =
7914         mCoherentBufferTracker.mBuffers[id.value];
7915 
7916     std::vector<PageRange> dirtyPageRanges = coherentBuffer->getDirtyPageRanges();
7917 
7918     if (mCoherentBufferTracker.isShadowMemoryEnabled() && !dirtyPageRanges.empty())
7919     {
7920         coherentBuffer->updateBufferMemory();
7921     }
7922 
7923     AddressRange wholeRange = coherentBuffer->getRange();
7924 
7925     for (PageRange &pageRange : dirtyPageRanges)
7926     {
7927         // Write protect the memory already, so the app is blocked on writing during our capture
7928         coherentBuffer->protectPageRange(pageRange);
7929 
7930         // Create the parameters to our helper for use during replay
7931         ParamBuffer dataParamBuffer;
7932 
7933         // Pass in the target buffer ID
7934         dataParamBuffer.addValueParam("dest", ParamType::TGLuint, buffer->id().value);
7935 
7936         // Capture the current buffer data with a binary param
7937         ParamCapture captureData("source", ParamType::TvoidConstPointer);
7938 
7939         AddressRange dirtyRange = coherentBuffer->getDirtyAddressRange(pageRange);
7940         CaptureMemory(reinterpret_cast<void *>(dirtyRange.start), dirtyRange.size, &captureData);
7941         dataParamBuffer.addParam(std::move(captureData));
7942 
7943         // Also track its size for use with memcpy
7944         dataParamBuffer.addValueParam<GLsizeiptr>("size", ParamType::TGLsizeiptr,
7945                                                   static_cast<GLsizeiptr>(dirtyRange.size));
7946 
7947         if (wholeRange.start != dirtyRange.start)
7948         {
7949             // Capture with offset
7950             GLsizeiptr offset = dirtyRange.start - wholeRange.start;
7951 
7952             ASSERT(offset > 0);
7953 
7954             // The dirty page range is not at the start of the buffer, track the offset.
7955             dataParamBuffer.addValueParam<GLsizeiptr>("offset", ParamType::TGLsizeiptr, offset);
7956 
7957             // Call the helper that populates the buffer with captured data
7958             mFrameCalls.emplace_back("UpdateClientBufferDataWithOffset",
7959                                      std::move(dataParamBuffer));
7960         }
7961         else
7962         {
7963             // Call the helper that populates the buffer with captured data
7964             mFrameCalls.emplace_back("UpdateClientBufferData", std::move(dataParamBuffer));
7965         }
7966     }
7967 }
7968 
captureMappedBufferSnapshot(const gl::Context * context,const CallCapture & call)7969 void FrameCaptureShared::captureMappedBufferSnapshot(const gl::Context *context,
7970                                                      const CallCapture &call)
7971 {
7972     // If the buffer was mapped writable, we need to restore its data, since we have no
7973     // visibility into what the client did to the buffer while mapped.
7974     // This sequence will result in replay calls like this:
7975     //   ...
7976     //   gMappedBufferData[gBufferMap[42]] = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, 65536,
7977     //                                                        GL_MAP_WRITE_BIT);
7978     //   ...
7979     //   UpdateClientBufferData(42, &gBinaryData[164631024], 65536);
7980     //   glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
7981     //   ...
7982 
7983     // Re-map the buffer, using the info we tracked about the buffer
7984     gl::BufferBinding target =
7985         call.params.getParam("targetPacked", ParamType::TBufferBinding, 0).value.BufferBindingVal;
7986 
7987     FrameCaptureShared *frameCaptureShared = context->getShareGroup()->getFrameCaptureShared();
7988     gl::Buffer *buffer                     = context->getState().getTargetBuffer(target);
7989     if (!frameCaptureShared->hasBufferData(buffer->id()))
7990     {
7991         // This buffer was not marked writable, so we did not back it up
7992         return;
7993     }
7994 
7995     std::pair<GLintptr, GLsizeiptr> bufferDataOffsetAndLength =
7996         frameCaptureShared->getBufferDataOffsetAndLength(buffer->id());
7997     GLintptr offset   = bufferDataOffsetAndLength.first;
7998     GLsizeiptr length = bufferDataOffsetAndLength.second;
7999 
8000     // Map the buffer so we can copy its contents out
8001     ASSERT(!buffer->isMapped());
8002     angle::Result result = buffer->mapRange(context, offset, length, GL_MAP_READ_BIT);
8003     if (result != angle::Result::Continue)
8004     {
8005         ERR() << "Failed to mapRange of buffer" << std::endl;
8006     }
8007     const uint8_t *data = reinterpret_cast<const uint8_t *>(buffer->getMapPointer());
8008 
8009     // Create the parameters to our helper for use during replay
8010     ParamBuffer dataParamBuffer;
8011 
8012     // Pass in the target buffer ID
8013     dataParamBuffer.addValueParam("dest", ParamType::TGLuint, buffer->id().value);
8014 
8015     // Capture the current buffer data with a binary param
8016     ParamCapture captureData("source", ParamType::TvoidConstPointer);
8017     CaptureMemory(data, length, &captureData);
8018     dataParamBuffer.addParam(std::move(captureData));
8019 
8020     // Also track its size for use with memcpy
8021     dataParamBuffer.addValueParam<GLsizeiptr>("size", ParamType::TGLsizeiptr, length);
8022 
8023     // Call the helper that populates the buffer with captured data
8024     mFrameCalls.emplace_back("UpdateClientBufferData", std::move(dataParamBuffer));
8025 
8026     // Unmap the buffer and move on
8027     GLboolean dontCare;
8028     (void)buffer->unmap(context, &dontCare);
8029 }
8030 
checkForCaptureTrigger()8031 void FrameCaptureShared::checkForCaptureTrigger()
8032 {
8033     // Determine if trigger has changed
8034     std::string captureTriggerStr = GetCaptureTrigger();
8035     if (captureTriggerStr.empty())
8036     {
8037         return;
8038     }
8039 
8040     // If the value has changed, use the original value as the frame count
8041     uint32_t captureTrigger = atoi(captureTriggerStr.c_str());
8042     if ((mCaptureTrigger > 0) && (captureTrigger == 0))
8043     {
8044         // Start mid-execution capture for the current frame
8045         mCaptureStartFrame = mFrameIndex + 1;
8046 
8047         // Use the original trigger value as the frame count
8048         mCaptureEndFrame = mCaptureStartFrame + mCaptureTrigger - 1;
8049 
8050         INFO() << "Capture triggered after frame " << mFrameIndex << " for " << mCaptureTrigger
8051                << " frames";
8052 
8053         // Stop polling
8054         mCaptureTrigger = 0;
8055     }
8056     else if (captureTrigger > 0)
8057     {
8058         // Update number of frames to capture in MEC
8059         mCaptureTrigger = captureTrigger;
8060     }
8061 }
8062 
scanSetupCalls(std::vector<CallCapture> & setupCalls)8063 void FrameCaptureShared::scanSetupCalls(std::vector<CallCapture> &setupCalls)
8064 {
8065     // Scan all the instructions in the list for tracking
8066     for (CallCapture &call : setupCalls)
8067     {
8068         updateReadBufferSize(call.params.getReadBufferSize());
8069         updateResourceCountsFromCallCapture(call);
8070     }
8071 }
8072 
runMidExecutionCapture(gl::Context * mainContext)8073 void FrameCaptureShared::runMidExecutionCapture(gl::Context *mainContext)
8074 {
8075     // Set the capture active to ensure all GLES commands issued by the next frame are
8076     // handled correctly by maybeCapturePreCallUpdates() and maybeCapturePostCallUpdates().
8077     setCaptureActive();
8078 
8079     // Make sure all pending work for every Context in the share group has completed so all data
8080     // (buffers, textures, etc.) has been updated and no resources are in use.
8081     egl::ShareGroup *shareGroup = mainContext->getShareGroup();
8082     shareGroup->finishAllContexts();
8083 
8084     const gl::State &contextState = mainContext->getState();
8085     gl::State mainContextReplayState(
8086         nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, contextState.getClientVersion(),
8087         false, true, true, true, false, EGL_CONTEXT_PRIORITY_MEDIUM_IMG,
8088         contextState.hasRobustAccess(), contextState.hasProtectedContent(), false);
8089     mainContextReplayState.initializeForCapture(mainContext);
8090 
8091     CaptureShareGroupMidExecutionSetup(mainContext, &mShareGroupSetupCalls, &mResourceTracker,
8092                                        mainContextReplayState, mMaxAccessedResourceIDs);
8093 
8094     scanSetupCalls(mShareGroupSetupCalls);
8095 
8096     egl::Display *display = mainContext->getDisplay();
8097     egl::Surface *draw    = mainContext->getCurrentDrawSurface();
8098     egl::Surface *read    = mainContext->getCurrentReadSurface();
8099 
8100     for (auto shareContext : shareGroup->getContexts())
8101     {
8102         FrameCapture *frameCapture = shareContext.second->getFrameCapture();
8103         ASSERT(frameCapture->getSetupCalls().empty());
8104 
8105         if (shareContext.second->id() == mainContext->id())
8106         {
8107             CaptureMidExecutionSetup(shareContext.second, &frameCapture->getSetupCalls(),
8108                                      frameCapture->getStateResetHelper(), &mShareGroupSetupCalls,
8109                                      &mResourceIDToSetupCalls, &mResourceTracker,
8110                                      mainContextReplayState, mValidateSerializedState);
8111             scanSetupCalls(frameCapture->getSetupCalls());
8112 
8113             std::stringstream protoStream;
8114             std::stringstream headerStream;
8115             std::stringstream bodyStream;
8116 
8117             protoStream << "void "
8118                         << FmtSetupFunction(kNoPartId, mainContext->id(), FuncUsage::Prototype);
8119             std::string proto = protoStream.str();
8120 
8121             WriteCppReplayFunctionWithParts(mainContext->id(), ReplayFunc::Setup, mReplayWriter, 1,
8122                                             &mBinaryData, frameCapture->getSetupCalls(),
8123                                             headerStream, bodyStream, &mResourceIDBufferSize);
8124 
8125             mReplayWriter.addPrivateFunction(proto, headerStream, bodyStream);
8126         }
8127         else
8128         {
8129             const gl::State &shareContextState = shareContext.second->getState();
8130             gl::State auxContextReplayState(nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
8131                                             shareContextState.getClientVersion(), false, true, true,
8132                                             true, false, EGL_CONTEXT_PRIORITY_MEDIUM_IMG,
8133                                             shareContextState.hasRobustAccess(),
8134                                             shareContextState.hasProtectedContent(), false);
8135             auxContextReplayState.initializeForCapture(shareContext.second);
8136 
8137             egl::Error error = shareContext.second->makeCurrent(display, draw, read);
8138             if (error.isError())
8139             {
8140                 INFO() << "MEC unable to make secondary context current";
8141             }
8142 
8143             CaptureMidExecutionSetup(shareContext.second, &frameCapture->getSetupCalls(),
8144                                      frameCapture->getStateResetHelper(), &mShareGroupSetupCalls,
8145                                      &mResourceIDToSetupCalls, &mResourceTracker,
8146                                      auxContextReplayState, mValidateSerializedState);
8147 
8148             scanSetupCalls(frameCapture->getSetupCalls());
8149 
8150             WriteAuxiliaryContextCppSetupReplay(
8151                 mReplayWriter, mCompression, mOutDirectory, shareContext.second, mCaptureLabel, 1,
8152                 frameCapture->getSetupCalls(), &mBinaryData, mSerializeStateEnabled, *this,
8153                 &mResourceIDBufferSize);
8154         }
8155         // Track that this context was created before MEC started
8156         mActiveContexts.insert(shareContext.first);
8157     }
8158 
8159     egl::Error error = mainContext->makeCurrent(display, draw, read);
8160     if (error.isError())
8161     {
8162         INFO() << "MEC unable to make main context current again";
8163     }
8164 }
8165 
onEndFrame(gl::Context * context)8166 void FrameCaptureShared::onEndFrame(gl::Context *context)
8167 {
8168     if (!enabled() || mFrameIndex > mCaptureEndFrame)
8169     {
8170         setCaptureInactive();
8171         mCoherentBufferTracker.onEndFrame();
8172         if (enabled())
8173         {
8174             resetMidExecutionCapture(context);
8175         }
8176         resetCaptureStartEndFrames();
8177         mFrameIndex++;
8178         return;
8179     }
8180 
8181     FrameCapture *frameCapture = context->getFrameCapture();
8182 
8183     // Count resource IDs. This is also done on every frame. It could probably be done by
8184     // checking the GL state instead of the calls.
8185     for (const CallCapture &call : mFrameCalls)
8186     {
8187         for (const ParamCapture &param : call.params.getParamCaptures())
8188         {
8189             ResourceIDType idType = GetResourceIDTypeFromParamType(param.type);
8190             if (idType != ResourceIDType::InvalidEnum)
8191             {
8192                 mHasResourceType.set(idType);
8193             }
8194         }
8195     }
8196 
8197     mWindowSurfaceContextID = context->id();
8198 
8199     // On Android, we can trigger a capture during the run
8200     checkForCaptureTrigger();
8201 
8202     // Check for MEC. Done after checkForCaptureTrigger(), since that can modify mCaptureStartFrame.
8203     if (mFrameIndex < mCaptureStartFrame)
8204     {
8205         if (mFrameIndex == mCaptureStartFrame - 1)
8206         {
8207             // Update output directory location
8208             getOutputDirectory();
8209             // Trigger MEC.
8210             runMidExecutionCapture(context);
8211         }
8212         mFrameIndex++;
8213         reset();
8214         return;
8215     }
8216 
8217     ASSERT(isCaptureActive());
8218 
8219     if (!mFrameCalls.empty())
8220     {
8221         mActiveFrameIndices.push_back(getReplayFrameIndex());
8222     }
8223 
8224     // Make sure all pending work for every Context in the share group has completed so all data
8225     // (buffers, textures, etc.) has been updated and no resources are in use.
8226     egl::ShareGroup *shareGroup = context->getShareGroup();
8227     shareGroup->finishAllContexts();
8228 
8229     // Only validate the first frame for now to save on retracing time.
8230     if (mValidateSerializedState && mFrameIndex == mCaptureStartFrame)
8231     {
8232         CaptureValidateSerializedState(context, &mFrameCalls);
8233     }
8234 
8235     writeMainContextCppReplay(context, frameCapture->getSetupCalls(),
8236                               frameCapture->getStateResetHelper());
8237 
8238     if (mFrameIndex == mCaptureEndFrame)
8239     {
8240         // Write shared MEC after frame sequence so we can eliminate unused assets like programs
8241         WriteShareGroupCppSetupReplay(mReplayWriter, mCompression, mOutDirectory, mCaptureLabel, 1,
8242                                       1, mShareGroupSetupCalls, &mResourceTracker, &mBinaryData,
8243                                       mSerializeStateEnabled, mWindowSurfaceContextID,
8244                                       &mResourceIDBufferSize);
8245 
8246         // Save the index files after the last frame.
8247         writeCppReplayIndexFiles(context, false);
8248         SaveBinaryData(mCompression, mOutDirectory, kSharedContextId, mCaptureLabel, mBinaryData);
8249         mBinaryData.clear();
8250         mWroteIndexFile = true;
8251         INFO() << "Finished recording graphics API capture";
8252     }
8253 
8254     reset();
8255     mFrameIndex++;
8256 }
8257 
onDestroyContext(const gl::Context * context)8258 void FrameCaptureShared::onDestroyContext(const gl::Context *context)
8259 {
8260     if (!mEnabled)
8261     {
8262         return;
8263     }
8264     if (!mWroteIndexFile && mFrameIndex > mCaptureStartFrame)
8265     {
8266         // If context is destroyed before end frame is reached and at least
8267         // 1 frame has been recorded, then write the index files.
8268         // It doesn't make sense to write the index files when no frame has been recorded
8269         mFrameIndex -= 1;
8270         mCaptureEndFrame = mFrameIndex;
8271         writeCppReplayIndexFiles(context, true);
8272         SaveBinaryData(mCompression, mOutDirectory, kSharedContextId, mCaptureLabel, mBinaryData);
8273         mBinaryData.clear();
8274         mWroteIndexFile = true;
8275     }
8276 }
8277 
onMakeCurrent(const gl::Context * context,const egl::Surface * drawSurface)8278 void FrameCaptureShared::onMakeCurrent(const gl::Context *context, const egl::Surface *drawSurface)
8279 {
8280     if (!drawSurface)
8281     {
8282         return;
8283     }
8284 
8285     // Track the width, height and color space of the draw surface as provided to makeCurrent
8286     SurfaceParams &params = mDrawSurfaceParams[context->id()];
8287     params.extents        = gl::Extents(drawSurface->getWidth(), drawSurface->getHeight(), 1);
8288     params.colorSpace     = egl::FromEGLenum<egl::ColorSpace>(drawSurface->getGLColorspace());
8289 }
8290 
setDefaultResetCalls(const gl::Context * context,angle::EntryPoint entryPoint)8291 void StateResetHelper::setDefaultResetCalls(const gl::Context *context,
8292                                             angle::EntryPoint entryPoint)
8293 {
8294     static const gl::BlendState kDefaultBlendState;
8295 
8296     // Populate default reset calls for entrypoints to support looping to beginning
8297     switch (entryPoint)
8298     {
8299         case angle::EntryPoint::GLUseProgram:
8300         {
8301             if (context->getActiveLinkedProgram() &&
8302                 context->getActiveLinkedProgram()->id().value != 0)
8303             {
8304                 Capture(&mResetCalls[angle::EntryPoint::GLUseProgram],
8305                         gl::CaptureUseProgram(context->getState(), true, {0}));
8306             }
8307             break;
8308         }
8309         case angle::EntryPoint::GLBindVertexArray:
8310         {
8311             if (context->getState().getVertexArray()->id().value != 0)
8312             {
8313                 VertexArrayCaptureFuncs vertexArrayFuncs(context->isGLES1());
8314                 Capture(&mResetCalls[angle::EntryPoint::GLBindVertexArray],
8315                         vertexArrayFuncs.bindVertexArray(context->getState(), true, {0}));
8316             }
8317             break;
8318         }
8319         case angle::EntryPoint::GLBlendFunc:
8320         {
8321             Capture(&mResetCalls[angle::EntryPoint::GLBlendFunc],
8322                     CaptureBlendFunc(context->getState(), true, kDefaultBlendState.sourceBlendRGB,
8323                                      kDefaultBlendState.destBlendRGB));
8324             break;
8325         }
8326         case angle::EntryPoint::GLBlendFuncSeparate:
8327         {
8328             Capture(&mResetCalls[angle::EntryPoint::GLBlendFuncSeparate],
8329                     CaptureBlendFuncSeparate(
8330                         context->getState(), true, kDefaultBlendState.sourceBlendRGB,
8331                         kDefaultBlendState.destBlendRGB, kDefaultBlendState.sourceBlendAlpha,
8332                         kDefaultBlendState.destBlendAlpha));
8333             break;
8334         }
8335         case angle::EntryPoint::GLBlendEquation:
8336         {
8337             UNREACHABLE();  // GLBlendEquationSeparate is always used instead
8338             break;
8339         }
8340         case angle::EntryPoint::GLBlendEquationSeparate:
8341         {
8342             Capture(&mResetCalls[angle::EntryPoint::GLBlendEquationSeparate],
8343                     CaptureBlendEquationSeparate(context->getState(), true,
8344                                                  kDefaultBlendState.blendEquationRGB,
8345                                                  kDefaultBlendState.blendEquationAlpha));
8346             break;
8347         }
8348         case angle::EntryPoint::GLColorMask:
8349         {
8350             Capture(&mResetCalls[angle::EntryPoint::GLColorMask],
8351                     CaptureColorMask(context->getState(), true,
8352                                      gl::ConvertToGLBoolean(kDefaultBlendState.colorMaskRed),
8353                                      gl::ConvertToGLBoolean(kDefaultBlendState.colorMaskGreen),
8354                                      gl::ConvertToGLBoolean(kDefaultBlendState.colorMaskBlue),
8355                                      gl::ConvertToGLBoolean(kDefaultBlendState.colorMaskAlpha)));
8356             break;
8357         }
8358         case angle::EntryPoint::GLBlendColor:
8359         {
8360             Capture(&mResetCalls[angle::EntryPoint::GLBlendColor],
8361                     CaptureBlendColor(context->getState(), true, 0, 0, 0, 0));
8362             break;
8363         }
8364         default:
8365             ERR() << "Unhandled entry point in setDefaultResetCalls: "
8366                   << GetEntryPointName(entryPoint);
8367             UNREACHABLE();
8368             break;
8369     }
8370 }
8371 
setDeletedFenceSync(gl::SyncID sync)8372 void ResourceTracker::setDeletedFenceSync(gl::SyncID sync)
8373 {
8374     ASSERT(sync.value != 0);
8375     if (mStartingFenceSyncs.find(sync) == mStartingFenceSyncs.end())
8376     {
8377         // This is a fence sync created after MEC was initialized. Ignore it.
8378         return;
8379     }
8380 
8381     // In this case, the app is deleting a fence sync we started with, we need to regen on loop.
8382     mFenceSyncsToRegen.insert(sync);
8383 }
8384 
setModifiedDefaultUniform(gl::ShaderProgramID programID,gl::UniformLocation location)8385 void ResourceTracker::setModifiedDefaultUniform(gl::ShaderProgramID programID,
8386                                                 gl::UniformLocation location)
8387 {
8388     // Pull up or create the list of uniform locations for this program and mark one dirty
8389     mDefaultUniformsToReset[programID].insert(location);
8390 }
8391 
setDefaultUniformBaseLocation(gl::ShaderProgramID programID,gl::UniformLocation location,gl::UniformLocation baseLocation)8392 void ResourceTracker::setDefaultUniformBaseLocation(gl::ShaderProgramID programID,
8393                                                     gl::UniformLocation location,
8394                                                     gl::UniformLocation baseLocation)
8395 {
8396     // Track the base location used to populate arrayed uniforms in Setup
8397     mDefaultUniformBaseLocations[{programID, location}] = baseLocation;
8398 }
8399 
getTrackedResource(gl::ContextID contextID,ResourceIDType type)8400 TrackedResource &ResourceTracker::getTrackedResource(gl::ContextID contextID, ResourceIDType type)
8401 {
8402     if (IsSharedObjectResource(type))
8403     {
8404         // No need to index with context if shared
8405         return mTrackedResourcesShared[static_cast<uint32_t>(type)];
8406     }
8407     else
8408     {
8409         // For per-context objects, track the resource per-context
8410         return mTrackedResourcesPerContext[contextID][static_cast<uint32_t>(type)];
8411     }
8412 }
8413 
getContextIDs(std::set<gl::ContextID> & idsOut)8414 void ResourceTracker::getContextIDs(std::set<gl::ContextID> &idsOut)
8415 {
8416     for (const auto &trackedResourceIterator : mTrackedResourcesPerContext)
8417     {
8418         gl::ContextID contextID = trackedResourceIterator.first;
8419         idsOut.insert(contextID);
8420     }
8421 }
8422 
setGennedResource(GLuint id)8423 void TrackedResource::setGennedResource(GLuint id)
8424 {
8425     if (mStartingResources.find(id) == mStartingResources.end())
8426     {
8427         // This is a resource created after MEC was initialized, track it
8428         mNewResources.insert(id);
8429     }
8430     else
8431     {
8432         // In this case, the app is genning a resource with starting ID after previously deleting it
8433         ASSERT(mResourcesToRegen.find(id) != mResourcesToRegen.end());
8434 
8435         // For this, we need to delete it again to recreate it.
8436         mResourcesToDelete.insert(id);
8437     }
8438 }
8439 
resourceIsGenerated(GLuint id)8440 bool TrackedResource::resourceIsGenerated(GLuint id)
8441 {
8442     return mStartingResources.find(id) != mStartingResources.end() ||
8443            mNewResources.find(id) != mNewResources.end();
8444 }
8445 
setDeletedResource(GLuint id)8446 void TrackedResource::setDeletedResource(GLuint id)
8447 {
8448     if (id == 0)
8449     {
8450         // Ignore ID 0
8451         return;
8452     }
8453 
8454     if (mNewResources.find(id) != mNewResources.end())
8455     {
8456         // This is a resource created after MEC was initialized, just clear it, since there will be
8457         // no actions required for it to return to starting state.
8458         mNewResources.erase(id);
8459         return;
8460     }
8461 
8462     if (mStartingResources.find(id) != mStartingResources.end())
8463     {
8464         // In this case, the app is deleting a resource we started with, we need to regen on loop
8465 
8466         // Mark that we don't need to delete this
8467         mResourcesToDelete.erase(id);
8468 
8469         // Generate the resource again
8470         mResourcesToRegen.insert(id);
8471 
8472         // Also restore its contents
8473         mResourcesToRestore.insert(id);
8474     }
8475 
8476     // If none of the above is true, the app is deleting a resource that was never genned.
8477 }
8478 
setModifiedResource(GLuint id)8479 void TrackedResource::setModifiedResource(GLuint id)
8480 {
8481     // If this was a starting resource, we need to track it for restore
8482     if (mStartingResources.find(id) != mStartingResources.end())
8483     {
8484         mResourcesToRestore.insert(id);
8485     }
8486 }
8487 
setBufferMapped(gl::ContextID contextID,GLuint id)8488 void ResourceTracker::setBufferMapped(gl::ContextID contextID, GLuint id)
8489 {
8490     // If this was a starting buffer, we may need to restore it to original state during Reset.
8491     // Skip buffers that were deleted after the starting point.
8492     const TrackedResource &trackedBuffers = getTrackedResource(contextID, ResourceIDType::Buffer);
8493     const ResourceSet &startingBuffers    = trackedBuffers.getStartingResources();
8494     const ResourceSet &buffersToRegen     = trackedBuffers.getResourcesToRegen();
8495     if (startingBuffers.find(id) != startingBuffers.end() &&
8496         buffersToRegen.find(id) == buffersToRegen.end())
8497     {
8498         // Track that its current state is mapped (true)
8499         mStartingBuffersMappedCurrent[id] = true;
8500     }
8501 }
8502 
setBufferUnmapped(gl::ContextID contextID,GLuint id)8503 void ResourceTracker::setBufferUnmapped(gl::ContextID contextID, GLuint id)
8504 {
8505     // If this was a starting buffer, we may need to restore it to original state during Reset.
8506     // Skip buffers that were deleted after the starting point.
8507     const TrackedResource &trackedBuffers = getTrackedResource(contextID, ResourceIDType::Buffer);
8508     const ResourceSet &startingBuffers    = trackedBuffers.getStartingResources();
8509     const ResourceSet &buffersToRegen     = trackedBuffers.getResourcesToRegen();
8510     if (startingBuffers.find(id) != startingBuffers.end() &&
8511         buffersToRegen.find(id) == buffersToRegen.end())
8512     {
8513         // Track that its current state is unmapped (false)
8514         mStartingBuffersMappedCurrent[id] = false;
8515     }
8516 }
8517 
getStartingBuffersMappedCurrent(GLuint id) const8518 bool ResourceTracker::getStartingBuffersMappedCurrent(GLuint id) const
8519 {
8520     const auto &foundBool = mStartingBuffersMappedCurrent.find(id);
8521     ASSERT(foundBool != mStartingBuffersMappedCurrent.end());
8522     return foundBool->second;
8523 }
8524 
getStartingBuffersMappedInitial(GLuint id) const8525 bool ResourceTracker::getStartingBuffersMappedInitial(GLuint id) const
8526 {
8527     const auto &foundBool = mStartingBuffersMappedInitial.find(id);
8528     ASSERT(foundBool != mStartingBuffersMappedInitial.end());
8529     return foundBool->second;
8530 }
8531 
onShaderProgramAccess(gl::ShaderProgramID shaderProgramID)8532 void ResourceTracker::onShaderProgramAccess(gl::ShaderProgramID shaderProgramID)
8533 {
8534     mMaxShaderPrograms = std::max(mMaxShaderPrograms, shaderProgramID.value + 1);
8535 }
8536 
8537 // Serialize trace metadata into a JSON file. The JSON file will be named "trace_prefix.json".
8538 //
8539 // As of writing, it will have the format like so:
8540 // {
8541 //     "TraceMetadata":
8542 //     {
8543 //         "AreClientArraysEnabled" : 1, "CaptureRevision" : 16631, "ConfigAlphaBits" : 8,
8544 //             "ConfigBlueBits" : 8, "ConfigDepthBits" : 24, "ConfigGreenBits" : 8,
8545 // ... etc ...
writeJSON(const gl::Context * context)8546 void FrameCaptureShared::writeJSON(const gl::Context *context)
8547 {
8548     const gl::ContextID contextId           = context->id();
8549     const SurfaceParams &surfaceParams      = mDrawSurfaceParams.at(contextId);
8550     const gl::State &glState                = context->getState();
8551     const egl::Config *config               = context->getConfig();
8552     const egl::AttributeMap &displayAttribs = context->getDisplay()->getAttributeMap();
8553 
8554     unsigned int frameCount = getFrameCount();
8555 
8556     JsonSerializer json;
8557     json.startGroup("TraceMetadata");
8558     json.addScalar("CaptureRevision", GetANGLERevision());
8559     json.addScalar("ContextClientMajorVersion", context->getClientMajorVersion());
8560     json.addScalar("ContextClientMinorVersion", context->getClientMinorVersion());
8561     json.addHexValue("DisplayPlatformType", displayAttribs.getAsInt(EGL_PLATFORM_ANGLE_TYPE_ANGLE));
8562     json.addHexValue("DisplayDeviceType",
8563                      displayAttribs.getAsInt(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE));
8564     json.addScalar("FrameStart", 1);
8565     json.addScalar("FrameEnd", frameCount);
8566     json.addScalar("DrawSurfaceWidth", surfaceParams.extents.width);
8567     json.addScalar("DrawSurfaceHeight", surfaceParams.extents.height);
8568     json.addHexValue("DrawSurfaceColorSpace", ToEGLenum(surfaceParams.colorSpace));
8569     if (config)
8570     {
8571         json.addScalar("ConfigRedBits", config->redSize);
8572         json.addScalar("ConfigGreenBits", config->greenSize);
8573         json.addScalar("ConfigBlueBits", config->blueSize);
8574         json.addScalar("ConfigAlphaBits", config->alphaSize);
8575         json.addScalar("ConfigDepthBits", config->depthSize);
8576         json.addScalar("ConfigStencilBits", config->stencilSize);
8577     }
8578     else
8579     {
8580         json.addScalar("ConfigRedBits", EGL_DONT_CARE);
8581         json.addScalar("ConfigGreenBits", EGL_DONT_CARE);
8582         json.addScalar("ConfigBlueBits", EGL_DONT_CARE);
8583         json.addScalar("ConfigAlphaBits", EGL_DONT_CARE);
8584         json.addScalar("ConfigDepthBits", EGL_DONT_CARE);
8585         json.addScalar("ConfigStencilBits", EGL_DONT_CARE);
8586     }
8587     json.addBool("IsBinaryDataCompressed", mCompression);
8588     json.addBool("AreClientArraysEnabled", glState.areClientArraysEnabled());
8589     json.addBool("IsBindGeneratesResourcesEnabled", glState.isBindGeneratesResourceEnabled());
8590     json.addBool("IsWebGLCompatibilityEnabled", glState.isWebGL());
8591     json.addBool("IsRobustResourceInitEnabled", glState.isRobustResourceInitEnabled());
8592     json.endGroup();
8593 
8594     {
8595         const std::vector<std::string> &traceFiles = mReplayWriter.getAndResetWrittenFiles();
8596         json.addVectorOfStrings("TraceFiles", traceFiles);
8597     }
8598 
8599     json.addScalar("WindowSurfaceContextID", contextId.value);
8600 
8601     {
8602         std::stringstream jsonFileNameStream;
8603         jsonFileNameStream << mOutDirectory << FmtCapturePrefix(kNoContextId, mCaptureLabel)
8604                            << ".json";
8605         std::string jsonFileName = jsonFileNameStream.str();
8606 
8607         SaveFileHelper saveData(jsonFileName);
8608         saveData.write(reinterpret_cast<const uint8_t *>(json.data()), json.length());
8609     }
8610 }
8611 
writeCppReplayIndexFiles(const gl::Context * context,bool writeResetContextCall)8612 void FrameCaptureShared::writeCppReplayIndexFiles(const gl::Context *context,
8613                                                   bool writeResetContextCall)
8614 {
8615     // Ensure the last frame is written. This will no-op if the frame is already written.
8616     mReplayWriter.saveFrame();
8617 
8618     const gl::ContextID contextId = context->id();
8619 
8620     {
8621         std::stringstream header;
8622 
8623         header << "#pragma once\n";
8624         header << "\n";
8625         header << "#include <EGL/egl.h>\n";
8626         header << "#include <stdint.h>\n";
8627 
8628         std::string includes = header.str();
8629         mReplayWriter.setHeaderPrologue(includes);
8630     }
8631 
8632     {
8633         std::stringstream source;
8634 
8635         source << "#include \"" << FmtCapturePrefix(contextId, mCaptureLabel) << ".h\"\n";
8636         source << "#include \"trace_fixture.h\"\n";
8637         source << "#include \"angle_trace_gl.h\"\n";
8638 
8639         std::string sourcePrologue = source.str();
8640         mReplayWriter.setSourcePrologue(sourcePrologue);
8641     }
8642 
8643     {
8644         std::string proto = "void InitReplay(void)";
8645 
8646         std::stringstream source;
8647         source << proto << "\n";
8648         source << "{\n";
8649         WriteInitReplayCall(mCompression, source, context->id(), mCaptureLabel,
8650                             MaxClientArraySize(mClientArraySizes), mReadBufferSize,
8651                             mResourceIDBufferSize, mMaxAccessedResourceIDs);
8652         source << "}\n";
8653 
8654         mReplayWriter.addPrivateFunction(proto, std::stringstream(), source);
8655     }
8656 
8657     {
8658         std::string proto = "void ReplayFrame(uint32_t frameIndex)";
8659 
8660         std::stringstream source;
8661 
8662         source << proto << "\n";
8663         source << "{\n";
8664         source << "    switch (frameIndex)\n";
8665         source << "    {\n";
8666         for (uint32_t frameIndex : mActiveFrameIndices)
8667         {
8668             source << "        case " << frameIndex << ":\n";
8669             source << "            " << FmtReplayFunction(contextId, FuncUsage::Call, frameIndex)
8670                    << ";\n";
8671             source << "            break;\n";
8672         }
8673         source << "        default:\n";
8674         source << "            break;\n";
8675         source << "    }\n";
8676         source << "}\n";
8677 
8678         mReplayWriter.addPublicFunction(proto, std::stringstream(), source);
8679     }
8680 
8681     if (writeResetContextCall)
8682     {
8683         std::string proto = "void ResetReplay(void)";
8684 
8685         std::stringstream source;
8686 
8687         source << proto << "\n";
8688         source << "{\n";
8689         source << "    // Reset context is empty because context is destroyed before end "
8690                   "frame is reached\n";
8691         source << "}\n";
8692 
8693         mReplayWriter.addPublicFunction(proto, std::stringstream(), source);
8694     }
8695 
8696     if (mSerializeStateEnabled)
8697     {
8698         std::string proto = "const char *GetSerializedContextState(uint32_t frameIndex)";
8699 
8700         std::stringstream source;
8701 
8702         source << proto << "\n";
8703         source << "{\n";
8704         source << "    switch (frameIndex)\n";
8705         source << "    {\n";
8706         for (uint32_t frameIndex = 1; frameIndex <= getFrameCount(); ++frameIndex)
8707         {
8708             source << "        case " << frameIndex << ":\n";
8709             source << "            return "
8710                    << FmtGetSerializedContextStateFunction(contextId, FuncUsage::Call, frameIndex)
8711                    << ";\n";
8712         }
8713         source << "        default:\n";
8714         source << "            return NULL;\n";
8715         source << "    }\n";
8716         source << "}\n";
8717 
8718         mReplayWriter.addPublicFunction(proto, std::stringstream(), source);
8719     }
8720 
8721     {
8722         std::stringstream fnameStream;
8723         fnameStream << mOutDirectory << FmtCapturePrefix(contextId, mCaptureLabel);
8724         std::string fnamePattern = fnameStream.str();
8725 
8726         mReplayWriter.setFilenamePattern(fnamePattern);
8727     }
8728 
8729     mReplayWriter.saveIndexFilesAndHeader();
8730 
8731     writeJSON(context);
8732 }
8733 
writeMainContextCppReplay(const gl::Context * context,const std::vector<CallCapture> & setupCalls,StateResetHelper & stateResetHelper)8734 void FrameCaptureShared::writeMainContextCppReplay(const gl::Context *context,
8735                                                    const std::vector<CallCapture> &setupCalls,
8736                                                    StateResetHelper &stateResetHelper)
8737 {
8738     ASSERT(mWindowSurfaceContextID == context->id());
8739 
8740     {
8741         std::stringstream header;
8742 
8743         header << "#include \"" << FmtCapturePrefix(context->id(), mCaptureLabel) << ".h\"\n";
8744         header << "#include \"angle_trace_gl.h\"\n";
8745 
8746         std::string headerString = header.str();
8747         mReplayWriter.setSourcePrologue(headerString);
8748     }
8749 
8750     uint32_t frameCount = getFrameCount();
8751     uint32_t frameIndex = getReplayFrameIndex();
8752 
8753     if (frameIndex == 1)
8754     {
8755         {
8756             std::string proto = "void SetupReplay(void)";
8757 
8758             std::stringstream out;
8759 
8760             out << proto << "\n";
8761             out << "{\n";
8762 
8763             // Setup all of the shared objects.
8764             out << "    InitReplay();\n";
8765             if (usesMidExecutionCapture())
8766             {
8767                 out << "    " << FmtSetupFunction(kNoPartId, kSharedContextId, FuncUsage::Call)
8768                     << ";\n";
8769                 out << "    "
8770                     << FmtSetupInactiveFunction(kNoPartId, kSharedContextId, FuncUsage::Call)
8771                     << "\n";
8772                 // Make sure that the current context is mapped correctly
8773                 out << "    SetCurrentContextID(" << context->id() << ");\n";
8774             }
8775 
8776             // Setup each of the auxiliary contexts.
8777             egl::ShareGroup *shareGroup            = context->getShareGroup();
8778             const egl::ContextMap &shareContextMap = shareGroup->getContexts();
8779             for (auto shareContext : shareContextMap)
8780             {
8781                 if (shareContext.first == context->id().value)
8782                 {
8783                     if (usesMidExecutionCapture())
8784                     {
8785                         // Setup the presentation (this) context first.
8786                         out << "    " << FmtSetupFunction(kNoPartId, context->id(), FuncUsage::Call)
8787                             << ";\n";
8788                         out << "\n";
8789                     }
8790 
8791                     continue;
8792                 }
8793 
8794                 // The SetupReplayContextXX() calls only exist if this is a mid-execution capture
8795                 // and we can only call them if they exist, so only output the calls if this is a
8796                 // MEC.
8797                 if (usesMidExecutionCapture())
8798                 {
8799                     // Only call SetupReplayContext for secondary contexts that were current before
8800                     // MEC started
8801                     if (mActiveContexts.find(shareContext.first) != mActiveContexts.end())
8802                     {
8803                         // TODO(http://anglebug.com/42264418): Support capture/replay of
8804                         // eglCreateContext() so this block can be moved into SetupReplayContextXX()
8805                         // by injecting them into the beginning of the setup call stream.
8806                         out << "    CreateContext(" << shareContext.first << ");\n";
8807 
8808                         out << "    "
8809                             << FmtSetupFunction(kNoPartId, shareContext.second->id(),
8810                                                 FuncUsage::Call)
8811                             << ";\n";
8812                     }
8813                 }
8814             }
8815 
8816             // If there are other contexts that were initialized, we need to make the main context
8817             // current again.
8818             if (shareContextMap.size() > 1)
8819             {
8820                 out << "\n";
8821                 out << "    eglMakeCurrent(NULL, NULL, NULL, gContextMap2[" << context->id()
8822                     << "]);\n";
8823             }
8824 
8825             out << "}\n";
8826 
8827             mReplayWriter.addPublicFunction(proto, std::stringstream(), out);
8828         }
8829     }
8830 
8831     // Emit code to reset back to starting state
8832     if (frameIndex == frameCount)
8833     {
8834         std::stringstream resetProtoStream;
8835         std::stringstream resetHeaderStream;
8836         std::stringstream resetBodyStream;
8837 
8838         resetProtoStream << "void ResetReplay(void)";
8839 
8840         resetBodyStream << resetProtoStream.str() << "\n";
8841         resetBodyStream << "{\n";
8842 
8843         // Grab the list of contexts to be reset
8844         std::set<gl::ContextID> contextIDs;
8845         mResourceTracker.getContextIDs(contextIDs);
8846 
8847         // TODO(http://anglebug.com/42264418): Look at moving this into the shared context file
8848         // since it's resetting shared objects.
8849 
8850         // TODO(http://anglebug.com/42263204): Support function parts when writing Reset functions
8851 
8852         // Track whether anything was written during Reset
8853         bool anyResourceReset = false;
8854 
8855         // Track whether we changed contexts during Reset
8856         bool contextChanged = false;
8857 
8858         // First emit shared object reset, including opaque and context state
8859         {
8860             std::stringstream protoStream;
8861             std::stringstream headerStream;
8862             std::stringstream bodyStream;
8863 
8864             protoStream << "void "
8865                         << FmtResetFunction(kNoPartId, kSharedContextId, FuncUsage::Prototype);
8866             bodyStream << protoStream.str() << "\n";
8867             bodyStream << "{\n";
8868 
8869             for (ResourceIDType resourceType : AllEnums<ResourceIDType>())
8870             {
8871                 if (!IsSharedObjectResource(resourceType))
8872                 {
8873                     continue;
8874                 }
8875                 // Use current context for shared reset
8876                 MaybeResetResources(context->getDisplay(), context->id(), resourceType,
8877                                     mReplayWriter, bodyStream, headerStream, &mResourceTracker,
8878                                     &mBinaryData, anyResourceReset, &mResourceIDBufferSize);
8879             }
8880 
8881             // Reset opaque type objects that don't have IDs, so are not ResourceIDTypes.
8882             MaybeResetOpaqueTypeObjects(mReplayWriter, bodyStream, headerStream, context,
8883                                         &mResourceTracker, &mBinaryData, &mResourceIDBufferSize);
8884 
8885             bodyStream << "}\n";
8886 
8887             mReplayWriter.addPrivateFunction(protoStream.str(), headerStream, bodyStream);
8888         }
8889 
8890         // Emit the call to shared object reset
8891         resetBodyStream << "    " << FmtResetFunction(kNoPartId, kSharedContextId, FuncUsage::Call)
8892                         << ";\n";
8893 
8894         // Reset our output tracker (Note: This was unused during shared reset)
8895         anyResourceReset = false;
8896 
8897         // Walk through all contexts that need Reset
8898         for (const gl::ContextID &contextID : contextIDs)
8899         {
8900             // Create a function to reset each context's non-shared objects
8901             {
8902                 std::stringstream protoStream;
8903                 std::stringstream headerStream;
8904                 std::stringstream bodyStream;
8905 
8906                 protoStream << "void "
8907                             << FmtResetFunction(kNoPartId, contextID, FuncUsage::Prototype);
8908                 bodyStream << protoStream.str() << "\n";
8909                 bodyStream << "{\n";
8910 
8911                 // Build the Reset calls in a separate stream so we can insert before them
8912                 std::stringstream resetStream;
8913 
8914                 for (ResourceIDType resourceType : AllEnums<ResourceIDType>())
8915                 {
8916                     if (IsSharedObjectResource(resourceType))
8917                     {
8918                         continue;
8919                     }
8920                     MaybeResetResources(context->getDisplay(), contextID, resourceType,
8921                                         mReplayWriter, resetStream, headerStream, &mResourceTracker,
8922                                         &mBinaryData, anyResourceReset, &mResourceIDBufferSize);
8923                 }
8924 
8925                 // Only call eglMakeCurrent if anything was actually reset in the function and the
8926                 // context differs from current
8927                 if (anyResourceReset && contextID != context->id())
8928                 {
8929                     contextChanged = true;
8930                     bodyStream << "    eglMakeCurrent(NULL, NULL, NULL, gContextMap2["
8931                                << contextID.value << "]);\n\n";
8932                 }
8933 
8934                 // Then append the Reset calls
8935                 bodyStream << resetStream.str();
8936 
8937                 bodyStream << "}\n";
8938                 mReplayWriter.addPrivateFunction(protoStream.str(), headerStream, bodyStream);
8939             }
8940 
8941             // Emit a call to reset each context's non-shared objects
8942             resetBodyStream << "    " << FmtResetFunction(kNoPartId, contextID, FuncUsage::Call)
8943                             << ";\n";
8944         }
8945 
8946         // Bind the main context again if we bound any additional contexts
8947         if (contextChanged)
8948         {
8949             resetBodyStream << "    eglMakeCurrent(NULL, NULL, NULL, gContextMap2["
8950                             << context->id().value << "]);\n";
8951         }
8952 
8953         // Now that we're back on the main context, reset any additional state
8954         resetBodyStream << "\n    // Reset main context state\n";
8955         MaybeResetContextState(mReplayWriter, resetBodyStream, resetHeaderStream, &mResourceTracker,
8956                                context, &mBinaryData, stateResetHelper, &mResourceIDBufferSize);
8957 
8958         resetBodyStream << "}\n";
8959 
8960         mReplayWriter.addPublicFunction(resetProtoStream.str(), resetHeaderStream, resetBodyStream);
8961     }
8962 
8963     if (!mFrameCalls.empty())
8964     {
8965         std::stringstream protoStream;
8966         protoStream << "void "
8967                     << FmtReplayFunction(context->id(), FuncUsage::Prototype, frameIndex);
8968         std::string proto = protoStream.str();
8969         std::stringstream headerStream;
8970         std::stringstream bodyStream;
8971 
8972         if (context->getShareGroup()->getContexts().size() > 1)
8973         {
8974             // Only ReplayFunc::Replay trace file output functions are affected by multi-context
8975             // call grouping so they can safely be special-cased here.
8976             WriteCppReplayFunctionWithPartsMultiContext(
8977                 context->id(), ReplayFunc::Replay, mReplayWriter, frameIndex, &mBinaryData,
8978                 mFrameCalls, headerStream, bodyStream, &mResourceIDBufferSize);
8979         }
8980         else
8981         {
8982             WriteCppReplayFunctionWithParts(context->id(), ReplayFunc::Replay, mReplayWriter,
8983                                             frameIndex, &mBinaryData, mFrameCalls, headerStream,
8984                                             bodyStream, &mResourceIDBufferSize);
8985         }
8986         mReplayWriter.addPrivateFunction(proto, headerStream, bodyStream);
8987     }
8988 
8989     if (mSerializeStateEnabled)
8990     {
8991         std::string serializedContextString;
8992         if (SerializeContextToString(const_cast<gl::Context *>(context),
8993                                      &serializedContextString) == Result::Continue)
8994         {
8995             std::stringstream protoStream;
8996             protoStream << "const char *"
8997                         << FmtGetSerializedContextStateFunction(context->id(), FuncUsage::Prototype,
8998                                                                 frameIndex);
8999             std::string proto = protoStream.str();
9000 
9001             std::stringstream bodyStream;
9002             bodyStream << proto << "\n";
9003             bodyStream << "{\n";
9004             bodyStream << "    return " << FmtMultiLineString(serializedContextString) << ";\n";
9005             bodyStream << "}\n";
9006 
9007             mReplayWriter.addPrivateFunction(proto, std::stringstream(), bodyStream);
9008         }
9009     }
9010 
9011     {
9012         std::stringstream fnamePatternStream;
9013         fnamePatternStream << mOutDirectory << FmtCapturePrefix(context->id(), mCaptureLabel);
9014         std::string fnamePattern = fnamePatternStream.str();
9015 
9016         mReplayWriter.setFilenamePattern(fnamePattern);
9017     }
9018 
9019     if (mFrameIndex == mCaptureEndFrame)
9020     {
9021         mReplayWriter.saveFrame();
9022     }
9023     else
9024     {
9025         mReplayWriter.saveFrameIfFull();
9026     }
9027 }
9028 
getShaderSource(gl::ShaderProgramID id) const9029 const std::string &FrameCaptureShared::getShaderSource(gl::ShaderProgramID id) const
9030 {
9031     const auto &foundSources = mCachedShaderSource.find(id);
9032     ASSERT(foundSources != mCachedShaderSource.end());
9033     return foundSources->second;
9034 }
9035 
setShaderSource(gl::ShaderProgramID id,std::string source)9036 void FrameCaptureShared::setShaderSource(gl::ShaderProgramID id, std::string source)
9037 {
9038     mCachedShaderSource[id] = source;
9039 }
9040 
getProgramSources(gl::ShaderProgramID id) const9041 const ProgramSources &FrameCaptureShared::getProgramSources(gl::ShaderProgramID id) const
9042 {
9043     const auto &foundSources = mCachedProgramSources.find(id);
9044     ASSERT(foundSources != mCachedProgramSources.end());
9045     return foundSources->second;
9046 }
9047 
setProgramSources(gl::ShaderProgramID id,ProgramSources sources)9048 void FrameCaptureShared::setProgramSources(gl::ShaderProgramID id, ProgramSources sources)
9049 {
9050     mCachedProgramSources[id] = sources;
9051 }
9052 
markResourceSetupCallsInactive(std::vector<CallCapture> * setupCalls,ResourceIDType type,GLuint id,gl::Range<size_t> range)9053 void FrameCaptureShared::markResourceSetupCallsInactive(std::vector<CallCapture> *setupCalls,
9054                                                         ResourceIDType type,
9055                                                         GLuint id,
9056                                                         gl::Range<size_t> range)
9057 {
9058     ASSERT(mResourceIDToSetupCalls[type].find(id) == mResourceIDToSetupCalls[type].end());
9059 
9060     // Mark all of the calls that were used to initialize this resource as INACTIVE
9061     for (size_t index : range)
9062     {
9063         (*setupCalls)[index].isActive = false;
9064     }
9065 
9066     mResourceIDToSetupCalls[type][id] = range;
9067 }
9068 
CaptureStringLimit(const GLchar * str,uint32_t limit,ParamCapture * paramCapture)9069 void CaptureStringLimit(const GLchar *str, uint32_t limit, ParamCapture *paramCapture)
9070 {
9071     // Write the incoming string up to limit, including null terminator
9072     size_t length = strlen(str) + 1;
9073 
9074     if (length > limit)
9075     {
9076         // If too many characters, resize the string to fit in the limit
9077         std::string newStr = str;
9078         newStr.resize(limit - 1);
9079         CaptureString(newStr.c_str(), paramCapture);
9080     }
9081     else
9082     {
9083         CaptureMemory(str, length, paramCapture);
9084     }
9085 }
9086 
CaptureVertexPointerGLES1(const gl::State & glState,gl::ClientVertexArrayType type,const void * pointer,ParamCapture * paramCapture)9087 void CaptureVertexPointerGLES1(const gl::State &glState,
9088                                gl::ClientVertexArrayType type,
9089                                const void *pointer,
9090                                ParamCapture *paramCapture)
9091 {
9092     paramCapture->value.voidConstPointerVal = pointer;
9093     if (!glState.getTargetBuffer(gl::BufferBinding::Array))
9094     {
9095         paramCapture->arrayClientPointerIndex =
9096             gl::GLES1Renderer::VertexArrayIndex(type, glState.gles1());
9097     }
9098 }
9099 
GetProgramForCapture(const gl::State & glState,gl::ShaderProgramID handle)9100 gl::Program *GetProgramForCapture(const gl::State &glState, gl::ShaderProgramID handle)
9101 {
9102     gl::Program *program = glState.getShaderProgramManagerForCapture().getProgram(handle);
9103     return program;
9104 }
9105 
CaptureGetActiveUniformBlockivParameters(const gl::State & glState,gl::ShaderProgramID handle,gl::UniformBlockIndex uniformBlockIndex,GLenum pname,ParamCapture * paramCapture)9106 void CaptureGetActiveUniformBlockivParameters(const gl::State &glState,
9107                                               gl::ShaderProgramID handle,
9108                                               gl::UniformBlockIndex uniformBlockIndex,
9109                                               GLenum pname,
9110                                               ParamCapture *paramCapture)
9111 {
9112     int numParams = 1;
9113 
9114     // From the OpenGL ES 3.0 spec:
9115     // If pname is UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, then a list of the
9116     // active uniform indices for the uniform block identified by uniformBlockIndex is
9117     // returned. The number of elements that will be written to params is the value of
9118     // UNIFORM_BLOCK_ACTIVE_UNIFORMS for uniformBlockIndex
9119     if (pname == GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES)
9120     {
9121         gl::Program *program = GetProgramForCapture(glState, handle);
9122         if (program)
9123         {
9124             gl::QueryActiveUniformBlockiv(program, uniformBlockIndex,
9125                                           GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &numParams);
9126         }
9127     }
9128 
9129     paramCapture->readBufferSizeBytes = sizeof(GLint) * numParams;
9130 }
9131 
CaptureGetParameter(const gl::State & glState,GLenum pname,size_t typeSize,ParamCapture * paramCapture)9132 void CaptureGetParameter(const gl::State &glState,
9133                          GLenum pname,
9134                          size_t typeSize,
9135                          ParamCapture *paramCapture)
9136 {
9137     // kMaxReportedCapabilities is the biggest array we'll need to hold data from glGet calls.
9138     // This value needs to be updated if any new extensions are introduced that would allow for
9139     // more compressed texture formats. The current value is taken from:
9140     // http://opengles.gpuinfo.org/displaycapability.php?name=GL_NUM_COMPRESSED_TEXTURE_FORMATS&esversion=2
9141     constexpr unsigned int kMaxReportedCapabilities = 69;
9142     paramCapture->readBufferSizeBytes               = typeSize * kMaxReportedCapabilities;
9143 }
9144 
CaptureGenHandlesImpl(GLsizei n,GLuint * handles,ParamCapture * paramCapture)9145 void CaptureGenHandlesImpl(GLsizei n, GLuint *handles, ParamCapture *paramCapture)
9146 {
9147     paramCapture->readBufferSizeBytes = sizeof(GLuint) * n;
9148     CaptureMemory(handles, paramCapture->readBufferSizeBytes, paramCapture);
9149 }
9150 
CaptureShaderStrings(GLsizei count,const GLchar * const * strings,const GLint * length,ParamCapture * paramCapture)9151 void CaptureShaderStrings(GLsizei count,
9152                           const GLchar *const *strings,
9153                           const GLint *length,
9154                           ParamCapture *paramCapture)
9155 {
9156     // Concat the array elements of the string into one data vector,
9157     // append the terminating zero and use this as the captured shader
9158     // string. The string count and the length array are adjusted
9159     // accordingly in the capture post-processing
9160 
9161     std::vector<uint8_t> data;
9162     size_t offset = 0;
9163     for (GLsizei index = 0; index < count; ++index)
9164     {
9165         size_t len = ((length && length[index] >= 0) ? length[index] : strlen(strings[index]));
9166 
9167         // Count trailing zeros
9168         uint32_t i = 1;
9169         while (i < len && strings[index][len - i] == 0)
9170         {
9171             i++;
9172         }
9173 
9174         // Don't copy trailing zeros
9175         len -= (i - 1);
9176 
9177         data.resize(offset + len);
9178         std::copy(strings[index], strings[index] + len, data.begin() + offset);
9179         offset += len;
9180     }
9181 
9182     data.push_back(0);
9183     paramCapture->data.emplace_back(std::move(data));
9184 }
9185 
9186 }  // namespace angle
9187 
9188 namespace egl
9189 {
CaptureAttributeMap(const egl::AttributeMap & attribMap)9190 angle::ParamCapture CaptureAttributeMap(const egl::AttributeMap &attribMap)
9191 {
9192     switch (attribMap.getType())
9193     {
9194         case AttributeMapType::Attrib:
9195         {
9196             angle::ParamCapture paramCapture("attrib_list", angle::ParamType::TEGLAttribPointer);
9197             if (attribMap.isEmpty())
9198             {
9199                 paramCapture.value.EGLAttribPointerVal = nullptr;
9200             }
9201             else
9202             {
9203                 std::vector<EGLAttrib> attribs;
9204                 for (const auto &[key, value] : attribMap)
9205                 {
9206                     attribs.push_back(key);
9207                     attribs.push_back(value);
9208                 }
9209                 attribs.push_back(EGL_NONE);
9210 
9211                 angle::CaptureMemory(attribs.data(), attribs.size() * sizeof(EGLAttrib),
9212                                      &paramCapture);
9213             }
9214             return paramCapture;
9215         }
9216 
9217         case AttributeMapType::Int:
9218         {
9219             angle::ParamCapture paramCapture("attrib_list", angle::ParamType::TEGLintPointer);
9220             if (attribMap.isEmpty())
9221             {
9222                 paramCapture.value.EGLintPointerVal = nullptr;
9223             }
9224             else
9225             {
9226                 std::vector<EGLint> attribs;
9227                 for (const auto &[key, value] : attribMap)
9228                 {
9229                     attribs.push_back(static_cast<EGLint>(key));
9230                     attribs.push_back(static_cast<EGLint>(value));
9231                 }
9232                 attribs.push_back(EGL_NONE);
9233 
9234                 angle::CaptureMemory(attribs.data(), attribs.size() * sizeof(EGLint),
9235                                      &paramCapture);
9236             }
9237             return paramCapture;
9238         }
9239 
9240         default:
9241             UNREACHABLE();
9242             return angle::ParamCapture();
9243     }
9244 }
9245 }  // namespace egl
9246