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