xref: /aosp_15_r20/external/angle/src/libANGLE/capture/FrameCapture.h (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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 "common/PackedEnums.h"
14 #include "common/SimpleMutex.h"
15 #include "common/frame_capture_utils.h"
16 #include "common/system_utils.h"
17 #include "libANGLE/Context.h"
18 #include "libANGLE/ShareGroup.h"
19 #include "libANGLE/Thread.h"
20 #include "libANGLE/angletypes.h"
21 #include "libANGLE/entry_points_utils.h"
22 
23 namespace gl
24 {
25 enum class BigGLEnum;
26 enum class GLESEnum;
27 }  // namespace gl
28 
29 namespace angle
30 {
31 // Helper to use unique IDs for each local data variable.
32 class DataCounters final : angle::NonCopyable
33 {
34   public:
35     DataCounters();
36     ~DataCounters();
37 
38     int getAndIncrement(EntryPoint entryPoint, const std::string &paramName);
39 
40   private:
41     // <CallName, ParamName>
42     using Counter = std::pair<EntryPoint, std::string>;
43     std::map<Counter, int> mData;
44 };
45 
46 constexpr int kStringsNotFound = -1;
47 class StringCounters final : angle::NonCopyable
48 {
49   public:
50     StringCounters();
51     ~StringCounters();
52 
53     int getStringCounter(const std::vector<std::string> &str);
54     void setStringCounter(const std::vector<std::string> &str, int &counter);
55 
56   private:
57     std::map<std::vector<std::string>, int> mStringCounterMap;
58 };
59 
60 class DataTracker final : angle::NonCopyable
61 {
62   public:
63     DataTracker();
64     ~DataTracker();
65 
getCounters()66     DataCounters &getCounters() { return mCounters; }
getStringCounters()67     StringCounters &getStringCounters() { return mStringCounters; }
68 
69   private:
70     DataCounters mCounters;
71     StringCounters mStringCounters;
72 };
73 
74 class ReplayWriter final : angle::NonCopyable
75 {
76   public:
77     ReplayWriter();
78     ~ReplayWriter();
79 
80     void setSourceFileExtension(const char *ext);
81     void setSourceFileSizeThreshold(size_t sourceFileSizeThreshold);
82     void setFilenamePattern(const std::string &pattern);
83     void setCaptureLabel(const std::string &label);
84     void setSourcePrologue(const std::string &prologue);
85     void setHeaderPrologue(const std::string &prologue);
86 
87     void addPublicFunction(const std::string &functionProto,
88                            const std::stringstream &headerStream,
89                            const std::stringstream &bodyStream);
90     void addPrivateFunction(const std::string &functionProto,
91                             const std::stringstream &headerStream,
92                             const std::stringstream &bodyStream);
93     std::string getInlineVariableName(EntryPoint entryPoint, const std::string &paramName);
94 
95     std::string getInlineStringSetVariableName(EntryPoint entryPoint,
96                                                const std::string &paramName,
97                                                const std::vector<std::string> &strings,
98                                                bool *isNewEntryOut);
99 
100     void saveFrame();
101     void saveFrameIfFull();
102     void saveIndexFilesAndHeader();
103     void saveSetupFile();
104 
105     std::vector<std::string> getAndResetWrittenFiles();
106 
107   private:
108     static std::string GetVarName(EntryPoint entryPoint, const std::string &paramName, int counter);
109 
110     void saveHeader();
111     void writeReplaySource(const std::string &filename);
112     void addWrittenFile(const std::string &filename);
113     size_t getStoredReplaySourceSize() const;
114 
115     std::string mSourceFileExtension;
116     size_t mSourceFileSizeThreshold;
117     size_t mFrameIndex;
118 
119     DataTracker mDataTracker;
120     std::string mFilenamePattern;
121     std::string mCaptureLabel;
122     std::string mSourcePrologue;
123     std::string mHeaderPrologue;
124 
125     std::vector<std::string> mReplayHeaders;
126     std::vector<std::string> mGlobalVariableDeclarations;
127 
128     std::vector<std::string> mPublicFunctionPrototypes;
129     std::vector<std::string> mPublicFunctions;
130 
131     std::vector<std::string> mPrivateFunctionPrototypes;
132     std::vector<std::string> mPrivateFunctions;
133 
134     std::vector<std::string> mWrittenFiles;
135 };
136 
137 using BufferCalls = std::map<GLuint, std::vector<CallCapture>>;
138 
139 // true means mapped, false means unmapped
140 using BufferMapStatusMap = std::map<GLuint, bool>;
141 
142 using FenceSyncSet   = std::set<gl::SyncID>;
143 using FenceSyncCalls = std::map<gl::SyncID, std::vector<CallCapture>>;
144 
145 // For default uniforms, we need to track which ones are dirty, and the series of calls to reset.
146 // Each program has unique default uniforms, and each uniform has one or more locations in the
147 // default buffer. For reset efficiency, we track only the uniforms dirty by location, per program.
148 
149 // A set of all default uniforms (per program) that were modified during the run
150 using DefaultUniformLocationsSet = std::set<gl::UniformLocation>;
151 using DefaultUniformLocationsPerProgramMap =
152     std::map<gl::ShaderProgramID, DefaultUniformLocationsSet>;
153 
154 // A map of programs which maps to locations and their reset calls
155 using DefaultUniformCallsPerLocationMap = std::map<gl::UniformLocation, std::vector<CallCapture>>;
156 using DefaultUniformCallsPerProgramMap =
157     std::map<gl::ShaderProgramID, DefaultUniformCallsPerLocationMap>;
158 
159 using DefaultUniformBaseLocationMap =
160     std::map<std::pair<gl::ShaderProgramID, gl::UniformLocation>, gl::UniformLocation>;
161 
162 using ResourceSet   = std::set<GLuint>;
163 using ResourceCalls = std::map<GLuint, std::vector<CallCapture>>;
164 
165 class TrackedResource final : angle::NonCopyable
166 {
167   public:
168     TrackedResource();
169     ~TrackedResource();
170 
getStartingResources()171     const ResourceSet &getStartingResources() const { return mStartingResources; }
getStartingResources()172     ResourceSet &getStartingResources() { return mStartingResources; }
getNewResources()173     const ResourceSet &getNewResources() const { return mNewResources; }
getNewResources()174     ResourceSet &getNewResources() { return mNewResources; }
getResourcesToDelete()175     const ResourceSet &getResourcesToDelete() const { return mResourcesToDelete; }
getResourcesToDelete()176     ResourceSet &getResourcesToDelete() { return mResourcesToDelete; }
getResourcesToRegen()177     const ResourceSet &getResourcesToRegen() const { return mResourcesToRegen; }
getResourcesToRegen()178     ResourceSet &getResourcesToRegen() { return mResourcesToRegen; }
getResourcesToRestore()179     const ResourceSet &getResourcesToRestore() const { return mResourcesToRestore; }
getResourcesToRestore()180     ResourceSet &getResourcesToRestore() { return mResourcesToRestore; }
181 
182     void setGennedResource(GLuint id);
183     void setDeletedResource(GLuint id);
184     void setModifiedResource(GLuint id);
185     bool resourceIsGenerated(GLuint id);
186 
getResourceRegenCalls()187     ResourceCalls &getResourceRegenCalls() { return mResourceRegenCalls; }
getResourceRestoreCalls()188     ResourceCalls &getResourceRestoreCalls() { return mResourceRestoreCalls; }
189 
190   private:
191     // Resource regen calls will gen a resource
192     ResourceCalls mResourceRegenCalls;
193     // Resource restore calls will restore the contents of a resource
194     ResourceCalls mResourceRestoreCalls;
195 
196     // Resources created during startup
197     ResourceSet mStartingResources;
198 
199     // Resources created during the run that need to be deleted
200     ResourceSet mNewResources;
201     // Resources recreated during the run that need to be deleted
202     ResourceSet mResourcesToDelete;
203     // Resources deleted during the run that need to be recreated
204     ResourceSet mResourcesToRegen;
205     // Resources modified during the run that need to be restored
206     ResourceSet mResourcesToRestore;
207 };
208 
209 using TrackedResourceArray =
210     std::array<TrackedResource, static_cast<uint32_t>(ResourceIDType::EnumCount)>;
211 
212 enum class ShaderProgramType
213 {
214     ShaderType,
215     ProgramType
216 };
217 
218 // Helper to track resource changes during the capture
219 class ResourceTracker final : angle::NonCopyable
220 {
221   public:
222     ResourceTracker();
223     ~ResourceTracker();
224 
getBufferMapCalls()225     BufferCalls &getBufferMapCalls() { return mBufferMapCalls; }
getBufferUnmapCalls()226     BufferCalls &getBufferUnmapCalls() { return mBufferUnmapCalls; }
227 
getBufferBindingCalls()228     std::vector<CallCapture> &getBufferBindingCalls() { return mBufferBindingCalls; }
229 
230     void setBufferMapped(gl::ContextID contextID, GLuint id);
231     void setBufferUnmapped(gl::ContextID contextID, GLuint id);
232 
233     bool getStartingBuffersMappedCurrent(GLuint id) const;
234     bool getStartingBuffersMappedInitial(GLuint id) const;
235 
setStartingBufferMapped(GLuint id,bool mapped)236     void setStartingBufferMapped(GLuint id, bool mapped)
237     {
238         // Track the current state (which will change throughout the trace)
239         mStartingBuffersMappedCurrent[id] = mapped;
240 
241         // And the initial state, to compare during frame loop reset
242         mStartingBuffersMappedInitial[id] = mapped;
243     }
244 
245     void onShaderProgramAccess(gl::ShaderProgramID shaderProgramID);
getMaxShaderPrograms()246     uint32_t getMaxShaderPrograms() const { return mMaxShaderPrograms; }
247 
getStartingFenceSyncs()248     FenceSyncSet &getStartingFenceSyncs() { return mStartingFenceSyncs; }
getFenceSyncRegenCalls()249     FenceSyncCalls &getFenceSyncRegenCalls() { return mFenceSyncRegenCalls; }
getFenceSyncsToRegen()250     FenceSyncSet &getFenceSyncsToRegen() { return mFenceSyncsToRegen; }
251     void setDeletedFenceSync(gl::SyncID sync);
252 
getDefaultUniformsToReset()253     DefaultUniformLocationsPerProgramMap &getDefaultUniformsToReset()
254     {
255         return mDefaultUniformsToReset;
256     }
getDefaultUniformResetCalls(gl::ShaderProgramID id)257     DefaultUniformCallsPerLocationMap &getDefaultUniformResetCalls(gl::ShaderProgramID id)
258     {
259         return mDefaultUniformResetCalls[id];
260     }
261     void setModifiedDefaultUniform(gl::ShaderProgramID programID, gl::UniformLocation location);
262     void setDefaultUniformBaseLocation(gl::ShaderProgramID programID,
263                                        gl::UniformLocation location,
264                                        gl::UniformLocation baseLocation);
getDefaultUniformBaseLocation(gl::ShaderProgramID programID,gl::UniformLocation location)265     gl::UniformLocation getDefaultUniformBaseLocation(gl::ShaderProgramID programID,
266                                                       gl::UniformLocation location)
267     {
268         ASSERT(mDefaultUniformBaseLocations.find({programID, location}) !=
269                mDefaultUniformBaseLocations.end());
270         return mDefaultUniformBaseLocations[{programID, location}];
271     }
272 
273     TrackedResource &getTrackedResource(gl::ContextID contextID, ResourceIDType type);
274 
275     void getContextIDs(std::set<gl::ContextID> &idsOut);
276 
getImageToAttribTable()277     std::map<EGLImage, egl::AttributeMap> &getImageToAttribTable() { return mMatchImageToAttribs; }
278 
getTextureIDToImageTable()279     std::map<GLuint, egl::ImageID> &getTextureIDToImageTable() { return mMatchTextureIDToImage; }
280 
setShaderProgramType(gl::ShaderProgramID id,angle::ShaderProgramType type)281     void setShaderProgramType(gl::ShaderProgramID id, angle::ShaderProgramType type)
282     {
283         mShaderProgramType[id] = type;
284     }
getShaderProgramType(gl::ShaderProgramID id)285     ShaderProgramType getShaderProgramType(gl::ShaderProgramID id)
286     {
287         ASSERT(mShaderProgramType.find(id) != mShaderProgramType.end());
288         return mShaderProgramType[id];
289     }
290 
291   private:
292     // Buffer map calls will map a buffer with correct offset, length, and access flags
293     BufferCalls mBufferMapCalls;
294     // Buffer unmap calls will bind and unmap a given buffer
295     BufferCalls mBufferUnmapCalls;
296 
297     // Buffer binding calls to restore bindings recorded during MEC
298     std::vector<CallCapture> mBufferBindingCalls;
299 
300     // Whether a given buffer was mapped at the start of the trace
301     BufferMapStatusMap mStartingBuffersMappedInitial;
302     // The status of buffer mapping throughout the trace, modified with each Map/Unmap call
303     BufferMapStatusMap mStartingBuffersMappedCurrent;
304 
305     // Maximum accessed shader program ID.
306     uint32_t mMaxShaderPrograms = 0;
307 
308     // Fence sync objects created during MEC setup
309     FenceSyncSet mStartingFenceSyncs;
310     // Fence sync regen calls will create a fence sync objects
311     FenceSyncCalls mFenceSyncRegenCalls;
312     // Fence syncs to regen are a list of starting fence sync objects that were deleted and need to
313     // be regen'ed.
314     FenceSyncSet mFenceSyncsToRegen;
315 
316     // Default uniforms that were modified during the run
317     DefaultUniformLocationsPerProgramMap mDefaultUniformsToReset;
318     // Calls per default uniform to return to original state
319     DefaultUniformCallsPerProgramMap mDefaultUniformResetCalls;
320 
321     // Base location of arrayed uniforms
322     DefaultUniformBaseLocationMap mDefaultUniformBaseLocations;
323 
324     // Tracked resources per context
325     TrackedResourceArray mTrackedResourcesShared;
326     std::map<gl::ContextID, TrackedResourceArray> mTrackedResourcesPerContext;
327 
328     std::map<EGLImage, egl::AttributeMap> mMatchImageToAttribs;
329     std::map<GLuint, egl::ImageID> mMatchTextureIDToImage;
330 
331     std::map<gl::ShaderProgramID, ShaderProgramType> mShaderProgramType;
332 };
333 
334 // Used by the CPP replay to filter out unnecessary code.
335 using HasResourceTypeMap = angle::PackedEnumBitSet<ResourceIDType>;
336 
337 // Map of ResourceType to IDs and range of setup calls
338 using ResourceIDToSetupCallsMap =
339     PackedEnumMap<ResourceIDType, std::map<GLuint, gl::Range<size_t>>>;
340 
341 // Map of buffer ID to offset and size used when mapped
342 using BufferDataMap = std::map<gl::BufferID, std::pair<GLintptr, GLsizeiptr>>;
343 
344 // A dictionary of sources indexed by shader type.
345 using ProgramSources = gl::ShaderMap<std::string>;
346 
347 // Maps from IDs to sources.
348 using ShaderSourceMap  = std::map<gl::ShaderProgramID, std::string>;
349 using ProgramSourceMap = std::map<gl::ShaderProgramID, ProgramSources>;
350 
351 // Map from textureID to level and data
352 using TextureLevels       = std::map<GLint, std::vector<uint8_t>>;
353 using TextureLevelDataMap = std::map<gl::TextureID, TextureLevels>;
354 
355 struct SurfaceParams
356 {
357     gl::Extents extents;
358     egl::ColorSpace colorSpace;
359 };
360 
361 // Map from ContextID to SurfaceParams
362 using SurfaceParamsMap = std::map<gl::ContextID, SurfaceParams>;
363 
364 using CallVector = std::vector<std::vector<CallCapture> *>;
365 
366 // A map from API entry point to calls
367 using CallResetMap = std::map<angle::EntryPoint, std::vector<CallCapture>>;
368 
369 using TextureBinding  = std::pair<size_t, gl::TextureType>;
370 using TextureResetMap = std::map<TextureBinding, gl::TextureID>;
371 
372 using BufferBindingPair = std::pair<gl::BufferBinding, gl::BufferID>;
373 
374 // StateResetHelper provides a simple way to track whether an entry point has been called during the
375 // trace, along with the reset calls to get it back to starting state.  This is useful for things
376 // that are one dimensional, like context bindings or context state.
377 class StateResetHelper final : angle::NonCopyable
378 {
379   public:
380     StateResetHelper();
381     ~StateResetHelper();
382 
getDirtyEntryPoints()383     const std::set<angle::EntryPoint> &getDirtyEntryPoints() const { return mDirtyEntryPoints; }
setEntryPointDirty(EntryPoint entryPoint)384     void setEntryPointDirty(EntryPoint entryPoint) { mDirtyEntryPoints.insert(entryPoint); }
385 
getResetCalls()386     CallResetMap &getResetCalls() { return mResetCalls; }
getResetCalls()387     const CallResetMap &getResetCalls() const { return mResetCalls; }
388 
389     void setDefaultResetCalls(const gl::Context *context, angle::EntryPoint);
390 
getDirtyTextureBindings()391     const std::set<TextureBinding> &getDirtyTextureBindings() const
392     {
393         return mDirtyTextureBindings;
394     }
setTextureBindingDirty(size_t unit,gl::TextureType target)395     void setTextureBindingDirty(size_t unit, gl::TextureType target)
396     {
397         mDirtyTextureBindings.emplace(unit, target);
398     }
399 
getResetTextureBindings()400     TextureResetMap &getResetTextureBindings() { return mResetTextureBindings; }
401 
setResetActiveTexture(size_t textureID)402     void setResetActiveTexture(size_t textureID) { mResetActiveTexture = textureID; }
getResetActiveTexture()403     size_t getResetActiveTexture() { return mResetActiveTexture; }
404 
getDirtyBufferBindings()405     const std::set<gl::BufferBinding> &getDirtyBufferBindings() const
406     {
407         return mDirtyBufferBindings;
408     }
setBufferBindingDirty(gl::BufferBinding binding)409     void setBufferBindingDirty(gl::BufferBinding binding) { mDirtyBufferBindings.insert(binding); }
410 
getStartingBufferBindings()411     const std::set<BufferBindingPair> &getStartingBufferBindings() const
412     {
413         return mStartingBufferBindings;
414     }
setStartingBufferBinding(gl::BufferBinding binding,gl::BufferID bufferID)415     void setStartingBufferBinding(gl::BufferBinding binding, gl::BufferID bufferID)
416     {
417         mStartingBufferBindings.insert({binding, bufferID});
418     }
419 
420   private:
421     // Dirty state per entry point
422     std::set<angle::EntryPoint> mDirtyEntryPoints;
423 
424     // Reset calls per API entry point
425     CallResetMap mResetCalls;
426 
427     // Dirty state per texture binding
428     std::set<TextureBinding> mDirtyTextureBindings;
429 
430     // Texture bindings and active texture to restore
431     TextureResetMap mResetTextureBindings;
432     size_t mResetActiveTexture = 0;
433 
434     // Starting and dirty buffer bindings
435     std::set<BufferBindingPair> mStartingBufferBindings;
436     std::set<gl::BufferBinding> mDirtyBufferBindings;
437 };
438 
439 class FrameCapture final : angle::NonCopyable
440 {
441   public:
442     FrameCapture();
443     ~FrameCapture();
444 
getSetupCalls()445     std::vector<CallCapture> &getSetupCalls() { return mSetupCalls; }
clearSetupCalls()446     void clearSetupCalls() { mSetupCalls.clear(); }
447 
getStateResetHelper()448     StateResetHelper &getStateResetHelper() { return mStateResetHelper; }
449 
450     void reset();
451 
452   private:
453     std::vector<CallCapture> mSetupCalls;
454 
455     StateResetHelper mStateResetHelper;
456 };
457 
458 // Page range inside a coherent buffer
459 struct PageRange
460 {
461     PageRange(size_t start, size_t end);
462     ~PageRange();
463 
464     // Relative start page
465     size_t start;
466 
467     // First page after the relative end
468     size_t end;
469 };
470 
471 // Memory address range defined by start and size
472 struct AddressRange
473 {
474     AddressRange();
475     AddressRange(uintptr_t start, size_t size);
476     ~AddressRange();
477 
478     uintptr_t end();
479 
480     uintptr_t start;
481     size_t size;
482 };
483 
484 // Used to handle protection of buffers that overlap in pages.
485 enum class PageSharingType
486 {
487     NoneShared,
488     FirstShared,
489     LastShared,
490     FirstAndLastShared
491 };
492 
493 class CoherentBuffer
494 {
495   public:
496     CoherentBuffer(uintptr_t start, size_t size, size_t pageSize, bool useShadowMemory);
497     ~CoherentBuffer();
498 
499     // Sets the a range in the buffer clean and protects a selected range
500     void protectPageRange(const PageRange &pageRange);
501 
502     // Sets all pages to clean and enables protection
503     void protectAll();
504 
505     // Sets a page dirty state and sets it's protection
506     void setDirty(size_t relativePage, bool dirty);
507 
508     // Shadow memory synchronization
509     void updateBufferMemory();
510     void updateShadowMemory();
511 
512     // Removes protection
513     void removeProtection(PageSharingType sharingType);
514 
515     bool contains(size_t page, size_t *relativePage);
516     bool isDirty();
517 
518     // Returns dirty page ranges
519     std::vector<PageRange> getDirtyPageRanges();
520 
521     // Calculates address range from page range
522     AddressRange getDirtyAddressRange(const PageRange &dirtyPageRange);
523     AddressRange getRange();
524 
markShadowDirty()525     void markShadowDirty() { mShadowDirty = true; }
isShadowDirty()526     bool isShadowDirty() { return mShadowDirty; }
527 
528   private:
529     // Actual buffer start and size
530     AddressRange mRange;
531 
532     // Start and size of page aligned protected area
533     AddressRange mProtectionRange;
534 
535     // Start and end of protection in relative pages, calculated from mProtectionRange.
536     size_t mProtectionStartPage;
537     size_t mProtectionEndPage;
538 
539     size_t mPageCount;
540     size_t mPageSize;
541 
542     // Clean pages are protected
543     std::vector<bool> mDirtyPages;
544 
545     // shadow memory releated fields
546     bool mShadowMemoryEnabled;
547     uintptr_t mBufferStart;
548     void *mShadowMemory;
549     bool mShadowDirty;
550 };
551 
552 class CoherentBufferTracker final : angle::NonCopyable
553 {
554   public:
555     CoherentBufferTracker();
556     ~CoherentBufferTracker();
557 
558     bool isDirty(gl::BufferID id);
559     uintptr_t addBuffer(gl::BufferID id, uintptr_t start, size_t size);
560     void removeBuffer(gl::BufferID id);
561     void disable();
562     void enable();
563     void onEndFrame();
564     bool haveBuffer(gl::BufferID id);
isShadowMemoryEnabled()565     bool isShadowMemoryEnabled() { return mShadowMemoryEnabled; }
enableShadowMemory()566     void enableShadowMemory() { mShadowMemoryEnabled = true; }
567     void maybeUpdateShadowMemory();
568     void markAllShadowDirty();
569     // Determine whether memory protection can be used directly on graphics memory
570     bool canProtectDirectly(gl::Context *context);
571 
572   private:
573     // Detect overlapping pages when removing protection
574     PageSharingType doesBufferSharePage(gl::BufferID id);
575 
576     // Returns a map to found buffers and the corresponding pages for a given address.
577     // For addresses that are in a page shared by 2 buffers, 2 results are returned.
578     HashMap<std::shared_ptr<CoherentBuffer>, size_t> getBufferPagesForAddress(uintptr_t address);
579     PageFaultHandlerRangeType handleWrite(uintptr_t address);
580 
581   public:
582     angle::SimpleMutex mMutex;
583     HashMap<GLuint, std::shared_ptr<CoherentBuffer>> mBuffers;
584 
585   private:
586     bool mEnabled;
587     std::unique_ptr<PageFaultHandler> mPageFaultHandler;
588     size_t mPageSize;
589 
590     bool mShadowMemoryEnabled;
591 };
592 
593 // Shared class for any items that need to be tracked by FrameCapture across shared contexts
594 class FrameCaptureShared final : angle::NonCopyable
595 {
596   public:
597     FrameCaptureShared();
598     ~FrameCaptureShared();
599 
600     void captureCall(gl::Context *context, CallCapture &&call, bool isCallValid);
601     void checkForCaptureTrigger();
602     void onEndFrame(gl::Context *context);
603     void onDestroyContext(const gl::Context *context);
604     void onMakeCurrent(const gl::Context *context, const egl::Surface *drawSurface);
enabled()605     bool enabled() const { return mEnabled; }
606 
607     bool isCapturing() const;
608     uint32_t getFrameCount() const;
609 
610     // Returns a frame index starting from "1" as the first frame.
611     uint32_t getReplayFrameIndex() const;
612 
613     void trackBufferMapping(const gl::Context *context,
614                             CallCapture *call,
615                             gl::BufferID id,
616                             gl::Buffer *buffer,
617                             GLintptr offset,
618                             GLsizeiptr length,
619                             bool writable,
620                             bool coherent);
621 
622     void trackTextureUpdate(const gl::Context *context, const CallCapture &call);
623     void trackImageUpdate(const gl::Context *context, const CallCapture &call);
624     void trackDefaultUniformUpdate(const gl::Context *context, const CallCapture &call);
625     void trackVertexArrayUpdate(const gl::Context *context, const CallCapture &call);
626 
627     const std::string &getShaderSource(gl::ShaderProgramID id) const;
628     void setShaderSource(gl::ShaderProgramID id, std::string sources);
629 
630     const ProgramSources &getProgramSources(gl::ShaderProgramID id) const;
631     void setProgramSources(gl::ShaderProgramID id, ProgramSources sources);
632 
633     // Load data from a previously stored texture level
634     const std::vector<uint8_t> &retrieveCachedTextureLevel(gl::TextureID id,
635                                                            gl::TextureTarget target,
636                                                            GLint level);
637 
638     // Create new texture level data and copy the source into it
639     void copyCachedTextureLevel(const gl::Context *context,
640                                 gl::TextureID srcID,
641                                 GLint srcLevel,
642                                 gl::TextureID dstID,
643                                 GLint dstLevel,
644                                 const CallCapture &call);
645 
646     // Create the location that should be used to cache texture level data
647     std::vector<uint8_t> &getCachedTextureLevelData(gl::Texture *texture,
648                                                     gl::TextureTarget target,
649                                                     GLint level,
650                                                     EntryPoint entryPoint);
651 
652     // Capture coherent buffer storages
653     void captureCoherentBufferSnapshot(const gl::Context *context, gl::BufferID bufferID);
654 
655     // Remove any cached texture levels on deletion
656     void deleteCachedTextureLevelData(gl::TextureID id);
657 
eraseBufferDataMapEntry(const gl::BufferID bufferId)658     void eraseBufferDataMapEntry(const gl::BufferID bufferId)
659     {
660         const auto &bufferDataInfo = mBufferDataMap.find(bufferId);
661         if (bufferDataInfo != mBufferDataMap.end())
662         {
663             mBufferDataMap.erase(bufferDataInfo);
664         }
665     }
666 
hasBufferData(gl::BufferID bufferID)667     bool hasBufferData(gl::BufferID bufferID)
668     {
669         const auto &bufferDataInfo = mBufferDataMap.find(bufferID);
670         if (bufferDataInfo != mBufferDataMap.end())
671         {
672             return true;
673         }
674         return false;
675     }
676 
getBufferDataOffsetAndLength(gl::BufferID bufferID)677     std::pair<GLintptr, GLsizeiptr> getBufferDataOffsetAndLength(gl::BufferID bufferID)
678     {
679         const auto &bufferDataInfo = mBufferDataMap.find(bufferID);
680         ASSERT(bufferDataInfo != mBufferDataMap.end());
681         return bufferDataInfo->second;
682     }
683 
setCaptureActive()684     void setCaptureActive() { mCaptureActive = true; }
setCaptureInactive()685     void setCaptureInactive() { mCaptureActive = false; }
isCaptureActive()686     bool isCaptureActive() { return mCaptureActive; }
usesMidExecutionCapture()687     bool usesMidExecutionCapture() { return mCaptureStartFrame > 1; }
688 
getWindowSurfaceContextID()689     gl::ContextID getWindowSurfaceContextID() const { return mWindowSurfaceContextID; }
690 
691     void markResourceSetupCallsInactive(std::vector<CallCapture> *setupCalls,
692                                         ResourceIDType type,
693                                         GLuint id,
694                                         gl::Range<size_t> range);
695 
updateReadBufferSize(size_t readBufferSize)696     void updateReadBufferSize(size_t readBufferSize)
697     {
698         mReadBufferSize = std::max(mReadBufferSize, readBufferSize);
699     }
700 
701     template <typename ResourceType>
handleGennedResource(const gl::Context * context,ResourceType resourceID)702     void handleGennedResource(const gl::Context *context, ResourceType resourceID)
703     {
704         if (isCaptureActive())
705         {
706             ResourceIDType idType    = GetResourceIDTypeFromType<ResourceType>::IDType;
707             TrackedResource &tracker = mResourceTracker.getTrackedResource(context->id(), idType);
708             tracker.setGennedResource(resourceID.value);
709         }
710     }
711 
712     template <typename ResourceType>
resourceIsGenerated(const gl::Context * context,ResourceType resourceID)713     bool resourceIsGenerated(const gl::Context *context, ResourceType resourceID)
714     {
715         ResourceIDType idType    = GetResourceIDTypeFromType<ResourceType>::IDType;
716         TrackedResource &tracker = mResourceTracker.getTrackedResource(context->id(), idType);
717         return tracker.resourceIsGenerated(resourceID.value);
718     }
719 
720     template <typename ResourceType>
handleDeletedResource(const gl::Context * context,ResourceType resourceID)721     void handleDeletedResource(const gl::Context *context, ResourceType resourceID)
722     {
723         if (isCaptureActive())
724         {
725             ResourceIDType idType    = GetResourceIDTypeFromType<ResourceType>::IDType;
726             TrackedResource &tracker = mResourceTracker.getTrackedResource(context->id(), idType);
727             tracker.setDeletedResource(resourceID.value);
728         }
729     }
730 
731     void *maybeGetShadowMemoryPointer(gl::Buffer *buffer, GLsizeiptr length, GLbitfield access);
732     void determineMemoryProtectionSupport(gl::Context *context);
733 
getFrameCaptureMutex()734     angle::SimpleMutex &getFrameCaptureMutex() { return mFrameCaptureMutex; }
735 
setDeferredLinkProgram(gl::ShaderProgramID programID)736     void setDeferredLinkProgram(gl::ShaderProgramID programID)
737     {
738         mDeferredLinkPrograms.emplace(programID);
739     }
isDeferredLinkProgram(gl::ShaderProgramID programID)740     bool isDeferredLinkProgram(gl::ShaderProgramID programID)
741     {
742         return (mDeferredLinkPrograms.find(programID) != mDeferredLinkPrograms.end());
743     }
744 
745   private:
746     void writeJSON(const gl::Context *context);
747     void writeCppReplayIndexFiles(const gl::Context *context, bool writeResetContextCall);
748     void writeMainContextCppReplay(const gl::Context *context,
749                                    const std::vector<CallCapture> &setupCalls,
750                                    StateResetHelper &StateResetHelper);
751 
752     void captureClientArraySnapshot(const gl::Context *context,
753                                     size_t vertexCount,
754                                     size_t instanceCount);
755     void captureMappedBufferSnapshot(const gl::Context *context, const CallCapture &call);
756 
757     void copyCompressedTextureData(const gl::Context *context, const CallCapture &call);
758     void captureCompressedTextureData(const gl::Context *context, const CallCapture &call);
759 
760     void reset();
761     void maybeOverrideEntryPoint(const gl::Context *context,
762                                  CallCapture &call,
763                                  std::vector<CallCapture> &newCalls);
764     void maybeCapturePreCallUpdates(const gl::Context *context,
765                                     CallCapture &call,
766                                     std::vector<CallCapture> *shareGroupSetupCalls,
767                                     ResourceIDToSetupCallsMap *resourceIDToSetupCalls);
768     template <typename ParamValueType>
769     void maybeGenResourceOnBind(const gl::Context *context, CallCapture &call);
770     void maybeCapturePostCallUpdates(const gl::Context *context);
771     void maybeCaptureDrawArraysClientData(const gl::Context *context,
772                                           CallCapture &call,
773                                           size_t instanceCount);
774     void maybeCaptureDrawElementsClientData(const gl::Context *context,
775                                             CallCapture &call,
776                                             size_t instanceCount);
777     void maybeCaptureCoherentBuffers(const gl::Context *context);
778     void captureCustomMapBufferFromContext(const gl::Context *context,
779                                            const char *entryPointName,
780                                            CallCapture &call,
781                                            std::vector<CallCapture> &callsOut);
782     void updateCopyImageSubData(CallCapture &call);
783     void overrideProgramBinary(const gl::Context *context,
784                                CallCapture &call,
785                                std::vector<CallCapture> &outCalls);
786     void updateResourceCountsFromParamCapture(const ParamCapture &param, ResourceIDType idType);
787     void updateResourceCountsFromCallCapture(const CallCapture &call);
788 
789     void runMidExecutionCapture(gl::Context *context);
790 
791     void scanSetupCalls(std::vector<CallCapture> &setupCalls);
792 
793     std::vector<CallCapture> mFrameCalls;
794 
795     // We save one large buffer of binary data for the whole CPP replay.
796     // This simplifies a lot of file management.
797     std::vector<uint8_t> mBinaryData;
798 
799     bool mEnabled;
800     bool mSerializeStateEnabled;
801     std::string mOutDirectory;
802     std::string mCaptureLabel;
803     bool mCompression;
804     gl::AttribArray<int> mClientVertexArrayMap;
805     uint32_t mFrameIndex;
806     uint32_t mCaptureStartFrame;
807     uint32_t mCaptureEndFrame;
808     bool mIsFirstFrame   = true;
809     bool mWroteIndexFile = false;
810     SurfaceParamsMap mDrawSurfaceParams;
811     gl::AttribArray<size_t> mClientArraySizes;
812     size_t mReadBufferSize;
813     size_t mResourceIDBufferSize;
814     HasResourceTypeMap mHasResourceType;
815     ResourceIDToSetupCallsMap mResourceIDToSetupCalls;
816     BufferDataMap mBufferDataMap;
817     bool mValidateSerializedState = false;
818     std::string mValidationExpression;
819     PackedEnumMap<ResourceIDType, uint32_t> mMaxAccessedResourceIDs;
820     CoherentBufferTracker mCoherentBufferTracker;
821     angle::SimpleMutex mFrameCaptureMutex;
822 
823     ResourceTracker mResourceTracker;
824     ReplayWriter mReplayWriter;
825 
826     // If you don't know which frame you want to start capturing at, use the capture trigger.
827     // Initialize it to the number of frames you want to capture, and then clear the value to 0 when
828     // you reach the content you want to capture. Currently only available on Android.
829     uint32_t mCaptureTrigger;
830 
831     bool mCaptureActive;
832     std::vector<uint32_t> mActiveFrameIndices;
833 
834     // Cache most recently compiled and linked sources.
835     ShaderSourceMap mCachedShaderSource;
836     ProgramSourceMap mCachedProgramSources;
837 
838     // Set of programs which were created but not linked before capture was started
839     std::set<gl::ShaderProgramID> mDeferredLinkPrograms;
840 
841     gl::ContextID mWindowSurfaceContextID;
842 
843     std::vector<CallCapture> mShareGroupSetupCalls;
844     // Track which Contexts were created and made current at least once before MEC,
845     // requiring setup for replay
846     std::unordered_set<GLuint> mActiveContexts;
847 
848     // Invalid call counts per entry point while capture is active and inactive.
849     std::unordered_map<EntryPoint, size_t> mInvalidCallCountsActive;
850     std::unordered_map<EntryPoint, size_t> mInvalidCallCountsInactive;
851 };
852 
853 template <typename CaptureFuncT, typename... ArgsT>
CaptureGLCallToFrameCapture(CaptureFuncT captureFunc,bool isCallValid,gl::Context * context,ArgsT...captureParams)854 void CaptureGLCallToFrameCapture(CaptureFuncT captureFunc,
855                                  bool isCallValid,
856                                  gl::Context *context,
857                                  ArgsT... captureParams)
858 {
859     FrameCaptureShared *frameCaptureShared = context->getShareGroup()->getFrameCaptureShared();
860 
861     // EGL calls are protected by the global context mutex but only a subset of GL calls
862     // are so protected. Ensure FrameCaptureShared access thread safety by using a
863     // frame-capture only mutex.
864     std::lock_guard<angle::SimpleMutex> lock(frameCaptureShared->getFrameCaptureMutex());
865 
866     if (!frameCaptureShared->isCapturing())
867     {
868         return;
869     }
870 
871     CallCapture call = captureFunc(context->getState(), isCallValid, captureParams...);
872     frameCaptureShared->captureCall(context, std::move(call), isCallValid);
873 }
874 
875 template <typename FirstT, typename... OthersT>
GetEGLDisplayArg(FirstT display,OthersT...others)876 egl::Display *GetEGLDisplayArg(FirstT display, OthersT... others)
877 {
878     if constexpr (std::is_same<egl::Display *, FirstT>::value)
879     {
880         return display;
881     }
882     return nullptr;
883 }
884 
885 template <typename CaptureFuncT, typename... ArgsT>
CaptureEGLCallToFrameCapture(CaptureFuncT captureFunc,bool isCallValid,egl::Thread * thread,ArgsT...captureParams)886 void CaptureEGLCallToFrameCapture(CaptureFuncT captureFunc,
887                                   bool isCallValid,
888                                   egl::Thread *thread,
889                                   ArgsT... captureParams)
890 {
891     gl::Context *context = thread->getContext();
892     if (!context)
893     {
894         // Get a valid context from the display argument if no context is associated with this
895         // thread
896         egl::Display *display = GetEGLDisplayArg(captureParams...);
897         if (display)
898         {
899             for (const auto &contextIter : display->getState().contextMap)
900             {
901                 context = contextIter.second;
902                 break;
903             }
904         }
905         if (!context)
906         {
907             return;
908         }
909     }
910     std::lock_guard<egl::ContextMutex> lock(context->getContextMutex());
911 
912     angle::FrameCaptureShared *frameCaptureShared =
913         context->getShareGroup()->getFrameCaptureShared();
914     if (!frameCaptureShared->isCapturing())
915     {
916         return;
917     }
918 
919     angle::CallCapture call = captureFunc(thread, isCallValid, captureParams...);
920     frameCaptureShared->captureCall(context, std::move(call), true);
921 }
922 
923 // Pointer capture helpers.
924 void CaptureMemory(const void *source, size_t size, ParamCapture *paramCapture);
925 void CaptureString(const GLchar *str, ParamCapture *paramCapture);
926 void CaptureStringLimit(const GLchar *str, uint32_t limit, ParamCapture *paramCapture);
927 void CaptureVertexPointerGLES1(const gl::State &glState,
928                                gl::ClientVertexArrayType type,
929                                const void *pointer,
930                                ParamCapture *paramCapture);
931 
932 gl::Program *GetProgramForCapture(const gl::State &glState, gl::ShaderProgramID handle);
933 
934 // For GetIntegerv, GetFloatv, etc.
935 void CaptureGetParameter(const gl::State &glState,
936                          GLenum pname,
937                          size_t typeSize,
938                          ParamCapture *paramCapture);
939 
940 void CaptureGetActiveUniformBlockivParameters(const gl::State &glState,
941                                               gl::ShaderProgramID handle,
942                                               gl::UniformBlockIndex uniformBlockIndex,
943                                               GLenum pname,
944                                               ParamCapture *paramCapture);
945 
946 template <typename T>
CaptureClearBufferValue(GLenum buffer,const T * value,ParamCapture * paramCapture)947 void CaptureClearBufferValue(GLenum buffer, const T *value, ParamCapture *paramCapture)
948 {
949     // Per the spec, color buffers have a vec4, the rest a single value
950     uint32_t valueSize = (buffer == GL_COLOR) ? 4 : 1;
951     CaptureMemory(value, valueSize * sizeof(T), paramCapture);
952 }
953 
954 void CaptureGenHandlesImpl(GLsizei n, GLuint *handles, ParamCapture *paramCapture);
955 
956 template <typename T>
CaptureGenHandles(GLsizei n,T * handles,ParamCapture * paramCapture)957 void CaptureGenHandles(GLsizei n, T *handles, ParamCapture *paramCapture)
958 {
959     paramCapture->dataNElements = n;
960     CaptureGenHandlesImpl(n, reinterpret_cast<GLuint *>(handles), paramCapture);
961 }
962 
963 template <typename T>
CaptureArray(T * elements,GLsizei n,ParamCapture * paramCapture)964 void CaptureArray(T *elements, GLsizei n, ParamCapture *paramCapture)
965 {
966     paramCapture->dataNElements = n;
967     CaptureMemory(elements, n * sizeof(T), paramCapture);
968 }
969 
970 void CaptureShaderStrings(GLsizei count,
971                           const GLchar *const *strings,
972                           const GLint *length,
973                           ParamCapture *paramCapture);
974 
975 bool IsTrackedPerContext(ResourceIDType type);
976 }  // namespace angle
977 
978 template <typename T>
CaptureTextureAndSamplerParameter_params(GLenum pname,const T * param,angle::ParamCapture * paramCapture)979 void CaptureTextureAndSamplerParameter_params(GLenum pname,
980                                               const T *param,
981                                               angle::ParamCapture *paramCapture)
982 {
983     if (pname == GL_TEXTURE_BORDER_COLOR || pname == GL_TEXTURE_CROP_RECT_OES)
984     {
985         CaptureMemory(param, sizeof(T) * 4, paramCapture);
986     }
987     else
988     {
989         CaptureMemory(param, sizeof(T), paramCapture);
990     }
991 }
992 
993 namespace egl
994 {
995 angle::ParamCapture CaptureAttributeMap(const egl::AttributeMap &attribMap);
996 }  // namespace egl
997 
998 #endif  // LIBANGLE_FRAME_CAPTURE_H_
999