• 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 "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 // StateResetHelper provides a simple way to track whether an entry point has been called during the
373 // trace, along with the reset calls to get it back to starting state.  This is useful for things
374 // that are one dimensional, like context bindings or context state.
375 class StateResetHelper final : angle::NonCopyable
376 {
377   public:
378     StateResetHelper();
379     ~StateResetHelper();
380 
getDirtyEntryPoints()381     const std::set<angle::EntryPoint> &getDirtyEntryPoints() const { return mDirtyEntryPoints; }
setEntryPointDirty(EntryPoint entryPoint)382     void setEntryPointDirty(EntryPoint entryPoint) { mDirtyEntryPoints.insert(entryPoint); }
383 
getResetCalls()384     CallResetMap &getResetCalls() { return mResetCalls; }
getResetCalls()385     const CallResetMap &getResetCalls() const { return mResetCalls; }
386 
387     void setDefaultResetCalls(const gl::Context *context, angle::EntryPoint);
388 
getDirtyTextureBindings()389     const std::set<TextureBinding> &getDirtyTextureBindings() const
390     {
391         return mDirtyTextureBindings;
392     }
setTextureBindingDirty(size_t unit,gl::TextureType target)393     void setTextureBindingDirty(size_t unit, gl::TextureType target)
394     {
395         mDirtyTextureBindings.emplace(unit, target);
396     }
397 
getResetTextureBindings()398     TextureResetMap &getResetTextureBindings() { return mResetTextureBindings; }
399 
setResetActiveTexture(size_t textureID)400     void setResetActiveTexture(size_t textureID) { mResetActiveTexture = textureID; }
getResetActiveTexture()401     size_t getResetActiveTexture() { return mResetActiveTexture; }
402 
403   private:
404     // Dirty state per entry point
405     std::set<angle::EntryPoint> mDirtyEntryPoints;
406 
407     // Reset calls per API entry point
408     CallResetMap mResetCalls;
409 
410     // Dirty state per texture binding
411     std::set<TextureBinding> mDirtyTextureBindings;
412 
413     // Texture bindings and active texture to restore
414     TextureResetMap mResetTextureBindings;
415     size_t mResetActiveTexture = 0;
416 };
417 
418 class FrameCapture final : angle::NonCopyable
419 {
420   public:
421     FrameCapture();
422     ~FrameCapture();
423 
getSetupCalls()424     std::vector<CallCapture> &getSetupCalls() { return mSetupCalls; }
clearSetupCalls()425     void clearSetupCalls() { mSetupCalls.clear(); }
426 
getStateResetHelper()427     StateResetHelper &getStateResetHelper() { return mStateResetHelper; }
428 
429     void reset();
430 
431   private:
432     std::vector<CallCapture> mSetupCalls;
433 
434     StateResetHelper mStateResetHelper;
435 };
436 
437 // Page range inside a coherent buffer
438 struct PageRange
439 {
440     PageRange(size_t start, size_t end);
441     ~PageRange();
442 
443     // Relative start page
444     size_t start;
445 
446     // First page after the relative end
447     size_t end;
448 };
449 
450 // Memory address range defined by start and size
451 struct AddressRange
452 {
453     AddressRange();
454     AddressRange(uintptr_t start, size_t size);
455     ~AddressRange();
456 
457     uintptr_t end();
458 
459     uintptr_t start;
460     size_t size;
461 };
462 
463 // Used to handle protection of buffers that overlap in pages.
464 enum class PageSharingType
465 {
466     NoneShared,
467     FirstShared,
468     LastShared,
469     FirstAndLastShared
470 };
471 
472 class CoherentBuffer
473 {
474   public:
475     CoherentBuffer(uintptr_t start, size_t size, size_t pageSize, bool useShadowMemory);
476     ~CoherentBuffer();
477 
478     // Sets the a range in the buffer clean and protects a selected range
479     void protectPageRange(const PageRange &pageRange);
480 
481     // Sets all pages to clean and enables protection
482     void protectAll();
483 
484     // Sets a page dirty state and sets it's protection
485     void setDirty(size_t relativePage, bool dirty);
486 
487     // Shadow memory synchronization
488     void updateBufferMemory();
489     void updateShadowMemory();
490 
491     // Removes protection
492     void removeProtection(PageSharingType sharingType);
493 
494     bool contains(size_t page, size_t *relativePage);
495     bool isDirty();
496 
497     // Returns dirty page ranges
498     std::vector<PageRange> getDirtyPageRanges();
499 
500     // Calculates address range from page range
501     AddressRange getDirtyAddressRange(const PageRange &dirtyPageRange);
502     AddressRange getRange();
503 
markShadowDirty()504     void markShadowDirty() { mShadowDirty = true; }
isShadowDirty()505     bool isShadowDirty() { return mShadowDirty; }
506 
507   private:
508     // Actual buffer start and size
509     AddressRange mRange;
510 
511     // Start and size of page aligned protected area
512     AddressRange mProtectionRange;
513 
514     // Start and end of protection in relative pages, calculated from mProtectionRange.
515     size_t mProtectionStartPage;
516     size_t mProtectionEndPage;
517 
518     size_t mPageCount;
519     size_t mPageSize;
520 
521     // Clean pages are protected
522     std::vector<bool> mDirtyPages;
523 
524     // shadow memory releated fields
525     bool mShadowMemoryEnabled;
526     uintptr_t mBufferStart;
527     void *mShadowMemory;
528     bool mShadowDirty;
529 };
530 
531 class CoherentBufferTracker final : angle::NonCopyable
532 {
533   public:
534     CoherentBufferTracker();
535     ~CoherentBufferTracker();
536 
537     bool isDirty(gl::BufferID id);
538     uintptr_t addBuffer(gl::BufferID id, uintptr_t start, size_t size);
539     void removeBuffer(gl::BufferID id);
540     void disable();
541     void enable();
542     void onEndFrame();
543     bool haveBuffer(gl::BufferID id);
isShadowMemoryEnabled()544     bool isShadowMemoryEnabled() { return mShadowMemoryEnabled; }
enableShadowMemory()545     void enableShadowMemory() { mShadowMemoryEnabled = true; }
546     void maybeUpdateShadowMemory();
547     void markAllShadowDirty();
548     // Determine whether memory protection can be used directly on graphics memory
549     bool canProtectDirectly(gl::Context *context);
550 
551   private:
552     // Detect overlapping pages when removing protection
553     PageSharingType doesBufferSharePage(gl::BufferID id);
554 
555     // Returns a map to found buffers and the corresponding pages for a given address.
556     // For addresses that are in a page shared by 2 buffers, 2 results are returned.
557     HashMap<std::shared_ptr<CoherentBuffer>, size_t> getBufferPagesForAddress(uintptr_t address);
558     PageFaultHandlerRangeType handleWrite(uintptr_t address);
559 
560   public:
561     angle::SimpleMutex mMutex;
562     HashMap<GLuint, std::shared_ptr<CoherentBuffer>> mBuffers;
563 
564   private:
565     bool mEnabled;
566     std::unique_ptr<PageFaultHandler> mPageFaultHandler;
567     size_t mPageSize;
568 
569     bool mShadowMemoryEnabled;
570 };
571 
572 // Shared class for any items that need to be tracked by FrameCapture across shared contexts
573 class FrameCaptureShared final : angle::NonCopyable
574 {
575   public:
576     FrameCaptureShared();
577     ~FrameCaptureShared();
578 
579     void captureCall(gl::Context *context, CallCapture &&call, bool isCallValid);
580     void checkForCaptureTrigger();
581     void onEndFrame(gl::Context *context);
582     void onDestroyContext(const gl::Context *context);
583     void onMakeCurrent(const gl::Context *context, const egl::Surface *drawSurface);
enabled()584     bool enabled() const { return mEnabled; }
585 
586     bool isCapturing() const;
587     uint32_t getFrameCount() const;
588 
589     // Returns a frame index starting from "1" as the first frame.
590     uint32_t getReplayFrameIndex() const;
591 
592     void trackBufferMapping(const gl::Context *context,
593                             CallCapture *call,
594                             gl::BufferID id,
595                             gl::Buffer *buffer,
596                             GLintptr offset,
597                             GLsizeiptr length,
598                             bool writable,
599                             bool coherent);
600 
601     void trackTextureUpdate(const gl::Context *context, const CallCapture &call);
602     void trackImageUpdate(const gl::Context *context, const CallCapture &call);
603     void trackDefaultUniformUpdate(const gl::Context *context, const CallCapture &call);
604     void trackVertexArrayUpdate(const gl::Context *context, const CallCapture &call);
605 
606     const std::string &getShaderSource(gl::ShaderProgramID id) const;
607     void setShaderSource(gl::ShaderProgramID id, std::string sources);
608 
609     const ProgramSources &getProgramSources(gl::ShaderProgramID id) const;
610     void setProgramSources(gl::ShaderProgramID id, ProgramSources sources);
611 
612     // Load data from a previously stored texture level
613     const std::vector<uint8_t> &retrieveCachedTextureLevel(gl::TextureID id,
614                                                            gl::TextureTarget target,
615                                                            GLint level);
616 
617     // Create new texture level data and copy the source into it
618     void copyCachedTextureLevel(const gl::Context *context,
619                                 gl::TextureID srcID,
620                                 GLint srcLevel,
621                                 gl::TextureID dstID,
622                                 GLint dstLevel,
623                                 const CallCapture &call);
624 
625     // Create the location that should be used to cache texture level data
626     std::vector<uint8_t> &getCachedTextureLevelData(gl::Texture *texture,
627                                                     gl::TextureTarget target,
628                                                     GLint level,
629                                                     EntryPoint entryPoint);
630 
631     // Capture coherent buffer storages
632     void captureCoherentBufferSnapshot(const gl::Context *context, gl::BufferID bufferID);
633 
634     // Remove any cached texture levels on deletion
635     void deleteCachedTextureLevelData(gl::TextureID id);
636 
eraseBufferDataMapEntry(const gl::BufferID bufferId)637     void eraseBufferDataMapEntry(const gl::BufferID bufferId)
638     {
639         const auto &bufferDataInfo = mBufferDataMap.find(bufferId);
640         if (bufferDataInfo != mBufferDataMap.end())
641         {
642             mBufferDataMap.erase(bufferDataInfo);
643         }
644     }
645 
hasBufferData(gl::BufferID bufferID)646     bool hasBufferData(gl::BufferID bufferID)
647     {
648         const auto &bufferDataInfo = mBufferDataMap.find(bufferID);
649         if (bufferDataInfo != mBufferDataMap.end())
650         {
651             return true;
652         }
653         return false;
654     }
655 
getBufferDataOffsetAndLength(gl::BufferID bufferID)656     std::pair<GLintptr, GLsizeiptr> getBufferDataOffsetAndLength(gl::BufferID bufferID)
657     {
658         const auto &bufferDataInfo = mBufferDataMap.find(bufferID);
659         ASSERT(bufferDataInfo != mBufferDataMap.end());
660         return bufferDataInfo->second;
661     }
662 
setCaptureActive()663     void setCaptureActive() { mCaptureActive = true; }
setCaptureInactive()664     void setCaptureInactive() { mCaptureActive = false; }
isCaptureActive()665     bool isCaptureActive() { return mCaptureActive; }
usesMidExecutionCapture()666     bool usesMidExecutionCapture() { return mCaptureStartFrame > 1; }
667 
getWindowSurfaceContextID()668     gl::ContextID getWindowSurfaceContextID() const { return mWindowSurfaceContextID; }
669 
670     void markResourceSetupCallsInactive(std::vector<CallCapture> *setupCalls,
671                                         ResourceIDType type,
672                                         GLuint id,
673                                         gl::Range<size_t> range);
674 
updateReadBufferSize(size_t readBufferSize)675     void updateReadBufferSize(size_t readBufferSize)
676     {
677         mReadBufferSize = std::max(mReadBufferSize, readBufferSize);
678     }
679 
680     template <typename ResourceType>
handleGennedResource(const gl::Context * context,ResourceType resourceID)681     void handleGennedResource(const gl::Context *context, ResourceType resourceID)
682     {
683         if (isCaptureActive())
684         {
685             ResourceIDType idType    = GetResourceIDTypeFromType<ResourceType>::IDType;
686             TrackedResource &tracker = mResourceTracker.getTrackedResource(context->id(), idType);
687             tracker.setGennedResource(resourceID.value);
688         }
689     }
690 
691     template <typename ResourceType>
resourceIsGenerated(const gl::Context * context,ResourceType resourceID)692     bool resourceIsGenerated(const gl::Context *context, ResourceType resourceID)
693     {
694         ResourceIDType idType    = GetResourceIDTypeFromType<ResourceType>::IDType;
695         TrackedResource &tracker = mResourceTracker.getTrackedResource(context->id(), idType);
696         return tracker.resourceIsGenerated(resourceID.value);
697     }
698 
699     template <typename ResourceType>
handleDeletedResource(const gl::Context * context,ResourceType resourceID)700     void handleDeletedResource(const gl::Context *context, ResourceType resourceID)
701     {
702         if (isCaptureActive())
703         {
704             ResourceIDType idType    = GetResourceIDTypeFromType<ResourceType>::IDType;
705             TrackedResource &tracker = mResourceTracker.getTrackedResource(context->id(), idType);
706             tracker.setDeletedResource(resourceID.value);
707         }
708     }
709 
710     void *maybeGetShadowMemoryPointer(gl::Buffer *buffer, GLsizeiptr length, GLbitfield access);
711     void determineMemoryProtectionSupport(gl::Context *context);
712 
getFrameCaptureMutex()713     angle::SimpleMutex &getFrameCaptureMutex() { return mFrameCaptureMutex; }
714 
setDeferredLinkProgram(gl::ShaderProgramID programID)715     void setDeferredLinkProgram(gl::ShaderProgramID programID)
716     {
717         mDeferredLinkPrograms.emplace(programID);
718     }
isDeferredLinkProgram(gl::ShaderProgramID programID)719     bool isDeferredLinkProgram(gl::ShaderProgramID programID)
720     {
721         return (mDeferredLinkPrograms.find(programID) != mDeferredLinkPrograms.end());
722     }
723 
724   private:
725     void writeJSON(const gl::Context *context);
726     void writeCppReplayIndexFiles(const gl::Context *context, bool writeResetContextCall);
727     void writeMainContextCppReplay(const gl::Context *context,
728                                    const std::vector<CallCapture> &setupCalls,
729                                    StateResetHelper &StateResetHelper);
730 
731     void captureClientArraySnapshot(const gl::Context *context,
732                                     size_t vertexCount,
733                                     size_t instanceCount);
734     void captureMappedBufferSnapshot(const gl::Context *context, const CallCapture &call);
735 
736     void copyCompressedTextureData(const gl::Context *context, const CallCapture &call);
737     void captureCompressedTextureData(const gl::Context *context, const CallCapture &call);
738 
739     void reset();
740     void maybeOverrideEntryPoint(const gl::Context *context,
741                                  CallCapture &call,
742                                  std::vector<CallCapture> &newCalls);
743     void maybeCapturePreCallUpdates(const gl::Context *context,
744                                     CallCapture &call,
745                                     std::vector<CallCapture> *shareGroupSetupCalls,
746                                     ResourceIDToSetupCallsMap *resourceIDToSetupCalls);
747     template <typename ParamValueType>
748     void maybeGenResourceOnBind(const gl::Context *context, CallCapture &call);
749     void maybeCapturePostCallUpdates(const gl::Context *context);
750     void maybeCaptureDrawArraysClientData(const gl::Context *context,
751                                           CallCapture &call,
752                                           size_t instanceCount);
753     void maybeCaptureDrawElementsClientData(const gl::Context *context,
754                                             CallCapture &call,
755                                             size_t instanceCount);
756     void maybeCaptureCoherentBuffers(const gl::Context *context);
757     void captureCustomMapBufferFromContext(const gl::Context *context,
758                                            const char *entryPointName,
759                                            CallCapture &call,
760                                            std::vector<CallCapture> &callsOut);
761     void updateCopyImageSubData(CallCapture &call);
762     void overrideProgramBinary(const gl::Context *context,
763                                CallCapture &call,
764                                std::vector<CallCapture> &outCalls);
765     void updateResourceCountsFromParamCapture(const ParamCapture &param, ResourceIDType idType);
766     void updateResourceCountsFromCallCapture(const CallCapture &call);
767 
768     void runMidExecutionCapture(gl::Context *context);
769 
770     void scanSetupCalls(std::vector<CallCapture> &setupCalls);
771 
772     std::vector<CallCapture> mFrameCalls;
773 
774     // We save one large buffer of binary data for the whole CPP replay.
775     // This simplifies a lot of file management.
776     std::vector<uint8_t> mBinaryData;
777 
778     bool mEnabled;
779     bool mSerializeStateEnabled;
780     std::string mOutDirectory;
781     std::string mCaptureLabel;
782     bool mCompression;
783     gl::AttribArray<int> mClientVertexArrayMap;
784     uint32_t mFrameIndex;
785     uint32_t mCaptureStartFrame;
786     uint32_t mCaptureEndFrame;
787     bool mIsFirstFrame   = true;
788     bool mWroteIndexFile = false;
789     SurfaceParamsMap mDrawSurfaceParams;
790     gl::AttribArray<size_t> mClientArraySizes;
791     size_t mReadBufferSize;
792     size_t mResourceIDBufferSize;
793     HasResourceTypeMap mHasResourceType;
794     ResourceIDToSetupCallsMap mResourceIDToSetupCalls;
795     BufferDataMap mBufferDataMap;
796     bool mValidateSerializedState = false;
797     std::string mValidationExpression;
798     PackedEnumMap<ResourceIDType, uint32_t> mMaxAccessedResourceIDs;
799     CoherentBufferTracker mCoherentBufferTracker;
800     angle::SimpleMutex mFrameCaptureMutex;
801 
802     ResourceTracker mResourceTracker;
803     ReplayWriter mReplayWriter;
804 
805     // If you don't know which frame you want to start capturing at, use the capture trigger.
806     // Initialize it to the number of frames you want to capture, and then clear the value to 0 when
807     // you reach the content you want to capture. Currently only available on Android.
808     uint32_t mCaptureTrigger;
809 
810     bool mCaptureActive;
811     std::vector<uint32_t> mActiveFrameIndices;
812 
813     // Cache most recently compiled and linked sources.
814     ShaderSourceMap mCachedShaderSource;
815     ProgramSourceMap mCachedProgramSources;
816 
817     // Set of programs which were created but not linked before capture was started
818     std::set<gl::ShaderProgramID> mDeferredLinkPrograms;
819 
820     gl::ContextID mWindowSurfaceContextID;
821 
822     std::vector<CallCapture> mShareGroupSetupCalls;
823     // Track which Contexts were created and made current at least once before MEC,
824     // requiring setup for replay
825     std::unordered_set<GLuint> mActiveContexts;
826 
827     // Invalid call counts per entry point while capture is active and inactive.
828     std::unordered_map<EntryPoint, size_t> mInvalidCallCountsActive;
829     std::unordered_map<EntryPoint, size_t> mInvalidCallCountsInactive;
830 };
831 
832 template <typename CaptureFuncT, typename... ArgsT>
CaptureGLCallToFrameCapture(CaptureFuncT captureFunc,bool isCallValid,gl::Context * context,ArgsT...captureParams)833 void CaptureGLCallToFrameCapture(CaptureFuncT captureFunc,
834                                  bool isCallValid,
835                                  gl::Context *context,
836                                  ArgsT... captureParams)
837 {
838     FrameCaptureShared *frameCaptureShared = context->getShareGroup()->getFrameCaptureShared();
839 
840     // EGL calls are protected by the global context mutex but only a subset of GL calls
841     // are so protected. Ensure FrameCaptureShared access thread safety by using a
842     // frame-capture only mutex.
843     std::lock_guard<angle::SimpleMutex> lock(frameCaptureShared->getFrameCaptureMutex());
844 
845     if (!frameCaptureShared->isCapturing())
846     {
847         return;
848     }
849 
850     CallCapture call = captureFunc(context->getState(), isCallValid, captureParams...);
851     frameCaptureShared->captureCall(context, std::move(call), isCallValid);
852 }
853 
854 template <typename FirstT, typename... OthersT>
GetEGLDisplayArg(FirstT display,OthersT...others)855 egl::Display *GetEGLDisplayArg(FirstT display, OthersT... others)
856 {
857     if constexpr (std::is_same<egl::Display *, FirstT>::value)
858     {
859         return display;
860     }
861     return nullptr;
862 }
863 
864 template <typename CaptureFuncT, typename... ArgsT>
CaptureEGLCallToFrameCapture(CaptureFuncT captureFunc,bool isCallValid,egl::Thread * thread,ArgsT...captureParams)865 void CaptureEGLCallToFrameCapture(CaptureFuncT captureFunc,
866                                   bool isCallValid,
867                                   egl::Thread *thread,
868                                   ArgsT... captureParams)
869 {
870     gl::Context *context = thread->getContext();
871     if (!context)
872     {
873         // Get a valid context from the display argument if no context is associated with this
874         // thread
875         egl::Display *display = GetEGLDisplayArg(captureParams...);
876         if (display)
877         {
878             for (const auto &contextIter : display->getState().contextMap)
879             {
880                 context = contextIter.second;
881                 break;
882             }
883         }
884         if (!context)
885         {
886             return;
887         }
888     }
889     std::lock_guard<egl::ContextMutex> lock(context->getContextMutex());
890 
891     angle::FrameCaptureShared *frameCaptureShared =
892         context->getShareGroup()->getFrameCaptureShared();
893     if (!frameCaptureShared->isCapturing())
894     {
895         return;
896     }
897 
898     angle::CallCapture call = captureFunc(thread, isCallValid, captureParams...);
899     frameCaptureShared->captureCall(context, std::move(call), true);
900 }
901 
902 // Pointer capture helpers.
903 void CaptureMemory(const void *source, size_t size, ParamCapture *paramCapture);
904 void CaptureString(const GLchar *str, ParamCapture *paramCapture);
905 void CaptureStringLimit(const GLchar *str, uint32_t limit, ParamCapture *paramCapture);
906 void CaptureVertexPointerGLES1(const gl::State &glState,
907                                gl::ClientVertexArrayType type,
908                                const void *pointer,
909                                ParamCapture *paramCapture);
910 
911 gl::Program *GetProgramForCapture(const gl::State &glState, gl::ShaderProgramID handle);
912 
913 // For GetIntegerv, GetFloatv, etc.
914 void CaptureGetParameter(const gl::State &glState,
915                          GLenum pname,
916                          size_t typeSize,
917                          ParamCapture *paramCapture);
918 
919 void CaptureGetActiveUniformBlockivParameters(const gl::State &glState,
920                                               gl::ShaderProgramID handle,
921                                               gl::UniformBlockIndex uniformBlockIndex,
922                                               GLenum pname,
923                                               ParamCapture *paramCapture);
924 
925 template <typename T>
CaptureClearBufferValue(GLenum buffer,const T * value,ParamCapture * paramCapture)926 void CaptureClearBufferValue(GLenum buffer, const T *value, ParamCapture *paramCapture)
927 {
928     // Per the spec, color buffers have a vec4, the rest a single value
929     uint32_t valueSize = (buffer == GL_COLOR) ? 4 : 1;
930     CaptureMemory(value, valueSize * sizeof(T), paramCapture);
931 }
932 
933 void CaptureGenHandlesImpl(GLsizei n, GLuint *handles, ParamCapture *paramCapture);
934 
935 template <typename T>
CaptureGenHandles(GLsizei n,T * handles,ParamCapture * paramCapture)936 void CaptureGenHandles(GLsizei n, T *handles, ParamCapture *paramCapture)
937 {
938     paramCapture->dataNElements = n;
939     CaptureGenHandlesImpl(n, reinterpret_cast<GLuint *>(handles), paramCapture);
940 }
941 
942 template <typename T>
CaptureArray(T * elements,GLsizei n,ParamCapture * paramCapture)943 void CaptureArray(T *elements, GLsizei n, ParamCapture *paramCapture)
944 {
945     paramCapture->dataNElements = n;
946     CaptureMemory(elements, n * sizeof(T), paramCapture);
947 }
948 
949 void CaptureShaderStrings(GLsizei count,
950                           const GLchar *const *strings,
951                           const GLint *length,
952                           ParamCapture *paramCapture);
953 
954 }  // namespace angle
955 
956 template <typename T>
CaptureTextureAndSamplerParameter_params(GLenum pname,const T * param,angle::ParamCapture * paramCapture)957 void CaptureTextureAndSamplerParameter_params(GLenum pname,
958                                               const T *param,
959                                               angle::ParamCapture *paramCapture)
960 {
961     if (pname == GL_TEXTURE_BORDER_COLOR || pname == GL_TEXTURE_CROP_RECT_OES)
962     {
963         CaptureMemory(param, sizeof(T) * 4, paramCapture);
964     }
965     else
966     {
967         CaptureMemory(param, sizeof(T), paramCapture);
968     }
969 }
970 
971 namespace egl
972 {
973 angle::ParamCapture CaptureAttributeMap(const egl::AttributeMap &attribMap);
974 }  // namespace egl
975 
976 #endif  // LIBANGLE_FRAME_CAPTURE_H_
977