• 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.h:
7 //   ANGLE Frame capture interface.
8 //
9 
10 #ifndef LIBANGLE_FRAME_CAPTURE_H_
11 #define LIBANGLE_FRAME_CAPTURE_H_
12 
13 #include <fstream>
14 #include "sys/stat.h"
15 
16 #include "common/PackedEnums.h"
17 #include "common/SimpleMutex.h"
18 #include "common/frame_capture_utils.h"
19 #include "common/string_utils.h"
20 #include "common/system_utils.h"
21 #include "libANGLE/Context.h"
22 #include "libANGLE/ShareGroup.h"
23 #include "libANGLE/Thread.h"
24 #include "libANGLE/angletypes.h"
25 #include "libANGLE/entry_points_utils.h"
26 
27 #ifdef ANGLE_ENABLE_CL
28 #    include "libANGLE/CLPlatform.h"
29 #endif
30 
31 namespace gl
32 {
33 enum class BigGLEnum;
34 enum class GLESEnum;
35 }  // namespace gl
36 
37 namespace angle
38 {
39 // Helper to use unique IDs for each local data variable.
40 class DataCounters final : angle::NonCopyable
41 {
42   public:
43     DataCounters();
44     ~DataCounters();
45 
46     int getAndIncrement(EntryPoint entryPoint, const std::string &paramName);
reset()47     void reset() { mData.clear(); }
48 
49   private:
50     // <CallName, ParamName>
51     using Counter = std::pair<EntryPoint, std::string>;
52     std::map<Counter, int> mData;
53 };
54 
55 constexpr int kStringsNotFound = -1;
56 class StringCounters final : angle::NonCopyable
57 {
58   public:
59     StringCounters();
60     ~StringCounters();
61 
62     int getStringCounter(const std::vector<std::string> &str);
63     void setStringCounter(const std::vector<std::string> &str, int &counter);
reset()64     void reset() { mStringCounterMap.clear(); }
65 
66   private:
67     std::map<std::vector<std::string>, int> mStringCounterMap;
68 };
69 
70 class DataTracker final : angle::NonCopyable
71 {
72   public:
73     DataTracker();
74     ~DataTracker();
75 
getCounters()76     DataCounters &getCounters() { return mCounters; }
getStringCounters()77     StringCounters &getStringCounters() { return mStringCounters; }
78 
reset()79     void reset()
80     {
81         mCounters.reset();
82         mStringCounters.reset();
83     }
84 
85   private:
86     DataCounters mCounters;
87     StringCounters mStringCounters;
88 };
89 
90 enum class CaptureAPI : uint8_t
91 {
92     GL = 0,
93     CL = 1,
94 
95     InvalidEnum = 2,
96     EnumCount   = 2,
97 };
98 
99 class ReplayWriter final : angle::NonCopyable
100 {
101   public:
102     ReplayWriter();
103     ~ReplayWriter();
104 
105     void setSourceFileExtension(const char *ext);
106     void setSourceFileSizeThreshold(size_t sourceFileSizeThreshold);
107     void setFilenamePattern(const std::string &pattern);
108     void setSourcePrologue(const std::string &prologue);
109     void setHeaderPrologue(const std::string &prologue);
110 
111     void addPublicFunction(const std::string &functionProto,
112                            const std::stringstream &headerStream,
113                            const std::stringstream &bodyStream);
114     void addPrivateFunction(const std::string &functionProto,
115                             const std::stringstream &headerStream,
116                             const std::stringstream &bodyStream);
117     std::string getInlineVariableName(EntryPoint entryPoint, const std::string &paramName);
118 
119     std::string getInlineStringSetVariableName(EntryPoint entryPoint,
120                                                const std::string &paramName,
121                                                const std::vector<std::string> &strings,
122                                                bool *isNewEntryOut);
123 
124     void addStaticVariable(const std::string &customVarType, const std::string &customVarName);
125 
126     void saveFrame();
127     void saveFrameIfFull();
128     void saveIndexFilesAndHeader();
129     void saveSetupFile();
130 
131     std::vector<std::string> getAndResetWrittenFiles();
132 
reset()133     void reset()
134     {
135         mDataTracker.reset();
136         mFrameIndex = 1;  // This is really the FileIndex
137     }
138 
139     CaptureAPI captureAPI = CaptureAPI::GL;
140 
141   private:
142     static std::string GetVarName(EntryPoint entryPoint, const std::string &paramName, int counter);
143 
144     void saveHeader();
145     void writeReplaySource(const std::string &filename);
146     void addWrittenFile(const std::string &filename);
147     size_t getStoredReplaySourceSize() const;
148 
149     std::string mSourceFileExtension;
150     size_t mSourceFileSizeThreshold;
151     size_t mFrameIndex;
152 
153     DataTracker mDataTracker;
154     std::string mFilenamePattern;
155     std::string mSourcePrologue;
156     std::string mHeaderPrologue;
157 
158     std::vector<std::string> mReplayHeaders;
159     std::vector<std::string> mGlobalVariableDeclarations;
160     std::vector<std::string> mStaticVariableDeclarations;
161 
162     std::vector<std::string> mPublicFunctionPrototypes;
163     std::vector<std::string> mPublicFunctions;
164 
165     std::vector<std::string> mPrivateFunctionPrototypes;
166     std::vector<std::string> mPrivateFunctions;
167 
168     std::vector<std::string> mWrittenFiles;
169 };
170 
171 using BufferCalls = std::map<GLuint, std::vector<CallCapture>>;
172 
173 // true means mapped, false means unmapped
174 using BufferMapStatusMap = std::map<GLuint, bool>;
175 
176 using FenceSyncSet   = std::set<gl::SyncID>;
177 using FenceSyncCalls = std::map<gl::SyncID, std::vector<CallCapture>>;
178 
179 // For default uniforms, we need to track which ones are dirty, and the series of calls to reset.
180 // Each program has unique default uniforms, and each uniform has one or more locations in the
181 // default buffer. For reset efficiency, we track only the uniforms dirty by location, per program.
182 
183 // A set of all default uniforms (per program) that were modified during the run
184 using DefaultUniformLocationsSet = std::set<gl::UniformLocation>;
185 using DefaultUniformLocationsPerProgramMap =
186     std::map<gl::ShaderProgramID, DefaultUniformLocationsSet>;
187 
188 // A map of programs which maps to locations and their reset calls
189 using DefaultUniformCallsPerLocationMap = std::map<gl::UniformLocation, std::vector<CallCapture>>;
190 using DefaultUniformCallsPerProgramMap =
191     std::map<gl::ShaderProgramID, DefaultUniformCallsPerLocationMap>;
192 
193 using DefaultUniformBaseLocationMap =
194     std::map<std::pair<gl::ShaderProgramID, gl::UniformLocation>, gl::UniformLocation>;
195 
196 using ResourceSet   = std::set<GLuint>;
197 using ResourceCalls = std::map<GLuint, std::vector<CallCapture>>;
198 
199 class TrackedResource final : angle::NonCopyable
200 {
201   public:
202     TrackedResource();
203     ~TrackedResource();
204 
getStartingResources()205     const ResourceSet &getStartingResources() const { return mStartingResources; }
getStartingResources()206     ResourceSet &getStartingResources() { return mStartingResources; }
getNewResources()207     const ResourceSet &getNewResources() const { return mNewResources; }
getNewResources()208     ResourceSet &getNewResources() { return mNewResources; }
getResourcesToDelete()209     const ResourceSet &getResourcesToDelete() const { return mResourcesToDelete; }
getResourcesToDelete()210     ResourceSet &getResourcesToDelete() { return mResourcesToDelete; }
getResourcesToRegen()211     const ResourceSet &getResourcesToRegen() const { return mResourcesToRegen; }
getResourcesToRegen()212     ResourceSet &getResourcesToRegen() { return mResourcesToRegen; }
getResourcesToRestore()213     const ResourceSet &getResourcesToRestore() const { return mResourcesToRestore; }
getResourcesToRestore()214     ResourceSet &getResourcesToRestore() { return mResourcesToRestore; }
215 
216     void setGennedResource(GLuint id);
217     void setDeletedResource(GLuint id);
218     void setModifiedResource(GLuint id);
219     bool resourceIsGenerated(GLuint id);
220 
getResourceRegenCalls()221     ResourceCalls &getResourceRegenCalls() { return mResourceRegenCalls; }
getResourceRestoreCalls()222     ResourceCalls &getResourceRestoreCalls() { return mResourceRestoreCalls; }
223 
reset()224     void reset()
225     {
226         mResourceRegenCalls.clear();
227         mResourceRestoreCalls.clear();
228         mStartingResources.clear();
229         mNewResources.clear();
230         mResourcesToDelete.clear();
231         mResourcesToRegen.clear();
232         mResourcesToRestore.clear();
233     }
234 
235   private:
236     // Resource regen calls will gen a resource
237     ResourceCalls mResourceRegenCalls;
238     // Resource restore calls will restore the contents of a resource
239     ResourceCalls mResourceRestoreCalls;
240 
241     // Resources created during startup
242     ResourceSet mStartingResources;
243 
244     // Resources created during the run that need to be deleted
245     ResourceSet mNewResources;
246     // Resources recreated during the run that need to be deleted
247     ResourceSet mResourcesToDelete;
248     // Resources deleted during the run that need to be recreated
249     ResourceSet mResourcesToRegen;
250     // Resources modified during the run that need to be restored
251     ResourceSet mResourcesToRestore;
252 };
253 
254 using TrackedResourceArray =
255     std::array<TrackedResource, static_cast<uint32_t>(ResourceIDType::EnumCount)>;
256 
257 enum class ShaderProgramType
258 {
259     ShaderType,
260     ProgramType
261 };
262 
263 // Helper to track resource changes during the capture
264 class ResourceTracker final : angle::NonCopyable
265 {
266   public:
267     ResourceTracker();
268     ~ResourceTracker();
269 
getBufferMapCalls()270     BufferCalls &getBufferMapCalls() { return mBufferMapCalls; }
getBufferUnmapCalls()271     BufferCalls &getBufferUnmapCalls() { return mBufferUnmapCalls; }
272 
getBufferBindingCalls()273     std::vector<CallCapture> &getBufferBindingCalls() { return mBufferBindingCalls; }
274 
275     void setBufferMapped(gl::ContextID contextID, GLuint id);
276     void setBufferUnmapped(gl::ContextID contextID, GLuint id);
277 
278     bool getStartingBuffersMappedCurrent(GLuint id) const;
279     bool getStartingBuffersMappedInitial(GLuint id) const;
280 
setStartingBufferMapped(GLuint id,bool mapped)281     void setStartingBufferMapped(GLuint id, bool mapped)
282     {
283         // Track the current state (which will change throughout the trace)
284         mStartingBuffersMappedCurrent[id] = mapped;
285 
286         // And the initial state, to compare during frame loop reset
287         mStartingBuffersMappedInitial[id] = mapped;
288     }
289 
290     void onShaderProgramAccess(gl::ShaderProgramID shaderProgramID);
getMaxShaderPrograms()291     uint32_t getMaxShaderPrograms() const { return mMaxShaderPrograms; }
292 
getStartingFenceSyncs()293     FenceSyncSet &getStartingFenceSyncs() { return mStartingFenceSyncs; }
getFenceSyncRegenCalls()294     FenceSyncCalls &getFenceSyncRegenCalls() { return mFenceSyncRegenCalls; }
getFenceSyncsToRegen()295     FenceSyncSet &getFenceSyncsToRegen() { return mFenceSyncsToRegen; }
296     void setDeletedFenceSync(gl::SyncID sync);
297 
getDefaultUniformsToReset()298     DefaultUniformLocationsPerProgramMap &getDefaultUniformsToReset()
299     {
300         return mDefaultUniformsToReset;
301     }
getDefaultUniformResetCalls(gl::ShaderProgramID id)302     DefaultUniformCallsPerLocationMap &getDefaultUniformResetCalls(gl::ShaderProgramID id)
303     {
304         return mDefaultUniformResetCalls[id];
305     }
306     void setModifiedDefaultUniform(gl::ShaderProgramID programID, gl::UniformLocation location);
307     void setDefaultUniformBaseLocation(gl::ShaderProgramID programID,
308                                        gl::UniformLocation location,
309                                        gl::UniformLocation baseLocation);
getDefaultUniformBaseLocation(gl::ShaderProgramID programID,gl::UniformLocation location)310     gl::UniformLocation getDefaultUniformBaseLocation(gl::ShaderProgramID programID,
311                                                       gl::UniformLocation location)
312     {
313         ASSERT(mDefaultUniformBaseLocations.find({programID, location}) !=
314                mDefaultUniformBaseLocations.end());
315         return mDefaultUniformBaseLocations[{programID, location}];
316     }
317 
318     TrackedResource &getTrackedResource(gl::ContextID contextID, ResourceIDType type);
319 
320     void getContextIDs(std::set<gl::ContextID> &idsOut);
321 
getImageToAttribTable()322     std::map<EGLImage, egl::AttributeMap> &getImageToAttribTable() { return mMatchImageToAttribs; }
323 
getTextureIDToImageTable()324     std::map<GLuint, egl::ImageID> &getTextureIDToImageTable() { return mMatchTextureIDToImage; }
325 
setShaderProgramType(gl::ShaderProgramID id,angle::ShaderProgramType type)326     void setShaderProgramType(gl::ShaderProgramID id, angle::ShaderProgramType type)
327     {
328         mShaderProgramType[id] = type;
329     }
getShaderProgramType(gl::ShaderProgramID id)330     ShaderProgramType getShaderProgramType(gl::ShaderProgramID id)
331     {
332         ASSERT(mShaderProgramType.find(id) != mShaderProgramType.end());
333         return mShaderProgramType[id];
334     }
335 
resetTrackedResourceArray(TrackedResourceArray & trackedResourceArray)336     void resetTrackedResourceArray(TrackedResourceArray &trackedResourceArray)
337     {
338         for (auto &trackedResource : trackedResourceArray)
339         {
340             trackedResource.reset();
341         }
342     }
343 
344     // Some data in FrameCaptureShared tracks resources across all captures while
345     // other data is tracked per-capture. This function is responsible for
346     // resetting the per-capture tracking data in this class.
resetResourceTracking()347     void resetResourceTracking()
348     {
349         resetTrackedResourceArray(mTrackedResourcesShared);
350         for (auto &pair : mTrackedResourcesPerContext)
351         {
352             resetTrackedResourceArray(pair.second);
353         }
354 
355         mBufferMapCalls.clear();
356         mBufferUnmapCalls.clear();
357         mBufferBindingCalls.clear();
358         mStartingBuffersMappedInitial.clear();
359         mStartingBuffersMappedCurrent.clear();
360         mMaxShaderPrograms = 0;
361         mStartingFenceSyncs.clear();
362         mFenceSyncRegenCalls.clear();
363         mFenceSyncsToRegen.clear();
364         mDefaultUniformsToReset.clear();
365         mDefaultUniformResetCalls.clear();
366         mDefaultUniformBaseLocations.clear();
367     }
368 
369   private:
370     // These data structures are per-capture and must be reset before beginning a new
371     // capture in the resetResourceTracking() function above
372 
373     // Buffer map calls will map a buffer with correct offset, length, and access flags
374     BufferCalls mBufferMapCalls;
375     // Buffer unmap calls will bind and unmap a given buffer
376     BufferCalls mBufferUnmapCalls;
377     // Buffer binding calls to restore bindings recorded during MEC
378     std::vector<CallCapture> mBufferBindingCalls;
379     // Whether a given buffer was mapped at the start of the trace
380     BufferMapStatusMap mStartingBuffersMappedInitial;
381     // The status of buffer mapping throughout the trace, modified with each Map/Unmap call
382     BufferMapStatusMap mStartingBuffersMappedCurrent;
383     // Maximum accessed shader program ID.
384     uint32_t mMaxShaderPrograms = 0;
385     // Fence sync objects created during MEC setup
386     FenceSyncSet mStartingFenceSyncs;
387     // Fence sync regen calls will create a fence sync objects
388     FenceSyncCalls mFenceSyncRegenCalls;
389     // Fence syncs to regen are a list of starting fence sync objects that were deleted and need to
390     // be regen'ed.
391     FenceSyncSet mFenceSyncsToRegen;
392     // Default uniforms that were modified during the run
393     DefaultUniformLocationsPerProgramMap mDefaultUniformsToReset;
394     // Calls per default uniform to return to original state
395     DefaultUniformCallsPerProgramMap mDefaultUniformResetCalls;
396     // Base location of arrayed uniforms
397     DefaultUniformBaseLocationMap mDefaultUniformBaseLocations;
398 
399     // These data structures must be preserved across all captures
400 
401     // Tracked resources per context
402     TrackedResourceArray mTrackedResourcesShared;
403     std::map<gl::ContextID, TrackedResourceArray> mTrackedResourcesPerContext;
404     std::map<EGLImage, egl::AttributeMap> mMatchImageToAttribs;
405     std::map<GLuint, egl::ImageID> mMatchTextureIDToImage;
406     std::map<gl::ShaderProgramID, ShaderProgramType> mShaderProgramType;
407 };
408 
409 // CL specific resource tracker to track resource changes during the capture
410 #ifdef ANGLE_ENABLE_CL
411 struct ResourceTrackerCL final : angle::NonCopyable
412 {
413     ResourceTrackerCL();
414     ~ResourceTrackerCL();
415 
416     // To obtain indices of CL arguments in replay
417     std::unordered_map<cl_platform_id, size_t> mCLPlatformIDIndices;
418     std::unordered_map<cl_device_id, size_t> mCLDeviceIDIndices;
419     std::unordered_map<cl_context, size_t> mCLContextIndices;
420     std::unordered_map<cl_event, size_t> mCLEventsIndices;
421     std::unordered_map<cl_command_queue, size_t> mCLCommandQueueIndices;
422     std::unordered_map<cl_mem, size_t> mCLMemIndices;
423     std::unordered_map<cl_sampler, size_t> mCLSamplerIndices;
424     std::unordered_map<cl_program, size_t> mCLProgramIndices;
425     std::unordered_map<cl_kernel, size_t> mCLKernelIndices;
426 
427     std::unordered_map<const void *, size_t> mCLVoidIndices;
428 
429     std::unordered_map<uint32_t, std::vector<size_t>> mCLParamIDToIndexVector;
430 
431     // To account for cl mem or SVM pointers that are potentially dirty
432     // coming into the starting frame or from mapping and unmapping.
433     std::vector<cl_mem> mCLDirtyMem;
434     std::vector<void *> mCLDirtySVM;
435 
436     // Keeps track of the # of times the program is linked, including it's own creation
437     std::unordered_map<cl_program, cl_uint> mCLProgramLinkCounter;
438 
439     // To keep track of the sub buffer and parent replationship
440     std::unordered_map<cl_mem, cl_mem> mCLSubBufferToParent;
441 
442     // To keep track of the linked programs
443     std::unordered_map<cl_program, std::vector<cl_program>> mCLLinkedPrograms;
444 
445     // Program to all the kernels in the program
446     // So that when a program is released, it can also remove all the kernels.
447     std::unordered_map<cl_program, std::vector<cl_kernel>> mCLProgramToKernels;
448 
449     // Kernel to program, to keep track of the program that a cloned kernel
450     // belongs to. Can't use ANGLE's getProgram() because the kernel object
451     // may be deleted by the time it's needed for capture.
452     std::unordered_map<cl_kernel, cl_program> mCLKernelToProgram;
453 
454     // Mapped pointer to the map call
455     std::unordered_map<const void *, CallCapture> mCLMapCall;
456 
457     // Gets the size of the SVM memory
458     std::unordered_map<const void *, size_t> SVMToSize;
459 
460     cl_command_queue mCLCurrentCommandQueue;
461 
462     std::vector<ParamCapture> mCLResetObjs;
463 };
464 #endif
465 
466 // Used by the CPP replay to filter out unnecessary code.
467 using HasResourceTypeMap = angle::PackedEnumBitSet<ResourceIDType>;
468 
469 // Map of ResourceType to IDs and range of setup calls
470 using ResourceIDToSetupCallsMap =
471     PackedEnumMap<ResourceIDType, std::map<GLuint, gl::Range<size_t>>>;
472 
473 // Map of buffer ID to offset and size used when mapped
474 using BufferDataMap = std::map<gl::BufferID, std::pair<GLintptr, GLsizeiptr>>;
475 
476 // A dictionary of sources indexed by shader type.
477 using ProgramSources = gl::ShaderMap<std::string>;
478 
479 // Maps from IDs to sources.
480 using ShaderSourceMap  = std::map<gl::ShaderProgramID, std::string>;
481 using ProgramSourceMap = std::map<gl::ShaderProgramID, ProgramSources>;
482 
483 // Map from textureID to level and data
484 using TextureLevels       = std::map<GLint, std::vector<uint8_t>>;
485 using TextureLevelDataMap = std::map<gl::TextureID, TextureLevels>;
486 
487 struct SurfaceParams
488 {
489     gl::Extents extents;
490     egl::ColorSpace colorSpace;
491 };
492 
493 // Map from ContextID to SurfaceParams
494 using SurfaceParamsMap = std::map<gl::ContextID, SurfaceParams>;
495 
496 using CallVector = std::vector<std::vector<CallCapture> *>;
497 
498 // A map from API entry point to calls
499 using CallResetMap = std::map<angle::EntryPoint, std::vector<CallCapture>>;
500 
501 using TextureBinding  = std::pair<size_t, gl::TextureType>;
502 using TextureResetMap = std::map<TextureBinding, gl::TextureID>;
503 
504 using BufferBindingPair = std::pair<gl::BufferBinding, gl::BufferID>;
505 
506 // StateResetHelper provides a simple way to track whether an entry point has been called during the
507 // trace, along with the reset calls to get it back to starting state.  This is useful for things
508 // that are one dimensional, like context bindings or context state.
509 class StateResetHelper final : angle::NonCopyable
510 {
511   public:
512     StateResetHelper();
513     ~StateResetHelper();
514 
getDirtyEntryPoints()515     const std::set<angle::EntryPoint> &getDirtyEntryPoints() const { return mDirtyEntryPoints; }
setEntryPointDirty(EntryPoint entryPoint)516     void setEntryPointDirty(EntryPoint entryPoint) { mDirtyEntryPoints.insert(entryPoint); }
517 
getResetCalls()518     CallResetMap &getResetCalls() { return mResetCalls; }
getResetCalls()519     const CallResetMap &getResetCalls() const { return mResetCalls; }
520 
521     void setDefaultResetCalls(const gl::Context *context, angle::EntryPoint);
522 
getDirtyTextureBindings()523     const std::set<TextureBinding> &getDirtyTextureBindings() const
524     {
525         return mDirtyTextureBindings;
526     }
setTextureBindingDirty(size_t unit,gl::TextureType target)527     void setTextureBindingDirty(size_t unit, gl::TextureType target)
528     {
529         mDirtyTextureBindings.emplace(unit, target);
530     }
531 
getResetTextureBindings()532     TextureResetMap &getResetTextureBindings() { return mResetTextureBindings; }
533 
setResetActiveTexture(size_t textureID)534     void setResetActiveTexture(size_t textureID) { mResetActiveTexture = textureID; }
getResetActiveTexture()535     size_t getResetActiveTexture() { return mResetActiveTexture; }
536 
getDirtyBufferBindings()537     const std::set<gl::BufferBinding> &getDirtyBufferBindings() const
538     {
539         return mDirtyBufferBindings;
540     }
setBufferBindingDirty(gl::BufferBinding binding)541     void setBufferBindingDirty(gl::BufferBinding binding) { mDirtyBufferBindings.insert(binding); }
542 
getStartingBufferBindings()543     const std::set<BufferBindingPair> &getStartingBufferBindings() const
544     {
545         return mStartingBufferBindings;
546     }
setStartingBufferBinding(gl::BufferBinding binding,gl::BufferID bufferID)547     void setStartingBufferBinding(gl::BufferBinding binding, gl::BufferID bufferID)
548     {
549         mStartingBufferBindings.insert({binding, bufferID});
550     }
551 
reset()552     void reset()
553     {
554         mDirtyEntryPoints.clear();
555         mResetCalls.clear();
556         mDirtyTextureBindings.clear();
557         mResetTextureBindings.clear();
558         mResetActiveTexture = 0;
559         mStartingBufferBindings.clear();
560         mDirtyBufferBindings.clear();
561     }
562 
563   private:
564     // Dirty state per entry point
565     std::set<angle::EntryPoint> mDirtyEntryPoints;
566 
567     // Reset calls per API entry point
568     CallResetMap mResetCalls;
569 
570     // Dirty state per texture binding
571     std::set<TextureBinding> mDirtyTextureBindings;
572 
573     // Texture bindings and active texture to restore
574     TextureResetMap mResetTextureBindings;
575     size_t mResetActiveTexture = 0;
576 
577     // Starting and dirty buffer bindings
578     std::set<BufferBindingPair> mStartingBufferBindings;
579     std::set<gl::BufferBinding> mDirtyBufferBindings;
580 };
581 
582 class FrameCapture final : angle::NonCopyable
583 {
584   public:
585     FrameCapture();
586     ~FrameCapture();
587 
getSetupCalls()588     std::vector<CallCapture> &getSetupCalls() { return mSetupCalls; }
clearSetupCalls()589     void clearSetupCalls() { mSetupCalls.clear(); }
590 
getStateResetHelper()591     StateResetHelper &getStateResetHelper() { return mStateResetHelper; }
592 
593     void reset();
594 
595   private:
596     std::vector<CallCapture> mSetupCalls;
597 
598     StateResetHelper mStateResetHelper;
599 };
600 
601 // Page range inside a coherent buffer
602 struct PageRange
603 {
604     PageRange(size_t start, size_t end);
605     ~PageRange();
606 
607     // Relative start page
608     size_t start;
609 
610     // First page after the relative end
611     size_t end;
612 };
613 
614 // Memory address range defined by start and size
615 struct AddressRange
616 {
617     AddressRange();
618     AddressRange(uintptr_t start, size_t size);
619     ~AddressRange();
620 
621     uintptr_t end();
622 
623     uintptr_t start;
624     size_t size;
625 };
626 
627 // Used to handle protection of buffers that overlap in pages.
628 enum class PageSharingType
629 {
630     NoneShared,
631     FirstShared,
632     LastShared,
633     FirstAndLastShared
634 };
635 
636 class CoherentBuffer
637 {
638   public:
639     CoherentBuffer(uintptr_t start, size_t size, size_t pageSize, bool useShadowMemory);
640     ~CoherentBuffer();
641 
642     // Sets the a range in the buffer clean and protects a selected range
643     void protectPageRange(const PageRange &pageRange);
644 
645     // Sets all pages to clean and enables protection
646     void protectAll();
647 
648     // Sets a page dirty state and sets it's protection
649     void setDirty(size_t relativePage, bool dirty);
650 
651     // Shadow memory synchronization
652     void updateBufferMemory();
653     void updateShadowMemory();
654 
655     // Removes protection
656     void removeProtection(PageSharingType sharingType);
657 
658     bool contains(size_t page, size_t *relativePage);
659     bool isDirty();
660 
661     // Returns dirty page ranges
662     std::vector<PageRange> getDirtyPageRanges();
663 
664     // Calculates address range from page range
665     AddressRange getDirtyAddressRange(const PageRange &dirtyPageRange);
666     AddressRange getRange();
667 
markShadowDirty()668     void markShadowDirty() { mShadowDirty = true; }
isShadowDirty()669     bool isShadowDirty() { return mShadowDirty; }
670 
671   private:
672     // Actual buffer start and size
673     AddressRange mRange;
674 
675     // Start and size of page aligned protected area
676     AddressRange mProtectionRange;
677 
678     // Start and end of protection in relative pages, calculated from mProtectionRange.
679     size_t mProtectionStartPage;
680     size_t mProtectionEndPage;
681 
682     size_t mPageCount;
683     size_t mPageSize;
684 
685     // Clean pages are protected
686     std::vector<bool> mDirtyPages;
687 
688     // shadow memory releated fields
689     bool mShadowMemoryEnabled;
690     uintptr_t mBufferStart;
691     void *mShadowMemory;
692     bool mShadowDirty;
693 };
694 
695 class CoherentBufferTracker final : angle::NonCopyable
696 {
697   public:
698     CoherentBufferTracker();
699     ~CoherentBufferTracker();
700 
701     bool isDirty(gl::BufferID id);
702     uintptr_t addBuffer(gl::BufferID id, uintptr_t start, size_t size);
703     void removeBuffer(gl::BufferID id);
704     void disable();
705     void enable();
706     void onEndFrame();
707     bool haveBuffer(gl::BufferID id);
isShadowMemoryEnabled()708     bool isShadowMemoryEnabled() { return mShadowMemoryEnabled; }
enableShadowMemory()709     void enableShadowMemory() { mShadowMemoryEnabled = true; }
710     void maybeUpdateShadowMemory();
711     void markAllShadowDirty();
712     // Determine whether memory protection can be used directly on graphics memory
713     bool canProtectDirectly(gl::Context *context);
714 
715   private:
716     // Detect overlapping pages when removing protection
717     PageSharingType doesBufferSharePage(gl::BufferID id);
718 
719     // Returns a map to found buffers and the corresponding pages for a given address.
720     // For addresses that are in a page shared by 2 buffers, 2 results are returned.
721     HashMap<std::shared_ptr<CoherentBuffer>, size_t> getBufferPagesForAddress(uintptr_t address);
722     PageFaultHandlerRangeType handleWrite(uintptr_t address);
723 
724   public:
725     angle::SimpleMutex mMutex;
726     HashMap<GLuint, std::shared_ptr<CoherentBuffer>> mBuffers;
hasBeenReset()727     bool hasBeenReset() { return mHasBeenReset; }
728 
729   private:
730     bool mEnabled;
731     bool mHasBeenReset;
732     std::unique_ptr<PageFaultHandler> mPageFaultHandler;
733     size_t mPageSize;
734 
735     bool mShadowMemoryEnabled;
736 };
737 
738 // Shared class for any items that need to be tracked by FrameCapture across shared contexts
739 class FrameCaptureShared final : angle::NonCopyable
740 {
741   public:
742     FrameCaptureShared();
743     ~FrameCaptureShared();
744 
745     void captureCall(gl::Context *context, CallCapture &&call, bool isCallValid);
746     void checkForCaptureTrigger();
747     void onEndFrame(gl::Context *context);
748     void onDestroyContext(const gl::Context *context);
749     bool onEndCLCapture();
750     void onMakeCurrent(const gl::Context *context, const egl::Surface *drawSurface);
enabled()751     bool enabled() const { return mEnabled; }
752 
753     bool isCapturing() const;
754     uint32_t getFrameCount() const;
755 
756     // Returns a frame index starting from "1" as the first frame.
757     uint32_t getReplayFrameIndex() const;
758 
759 #ifdef ANGLE_ENABLE_CL
760     void captureCLCall(CallCapture &&call, bool isCallValid);
761     static void onCLProgramEnd();
762 
763     template <typename T>
getIndex(const T * object)764     size_t getIndex(const T *object)
765     {
766         if (getMap<T>().find(*object) == getMap<T>().end())
767         {
768             return SIZE_MAX;
769         }
770         return getMap<T>()[*object];
771     }
772     size_t getCLVoidIndex(const void *v);
773     std::vector<size_t> getCLObjVector(const angle::ParamCapture *paramCaptureKey);
774 
775     template <typename T>
setIndex(const T * object)776     void setIndex(const T *object)
777     {
778         if (getMap<T>().find(*object) == getMap<T>().end())
779         {
780             size_t tempSize      = getMap<T>().size();
781             getMap<T>()[*object] = tempSize;
782         }
783     }
784     void setCLPlatformIndices(cl_platform_id *platforms, size_t numPlatforms);
785     void setCLDeviceIndices(cl_device_id *devices, size_t numDevices);
786     void setCLVoidIndex(const void *v);
787     void setOffsetsVector(const void *args,
788                           const void **argsLocations,
789                           size_t numLocations,
790                           const angle::ParamCapture *paramCaptureKey);
791     void setCLVoidVectorIndex(const void *pointers[],
792                               size_t numPointers,
793                               const angle::ParamCapture *paramCaptureKey);
794 
795     template <typename T>
796     using MemberFuncPtr = size_t (FrameCaptureShared::*)(const T *);
797 
798     template <typename T>
setCLObjVectorMap(const T * objs,size_t numObjs,const angle::ParamCapture * paramCaptureKey,MemberFuncPtr<const T> getCLObjIndexFunc)799     void setCLObjVectorMap(const T *objs,
800                            size_t numObjs,
801                            const angle::ParamCapture *paramCaptureKey,
802                            MemberFuncPtr<const T> getCLObjIndexFunc)
803     {
804         mResourceTrackerCL.mCLParamIDToIndexVector[paramCaptureKey->uniqueID] =
805             std::vector<size_t>();
806         for (size_t i = 0; i < numObjs; ++i)
807         {
808             mResourceTrackerCL.mCLParamIDToIndexVector[paramCaptureKey->uniqueID].push_back(
809                 (this->*getCLObjIndexFunc)(&objs[i]));
810         }
811     }
812 
813     template <typename T>
814     std::unordered_map<T, size_t> &getMap();
815 
816     void addCLResetObj(const angle::ParamCapture &param);
817     void removeCLResetObj(const ParamCapture &param);
818     void printCLResetObjs(std::stringstream &stream);
819 
820     void trackCLMemUpdate(const cl_mem *mem, bool created);
821     void trackCLProgramUpdate(const cl_program *program,
822                               bool referenced,
823                               cl_uint numLinkedPrograms,
824                               const cl_program *linkedPrograms);
825     void trackCLEvents(const cl_event *event, bool created);
826     void injectMemcpy(void *src, void *dest, size_t size, std::vector<CallCapture> *calls);
827     void captureUpdateCLObjs(std::vector<CallCapture> *calls);
828     void removeCLMemOccurrences(const cl_mem *mem, std::vector<CallCapture> *calls);
829     void removeCLKernelOccurrences(const cl_kernel *kernel, std::vector<CallCapture> *calls);
830     void removeCLProgramOccurrences(const cl_program *program, std::vector<CallCapture> *calls);
831     void removeCLCall(std::vector<CallCapture> *callVector, size_t &callIndex);
832 #endif
833 
834     void trackBufferMapping(const gl::Context *context,
835                             CallCapture *call,
836                             gl::BufferID id,
837                             gl::Buffer *buffer,
838                             GLintptr offset,
839                             GLsizeiptr length,
840                             bool writable,
841                             bool coherent);
842 
843     void trackTextureUpdate(const gl::Context *context, const CallCapture &call);
844     void trackImageUpdate(const gl::Context *context, const CallCapture &call);
845     void trackDefaultUniformUpdate(const gl::Context *context, const CallCapture &call);
846     void trackVertexArrayUpdate(const gl::Context *context, const CallCapture &call);
847 
848     const std::string &getShaderSource(gl::ShaderProgramID id) const;
849     void setShaderSource(gl::ShaderProgramID id, std::string sources);
850 
851     const ProgramSources &getProgramSources(gl::ShaderProgramID id) const;
852     void setProgramSources(gl::ShaderProgramID id, ProgramSources sources);
853 
854     // Load data from a previously stored texture level
855     const std::vector<uint8_t> &retrieveCachedTextureLevel(gl::TextureID id,
856                                                            gl::TextureTarget target,
857                                                            GLint level);
858 
859     // Create new texture level data and copy the source into it
860     void copyCachedTextureLevel(const gl::Context *context,
861                                 gl::TextureID srcID,
862                                 GLint srcLevel,
863                                 gl::TextureID dstID,
864                                 GLint dstLevel,
865                                 const CallCapture &call);
866 
867     // Create the location that should be used to cache texture level data
868     std::vector<uint8_t> &getCachedTextureLevelData(gl::Texture *texture,
869                                                     gl::TextureTarget target,
870                                                     GLint level,
871                                                     EntryPoint entryPoint);
872 
873     // Capture coherent buffer storages
874     void captureCoherentBufferSnapshot(const gl::Context *context, gl::BufferID bufferID);
875 
876     // Remove any cached texture levels on deletion
877     void deleteCachedTextureLevelData(gl::TextureID id);
878 
eraseBufferDataMapEntry(const gl::BufferID bufferId)879     void eraseBufferDataMapEntry(const gl::BufferID bufferId)
880     {
881         const auto &bufferDataInfo = mBufferDataMap.find(bufferId);
882         if (bufferDataInfo != mBufferDataMap.end())
883         {
884             mBufferDataMap.erase(bufferDataInfo);
885         }
886     }
887 
hasBufferData(gl::BufferID bufferID)888     bool hasBufferData(gl::BufferID bufferID)
889     {
890         const auto &bufferDataInfo = mBufferDataMap.find(bufferID);
891         if (bufferDataInfo != mBufferDataMap.end())
892         {
893             return true;
894         }
895         return false;
896     }
897 
getBufferDataOffsetAndLength(gl::BufferID bufferID)898     std::pair<GLintptr, GLsizeiptr> getBufferDataOffsetAndLength(gl::BufferID bufferID)
899     {
900         const auto &bufferDataInfo = mBufferDataMap.find(bufferID);
901         ASSERT(bufferDataInfo != mBufferDataMap.end());
902         return bufferDataInfo->second;
903     }
904 
setCaptureActive()905     void setCaptureActive() { mCaptureActive = true; }
setCaptureInactive()906     void setCaptureInactive() { mCaptureActive = false; }
isCaptureActive()907     bool isCaptureActive() { return mCaptureActive; }
usesMidExecutionCapture()908     bool usesMidExecutionCapture() { return mCaptureStartFrame > 1; }
909 
getWindowSurfaceContextID()910     gl::ContextID getWindowSurfaceContextID() const { return mWindowSurfaceContextID; }
911 
912     void markResourceSetupCallsInactive(std::vector<CallCapture> *setupCalls,
913                                         ResourceIDType type,
914                                         GLuint id,
915                                         gl::Range<size_t> range);
916 
917     void getOutputDirectory();
updateReadBufferSize(size_t readBufferSize)918     void updateReadBufferSize(size_t readBufferSize)
919     {
920         mReadBufferSize = std::max(mReadBufferSize, readBufferSize);
921     }
922 
923     template <typename ResourceType>
handleGennedResource(const gl::Context * context,ResourceType resourceID)924     void handleGennedResource(const gl::Context *context, ResourceType resourceID)
925     {
926         if (isCaptureActive())
927         {
928             ResourceIDType idType    = GetResourceIDTypeFromType<ResourceType>::IDType;
929             TrackedResource &tracker = mResourceTracker.getTrackedResource(context->id(), idType);
930             tracker.setGennedResource(resourceID.value);
931         }
932     }
933 
934     template <typename ResourceType>
resourceIsGenerated(const gl::Context * context,ResourceType resourceID)935     bool resourceIsGenerated(const gl::Context *context, ResourceType resourceID)
936     {
937         ResourceIDType idType    = GetResourceIDTypeFromType<ResourceType>::IDType;
938         TrackedResource &tracker = mResourceTracker.getTrackedResource(context->id(), idType);
939         return tracker.resourceIsGenerated(resourceID.value);
940     }
941 
942     template <typename ResourceType>
handleDeletedResource(const gl::Context * context,ResourceType resourceID)943     void handleDeletedResource(const gl::Context *context, ResourceType resourceID)
944     {
945         if (isCaptureActive())
946         {
947             ResourceIDType idType    = GetResourceIDTypeFromType<ResourceType>::IDType;
948             TrackedResource &tracker = mResourceTracker.getTrackedResource(context->id(), idType);
949             tracker.setDeletedResource(resourceID.value);
950         }
951     }
952 
953     void *maybeGetShadowMemoryPointer(gl::Buffer *buffer, GLsizeiptr length, GLbitfield access);
954     void determineMemoryProtectionSupport(gl::Context *context);
955 
getFrameCaptureMutex()956     angle::SimpleMutex &getFrameCaptureMutex() { return mFrameCaptureMutex; }
957 
setDeferredLinkProgram(gl::ShaderProgramID programID)958     void setDeferredLinkProgram(gl::ShaderProgramID programID)
959     {
960         mDeferredLinkPrograms.emplace(programID);
961     }
isDeferredLinkProgram(gl::ShaderProgramID programID)962     bool isDeferredLinkProgram(gl::ShaderProgramID programID)
963     {
964         return (mDeferredLinkPrograms.find(programID) != mDeferredLinkPrograms.end());
965     }
966 
967     static bool isRuntimeEnabled();
968 
resetCaptureStartEndFrames()969     void resetCaptureStartEndFrames()
970     {
971         // If the trigger has been populated the frame range variables will be calculated
972         // based on the trigger value, so for now reset them to unreasonable values.
973         mCaptureStartFrame = mCaptureEndFrame = std::numeric_limits<uint32_t>::max();
974         INFO() << "Capture trigger detected, resetting capture start/end frame.";
975     }
976 
977   private:
978     void writeJSON(const gl::Context *context);
979     void writeJSONCL();
980     void writeJSONCLGetInfo();
981     void saveCLGetInfo(const CallCapture &call);
982     void writeCppReplayIndexFiles(const gl::Context *context, bool writeResetContextCall);
983     void writeCppReplayIndexFilesCL();
984     void writeMainContextCppReplay(const gl::Context *context,
985                                    const std::vector<CallCapture> &setupCalls,
986                                    StateResetHelper &StateResetHelper);
987     void writeMainContextCppReplayCL();
988 
989     void captureClientArraySnapshot(const gl::Context *context,
990                                     size_t vertexCount,
991                                     size_t instanceCount);
992     void captureMappedBufferSnapshot(const gl::Context *context, const CallCapture &call);
993 
994     void copyCompressedTextureData(const gl::Context *context, const CallCapture &call);
995     void captureCompressedTextureData(const gl::Context *context, const CallCapture &call);
996 
997     void reset();
998     void resetMidExecutionCapture(gl::Context *context);
999     void maybeOverrideEntryPoint(const gl::Context *context,
1000                                  CallCapture &call,
1001                                  std::vector<CallCapture> &newCalls);
1002     void maybeCapturePreCallUpdates(const gl::Context *context,
1003                                     CallCapture &call,
1004                                     std::vector<CallCapture> *shareGroupSetupCalls,
1005                                     ResourceIDToSetupCallsMap *resourceIDToSetupCalls);
1006     void maybeCapturePreCallUpdatesCL(CallCapture &call);
1007     template <typename ParamValueType>
1008     void maybeGenResourceOnBind(const gl::Context *context, CallCapture &call);
1009     void maybeCapturePostCallUpdates(const gl::Context *context);
1010     void maybeCapturePostCallUpdatesCL();
1011     void maybeCaptureDrawArraysClientData(const gl::Context *context,
1012                                           CallCapture &call,
1013                                           size_t instanceCount);
1014     void maybeCaptureDrawElementsClientData(const gl::Context *context,
1015                                             CallCapture &call,
1016                                             size_t instanceCount);
1017     void maybeCaptureCoherentBuffers(const gl::Context *context);
1018     void captureCustomMapBufferFromContext(const gl::Context *context,
1019                                            const char *entryPointName,
1020                                            CallCapture &call,
1021                                            std::vector<CallCapture> &callsOut);
1022     void updateCopyImageSubData(CallCapture &call);
1023     void overrideProgramBinary(const gl::Context *context,
1024                                CallCapture &call,
1025                                std::vector<CallCapture> &outCalls);
1026     void updateResourceCountsFromParamCapture(const ParamCapture &param, ResourceIDType idType);
1027     void updateResourceCountsFromParamCaptureCL(const ParamCapture &param, const CallCapture &call);
1028     void updateResourceCountsFromCallCapture(const CallCapture &call);
1029     void updateResourceCountsFromCallCaptureCL(const CallCapture &call);
1030 
1031     void runMidExecutionCapture(gl::Context *context);
1032 
1033     void scanSetupCalls(std::vector<CallCapture> &setupCalls);
1034 
1035     std::vector<CallCapture> mFrameCalls;
1036 
1037     // We save one large buffer of binary data for the whole CPP replay.
1038     // This simplifies a lot of file management.
1039     std::vector<uint8_t> mBinaryData;
1040 
1041     bool mEnabled;
1042     static bool mRuntimeEnabled;
1043     static bool mRuntimeInitialized;
1044     bool mSerializeStateEnabled;
1045     std::string mOutDirectory;
1046     std::string mCaptureLabel;
1047     bool mCompression;
1048     gl::AttribArray<int> mClientVertexArrayMap;
1049     uint32_t mFrameIndex;
1050     uint32_t mCaptureStartFrame;
1051     uint32_t mCaptureEndFrame;
1052     bool mIsFirstFrame   = true;
1053     bool mWroteIndexFile = false;
1054     SurfaceParamsMap mDrawSurfaceParams;
1055     gl::AttribArray<size_t> mClientArraySizes;
1056     size_t mReadBufferSize;
1057     size_t mResourceIDBufferSize;
1058     HasResourceTypeMap mHasResourceType;
1059     ResourceIDToSetupCallsMap mResourceIDToSetupCalls;
1060     BufferDataMap mBufferDataMap;
1061     bool mValidateSerializedState = false;
1062     std::string mValidationExpression;
1063     PackedEnumMap<ResourceIDType, uint32_t> mMaxAccessedResourceIDs;
1064     std::map<ParamType, uint32_t> mMaxCLParamsSize;
1065     CoherentBufferTracker mCoherentBufferTracker;
1066     angle::SimpleMutex mFrameCaptureMutex;
1067     bool mCallCaptured           = false;
1068     bool mStartFrameCallCaptured = false;
1069 
1070     // When true, it removes unnecessary calls going into
1071     // replay files that occur before mCaptureStartFrame
1072     bool removeUnneededOpenCLCalls = false;
1073 
1074 #ifdef ANGLE_ENABLE_CL
1075     // OpenCL calls considered as "frames"
1076     std::unordered_set<EntryPoint> mCLEndFrameCalls = {EntryPoint::CLEnqueueNDRangeKernel,
1077                                                        EntryPoint::CLEnqueueNativeKernel,
1078                                                        EntryPoint::CLEnqueueTask};
1079 
1080     // "Optional" OpenCL calls not important for Capture/Replay
1081     std::unordered_set<EntryPoint> mCLOptionalCalls = {EntryPoint::CLGetPlatformInfo,
1082                                                        EntryPoint::CLGetDeviceInfo,
1083                                                        EntryPoint::CLGetContextInfo,
1084                                                        EntryPoint::CLGetCommandQueueInfo,
1085                                                        EntryPoint::CLGetProgramInfo,
1086                                                        EntryPoint::CLGetProgramBuildInfo,
1087                                                        EntryPoint::CLGetKernelInfo,
1088                                                        EntryPoint::CLGetKernelArgInfo,
1089                                                        EntryPoint::CLGetKernelWorkGroupInfo,
1090                                                        EntryPoint::CLGetEventInfo,
1091                                                        EntryPoint::CLGetEventProfilingInfo,
1092                                                        EntryPoint::CLGetMemObjectInfo,
1093                                                        EntryPoint::CLGetImageInfo,
1094                                                        EntryPoint::CLGetSamplerInfo,
1095                                                        EntryPoint::CLGetSupportedImageFormats};
1096     std::string mCLInfoJson;
1097     std::vector<std::string> mExtFuncsAdded;
1098 
1099     std::vector<CallCapture> mCLSetupCalls;
1100 
1101     ResourceTrackerCL mResourceTrackerCL;
1102 #endif
1103 
1104     ResourceTracker mResourceTracker;
1105     ReplayWriter mReplayWriter;
1106 
1107     // If you don't know which frame you want to start capturing at, use the capture trigger.
1108     // Initialize it to the number of frames you want to capture, and then clear the value to 0 when
1109     // you reach the content you want to capture. Currently only available on Android.
1110     uint32_t mCaptureTrigger;
1111 
1112     bool mCaptureActive;
1113     std::vector<uint32_t> mActiveFrameIndices;
1114 
1115     // Cache most recently compiled and linked sources.
1116     ShaderSourceMap mCachedShaderSource;
1117     ProgramSourceMap mCachedProgramSources;
1118 
1119     // Set of programs which were created but not linked before capture was started
1120     std::set<gl::ShaderProgramID> mDeferredLinkPrograms;
1121 
1122     gl::ContextID mWindowSurfaceContextID;
1123 
1124     std::vector<CallCapture> mShareGroupSetupCalls;
1125     // Track which Contexts were created and made current at least once before MEC,
1126     // requiring setup for replay
1127     std::unordered_set<GLuint> mActiveContexts;
1128 
1129     // Invalid call counts per entry point while capture is active and inactive.
1130     std::unordered_map<EntryPoint, size_t> mInvalidCallCountsActive;
1131     std::unordered_map<EntryPoint, size_t> mInvalidCallCountsInactive;
1132 };
1133 
1134 template <typename CaptureFuncT, typename... ArgsT>
CaptureGLCallToFrameCapture(CaptureFuncT captureFunc,bool isCallValid,gl::Context * context,ArgsT...captureParams)1135 void CaptureGLCallToFrameCapture(CaptureFuncT captureFunc,
1136                                  bool isCallValid,
1137                                  gl::Context *context,
1138                                  ArgsT... captureParams)
1139 {
1140     if (!FrameCaptureShared::isRuntimeEnabled())
1141     {
1142         // Return immediately to reduce overhead of compile-time flag
1143         return;
1144     }
1145     FrameCaptureShared *frameCaptureShared = context->getShareGroup()->getFrameCaptureShared();
1146 
1147     // EGL calls are protected by the global context mutex but only a subset of GL calls
1148     // are so protected. Ensure FrameCaptureShared access thread safety by using a
1149     // frame-capture only mutex.
1150     std::lock_guard<angle::SimpleMutex> lock(frameCaptureShared->getFrameCaptureMutex());
1151 
1152     if (!frameCaptureShared->isCapturing())
1153     {
1154         return;
1155     }
1156 
1157     CallCapture call = captureFunc(context->getState(), isCallValid, captureParams...);
1158     frameCaptureShared->captureCall(context, std::move(call), isCallValid);
1159 }
1160 
1161 template <typename FirstT, typename... OthersT>
GetEGLDisplayArg(FirstT display,OthersT...others)1162 egl::Display *GetEGLDisplayArg(FirstT display, OthersT... others)
1163 {
1164     if constexpr (std::is_same<egl::Display *, FirstT>::value)
1165     {
1166         return display;
1167     }
1168     return nullptr;
1169 }
1170 
1171 template <typename CaptureFuncT, typename... ArgsT>
CaptureEGLCallToFrameCapture(CaptureFuncT captureFunc,bool isCallValid,egl::Thread * thread,ArgsT...captureParams)1172 void CaptureEGLCallToFrameCapture(CaptureFuncT captureFunc,
1173                                   bool isCallValid,
1174                                   egl::Thread *thread,
1175                                   ArgsT... captureParams)
1176 {
1177     if (!FrameCaptureShared::isRuntimeEnabled())
1178     {
1179         // Return immediately to reduce overhead of compile-time flag
1180         return;
1181     }
1182     gl::Context *context = thread->getContext();
1183     if (!context)
1184     {
1185         // Get a valid context from the display argument if no context is associated with this
1186         // thread
1187         egl::Display *display = GetEGLDisplayArg(captureParams...);
1188         if (display)
1189         {
1190             for (const auto &contextIter : display->getState().contextMap)
1191             {
1192                 context = contextIter.second;
1193                 break;
1194             }
1195         }
1196         if (!context)
1197         {
1198             return;
1199         }
1200     }
1201     std::lock_guard<egl::ContextMutex> lock(context->getContextMutex());
1202 
1203     angle::FrameCaptureShared *frameCaptureShared =
1204         context->getShareGroup()->getFrameCaptureShared();
1205     if (!frameCaptureShared->isCapturing())
1206     {
1207         return;
1208     }
1209 
1210     angle::CallCapture call = captureFunc(thread, isCallValid, captureParams...);
1211     frameCaptureShared->captureCall(context, std::move(call), true);
1212 }
1213 
1214 #ifdef ANGLE_ENABLE_CL
1215 template <typename CaptureFuncT, typename... ArgsT>
CaptureCLCallToFrameCapture(CaptureFuncT captureFunc,bool isCallValid,ArgsT...captureParams)1216 void CaptureCLCallToFrameCapture(CaptureFuncT captureFunc, bool isCallValid, ArgsT... captureParams)
1217 {
1218     if (!FrameCaptureShared::isRuntimeEnabled())
1219     {
1220         // Return immediately to reduce overhead of compile-time flag
1221         return;
1222     }
1223     angle::FrameCaptureShared *frameCaptureShared =
1224         cl::Platform::GetDefault()->getFrameCaptureShared();
1225     std::lock_guard<angle::SimpleMutex> lock(frameCaptureShared->getFrameCaptureMutex());
1226     if (!frameCaptureShared || !frameCaptureShared->isCapturing())
1227     {
1228         return;
1229     }
1230     angle::CallCapture call = captureFunc(isCallValid, captureParams...);
1231     frameCaptureShared->captureCLCall(std::move(call), isCallValid);
1232 }
1233 #endif
1234 
1235 // Pointer capture helpers.
1236 void CaptureMemory(const void *source, size_t size, ParamCapture *paramCapture);
1237 void CaptureString(const GLchar *str, ParamCapture *paramCapture);
1238 void CaptureStringLimit(const GLchar *str, uint32_t limit, ParamCapture *paramCapture);
1239 void CaptureVertexPointerGLES1(const gl::State &glState,
1240                                gl::ClientVertexArrayType type,
1241                                const void *pointer,
1242                                ParamCapture *paramCapture);
1243 
1244 gl::Program *GetProgramForCapture(const gl::State &glState, gl::ShaderProgramID handle);
1245 
1246 // For GetIntegerv, GetFloatv, etc.
1247 void CaptureGetParameter(const gl::State &glState,
1248                          GLenum pname,
1249                          size_t typeSize,
1250                          ParamCapture *paramCapture);
1251 
1252 void CaptureGetActiveUniformBlockivParameters(const gl::State &glState,
1253                                               gl::ShaderProgramID handle,
1254                                               gl::UniformBlockIndex uniformBlockIndex,
1255                                               GLenum pname,
1256                                               ParamCapture *paramCapture);
1257 
1258 template <typename T>
CaptureClearBufferValue(GLenum buffer,const T * value,ParamCapture * paramCapture)1259 void CaptureClearBufferValue(GLenum buffer, const T *value, ParamCapture *paramCapture)
1260 {
1261     // Per the spec, color buffers have a vec4, the rest a single value
1262     uint32_t valueSize = (buffer == GL_COLOR) ? 4 : 1;
1263     CaptureMemory(value, valueSize * sizeof(T), paramCapture);
1264 }
1265 
1266 void CaptureGenHandlesImpl(GLsizei n, GLuint *handles, ParamCapture *paramCapture);
1267 
1268 template <typename T>
CaptureGenHandles(GLsizei n,T * handles,ParamCapture * paramCapture)1269 void CaptureGenHandles(GLsizei n, T *handles, ParamCapture *paramCapture)
1270 {
1271     paramCapture->dataNElements = n;
1272     CaptureGenHandlesImpl(n, reinterpret_cast<GLuint *>(handles), paramCapture);
1273 }
1274 
1275 template <typename T>
CaptureArray(T * elements,GLsizei n,ParamCapture * paramCapture)1276 void CaptureArray(T *elements, GLsizei n, ParamCapture *paramCapture)
1277 {
1278     paramCapture->dataNElements = n;
1279     CaptureMemory(elements, n * sizeof(T), paramCapture);
1280 }
1281 
1282 void CaptureShaderStrings(GLsizei count,
1283                           const GLchar *const *strings,
1284                           const GLint *length,
1285                           ParamCapture *paramCapture);
1286 
1287 bool IsTrackedPerContext(ResourceIDType type);
1288 
1289 // Function declarations & data types for both
1290 // capturing OpenGL and OpenCL
1291 
1292 std::string EscapeString(const std::string &string);
1293 
1294 // Used to indicate that "shared" should be used to identify the files.
1295 constexpr gl::ContextID kSharedContextId = {0};
1296 // Used to indicate no context ID should be output.
1297 constexpr gl::ContextID kNoContextId = {std::numeric_limits<uint32_t>::max()};
1298 
1299 constexpr uint32_t kNoPartId = std::numeric_limits<uint32_t>::max();
1300 
1301 std::ostream &operator<<(std::ostream &os, gl::ContextID contextId);
1302 
1303 struct FmtCapturePrefix
1304 {
FmtCapturePrefixFmtCapturePrefix1305     FmtCapturePrefix(gl::ContextID contextIdIn, const std::string &captureLabelIn)
1306         : contextId(contextIdIn), captureLabel(captureLabelIn)
1307     {}
1308     gl::ContextID contextId;
1309     const std::string &captureLabel;
1310 };
1311 
1312 std::ostream &operator<<(std::ostream &os, const FmtCapturePrefix &fmt);
1313 
1314 // In C, when you declare or define a function that takes no parameters, you must explicitly say the
1315 // function takes "void" parameters. When you're calling the function you omit this void. It's
1316 // therefore necessary to know how we're using a function to know if we should emi the "void".
1317 enum FuncUsage
1318 {
1319     Prototype,
1320     Definition,
1321     Call,
1322 };
1323 
1324 std::ostream &operator<<(std::ostream &os, FuncUsage usage);
1325 
1326 struct FmtReplayFunction
1327 {
1328     FmtReplayFunction(gl::ContextID contextIdIn,
1329                       FuncUsage usageIn,
1330                       uint32_t frameIndexIn,
1331                       uint32_t partIdIn = kNoPartId)
contextIdFmtReplayFunction1332         : contextId(contextIdIn), usage(usageIn), frameIndex(frameIndexIn), partId(partIdIn)
1333     {}
1334     gl::ContextID contextId;
1335     FuncUsage usage;
1336     uint32_t frameIndex;
1337     uint32_t partId;
1338 };
1339 
1340 std::ostream &operator<<(std::ostream &os, const FmtReplayFunction &fmt);
1341 
1342 enum class ReplayFunc
1343 {
1344     Replay,
1345     Setup,
1346     SetupInactive,
1347     Reset,
1348     SetupFirstFrame,
1349 };
1350 
1351 struct FmtFunction
1352 {
FmtFunctionFmtFunction1353     FmtFunction(ReplayFunc funcTypeIn,
1354                 gl::ContextID contextIdIn,
1355                 FuncUsage usageIn,
1356                 uint32_t frameIndexIn,
1357                 uint32_t partIdIn)
1358         : funcType(funcTypeIn),
1359           contextId(contextIdIn),
1360           usage(usageIn),
1361           frameIndex(frameIndexIn),
1362           partId(partIdIn)
1363     {}
1364 
1365     ReplayFunc funcType;
1366     gl::ContextID contextId;
1367     FuncUsage usage;
1368     uint32_t frameIndex;
1369     uint32_t partId;
1370 };
1371 
1372 std::ostream &operator<<(std::ostream &os, gl::ContextID contextId);
1373 
1374 std::ostream &operator<<(std::ostream &os, const FmtFunction &fmt);
1375 
1376 struct FmtSetupFunction
1377 {
FmtSetupFunctionFmtSetupFunction1378     FmtSetupFunction(uint32_t partIdIn, gl::ContextID contextIdIn, FuncUsage usageIn)
1379         : partId(partIdIn), contextId(contextIdIn), usage(usageIn)
1380     {}
1381 
1382     uint32_t partId;
1383     gl::ContextID contextId;
1384     FuncUsage usage;
1385 };
1386 
1387 std::ostream &operator<<(std::ostream &os, const FmtSetupFunction &fmt);
1388 
1389 struct FmtSetupFirstFrameFunction
1390 {
partIdFmtSetupFirstFrameFunction1391     FmtSetupFirstFrameFunction(uint32_t partIdIn = kNoPartId) : partId(partIdIn) {}
1392 
1393     uint32_t partId;
1394 };
1395 
1396 std::ostream &operator<<(std::ostream &os, const FmtSetupFirstFrameFunction &fmt);
1397 
1398 struct FmtSetupInactiveFunction
1399 {
FmtSetupInactiveFunctionFmtSetupInactiveFunction1400     FmtSetupInactiveFunction(uint32_t partIdIn, gl::ContextID contextIdIn, FuncUsage usageIn)
1401         : partId(partIdIn), contextId(contextIdIn), usage(usageIn)
1402     {}
1403 
1404     uint32_t partId;
1405     gl::ContextID contextId;
1406     FuncUsage usage;
1407 };
1408 
1409 std::ostream &operator<<(std::ostream &os, const FmtSetupInactiveFunction &fmt);
1410 
1411 struct FmtResetFunction
1412 {
FmtResetFunctionFmtResetFunction1413     FmtResetFunction(uint32_t partIdIn, gl::ContextID contextIdIn, FuncUsage usageIn)
1414         : partId(partIdIn), contextId(contextIdIn), usage(usageIn)
1415     {}
1416 
1417     uint32_t partId;
1418     gl::ContextID contextId;
1419     FuncUsage usage;
1420 };
1421 
1422 std::ostream &operator<<(std::ostream &os, const FmtResetFunction &fmt);
1423 
1424 // For compatibility with C, which does not have multi-line string literals, we break strings up
1425 // into multiple lines like:
1426 //
1427 //   const char *str[] = {
1428 //   "multiple\n"
1429 //   "line\n"
1430 //   "strings may have \"quotes\"\n"
1431 //   "and \\slashes\\\n",
1432 //   };
1433 //
1434 // Note we need to emit extra escapes to ensure quotes and other special characters are preserved.
1435 struct FmtMultiLineString
1436 {
FmtMultiLineStringFmtMultiLineString1437     FmtMultiLineString(const std::string &str) : strings()
1438     {
1439         std::string str2;
1440 
1441         // Strip any carriage returns before splitting, for consistency
1442         if (str.find("\r") != std::string::npos)
1443         {
1444             // str is const, so have to make a copy of it first
1445             str2 = str;
1446             ReplaceAllSubstrings(&str2, "\r", "");
1447         }
1448 
1449         strings =
1450             angle::SplitString(str2.empty() ? str : str2, "\n", WhitespaceHandling::KEEP_WHITESPACE,
1451                                SplitResult::SPLIT_WANT_ALL);
1452     }
1453 
1454     std::vector<std::string> strings;
1455 };
1456 
1457 std::ostream &operator<<(std::ostream &ostr, const FmtMultiLineString &fmt);
1458 
1459 struct SaveFileHelper
1460 {
1461   public:
1462     // We always use ios::binary to avoid inconsistent line endings when captured on Linux vs Win.
SaveFileHelperSaveFileHelper1463     SaveFileHelper(const std::string &filePathIn)
1464         : mOfs(filePathIn, std::ios::binary | std::ios::out), mFilePath(filePathIn)
1465     {
1466         if (!mOfs.is_open())
1467         {
1468             FATAL() << "Could not open " << filePathIn;
1469         }
1470     }
~SaveFileHelperSaveFileHelper1471     ~SaveFileHelper() { printf("Saved '%s'.\n", mFilePath.c_str()); }
1472 
1473     template <typename T>
1474     SaveFileHelper &operator<<(const T &value)
1475     {
1476         mOfs << value;
1477         if (mOfs.bad())
1478         {
1479             FATAL() << "Error writing to " << mFilePath;
1480         }
1481         return *this;
1482     }
1483 
writeSaveFileHelper1484     void write(const uint8_t *data, size_t size)
1485     {
1486         mOfs.write(reinterpret_cast<const char *>(data), size);
1487     }
1488 
1489   private:
1490     void checkError();
1491 
1492     std::ofstream mOfs;
1493     std::string mFilePath;
1494 };
1495 
1496 // TODO: Consolidate to C output and remove option. http://anglebug.com/42266223
1497 
1498 constexpr char kEnabledVarName[]        = "ANGLE_CAPTURE_ENABLED";
1499 constexpr char kOutDirectoryVarName[]   = "ANGLE_CAPTURE_OUT_DIR";
1500 constexpr char kFrameStartVarName[]     = "ANGLE_CAPTURE_FRAME_START";
1501 constexpr char kFrameEndVarName[]       = "ANGLE_CAPTURE_FRAME_END";
1502 constexpr char kTriggerVarName[]        = "ANGLE_CAPTURE_TRIGGER";
1503 constexpr char kCaptureLabelVarName[]   = "ANGLE_CAPTURE_LABEL";
1504 constexpr char kCompressionVarName[]    = "ANGLE_CAPTURE_COMPRESSION";
1505 constexpr char kSerializeStateVarName[] = "ANGLE_CAPTURE_SERIALIZE_STATE";
1506 constexpr char kValidationVarName[]     = "ANGLE_CAPTURE_VALIDATION";
1507 constexpr char kValidationExprVarName[] = "ANGLE_CAPTURE_VALIDATION_EXPR";
1508 constexpr char kSourceExtVarName[]      = "ANGLE_CAPTURE_SOURCE_EXT";
1509 constexpr char kSourceSizeVarName[]     = "ANGLE_CAPTURE_SOURCE_SIZE";
1510 constexpr char kForceShadowVarName[]    = "ANGLE_CAPTURE_FORCE_SHADOW";
1511 
1512 constexpr size_t kBinaryAlignment   = 16;
1513 constexpr size_t kFunctionSizeLimit = 5000;
1514 
1515 // Limit based on MSVC Compiler Error C2026
1516 constexpr size_t kStringLengthLimit = 16380;
1517 
1518 // Default limit to number of bytes in a capture source files.
1519 constexpr char kDefaultSourceFileExt[]           = "cpp";
1520 constexpr size_t kDefaultSourceFileSizeThreshold = 400000;
1521 
1522 // Android debug properties that correspond to the above environment variables
1523 constexpr char kAndroidEnabled[]        = "debug.angle.capture.enabled";
1524 constexpr char kAndroidOutDir[]         = "debug.angle.capture.out_dir";
1525 constexpr char kAndroidFrameStart[]     = "debug.angle.capture.frame_start";
1526 constexpr char kAndroidFrameEnd[]       = "debug.angle.capture.frame_end";
1527 constexpr char kAndroidTrigger[]        = "debug.angle.capture.trigger";
1528 constexpr char kAndroidCaptureLabel[]   = "debug.angle.capture.label";
1529 constexpr char kAndroidCompression[]    = "debug.angle.capture.compression";
1530 constexpr char kAndroidValidation[]     = "debug.angle.capture.validation";
1531 constexpr char kAndroidValidationExpr[] = "debug.angle.capture.validation_expr";
1532 constexpr char kAndroidSourceExt[]      = "debug.angle.capture.source_ext";
1533 constexpr char kAndroidSourceSize[]     = "debug.angle.capture.source_size";
1534 constexpr char kAndroidForceShadow[]    = "debug.angle.capture.force_shadow";
1535 
1536 void WriteCppReplayForCall(const CallCapture &call,
1537                            ReplayWriter &replayWriter,
1538                            std::ostream &out,
1539                            std::ostream &header,
1540                            std::vector<uint8_t> *binaryData,
1541                            size_t *maxResourceIDBufferSize);
1542 
1543 void WriteCppReplayForCallCL(const CallCapture &call,
1544                              ReplayWriter &replayWriter,
1545                              std::ostream &out,
1546                              std::ostream &header,
1547                              std::vector<uint8_t> *binaryData);
1548 
1549 void WriteBinaryParamReplay(ReplayWriter &replayWriter,
1550                             std::ostream &out,
1551                             std::ostream &header,
1552                             const CallCapture &call,
1553                             const ParamCapture &param,
1554                             std::vector<uint8_t> *binaryData);
1555 
1556 std::string GetBinaryDataFilePath(bool compression, const std::string &captureLabel);
1557 
1558 void SaveBinaryData(bool compression,
1559                     const std::string &outDir,
1560                     gl::ContextID contextId,
1561                     const std::string &captureLabel,
1562                     const std::vector<uint8_t> &binaryData);
1563 
1564 void WriteStringPointerParamReplay(ReplayWriter &replayWriter,
1565                                    std::ostream &out,
1566                                    std::ostream &header,
1567                                    const CallCapture &call,
1568                                    const ParamCapture &param);
1569 
1570 void WriteCppReplayFunctionWithParts(const gl::ContextID contextID,
1571                                      ReplayFunc replayFunc,
1572                                      ReplayWriter &replayWriter,
1573                                      uint32_t frameIndex,
1574                                      std::vector<uint8_t> *binaryData,
1575                                      const std::vector<CallCapture> &calls,
1576                                      std::stringstream &header,
1577                                      std::stringstream &out,
1578                                      size_t *maxResourceIDBufferSize);
1579 
1580 void WriteComment(std::ostream &out, const CallCapture &call);
1581 
1582 template <typename T, typename CastT = T>
WriteInlineData(const std::vector<uint8_t> & vec,std::ostream & out)1583 void WriteInlineData(const std::vector<uint8_t> &vec, std::ostream &out)
1584 {
1585     const T *data = reinterpret_cast<const T *>(vec.data());
1586     size_t count  = vec.size() / sizeof(T);
1587 
1588     if (data == nullptr)
1589     {
1590         return;
1591     }
1592 
1593     out << static_cast<CastT>(data[0]);
1594 
1595     for (size_t dataIndex = 1; dataIndex < count; ++dataIndex)
1596     {
1597         out << ", " << static_cast<CastT>(data[dataIndex]);
1598     }
1599 }
1600 
1601 template <>
1602 void WriteInlineData<GLchar>(const std::vector<uint8_t> &vec, std::ostream &out);
1603 
1604 void AddComment(std::vector<CallCapture> *outCalls, const std::string &comment);
1605 
1606 }  // namespace angle
1607 
1608 template <typename T>
CaptureTextureAndSamplerParameter_params(GLenum pname,const T * param,angle::ParamCapture * paramCapture)1609 void CaptureTextureAndSamplerParameter_params(GLenum pname,
1610                                               const T *param,
1611                                               angle::ParamCapture *paramCapture)
1612 {
1613     if (pname == GL_TEXTURE_BORDER_COLOR || pname == GL_TEXTURE_CROP_RECT_OES)
1614     {
1615         CaptureMemory(param, sizeof(T) * 4, paramCapture);
1616     }
1617     else
1618     {
1619         CaptureMemory(param, sizeof(T), paramCapture);
1620     }
1621 }
1622 
1623 namespace egl
1624 {
1625 angle::ParamCapture CaptureAttributeMap(const egl::AttributeMap &attribMap);
1626 }  // namespace egl
1627 
1628 #endif  // LIBANGLE_FRAME_CAPTURE_H_
1629