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/system_utils.h"
15 #include "libANGLE/Context.h"
16 #include "libANGLE/angletypes.h"
17 #include "libANGLE/capture/frame_capture_utils_autogen.h"
18 #include "libANGLE/entry_points_utils.h"
19
20 namespace gl
21 {
22 enum class GLenumGroup;
23 }
24
25 namespace angle
26 {
27
28 using ParamData = std::vector<std::vector<uint8_t>>;
29 struct ParamCapture : angle::NonCopyable
30 {
31 ParamCapture();
32 ParamCapture(const char *nameIn, ParamType typeIn);
33 ~ParamCapture();
34
35 ParamCapture(ParamCapture &&other);
36 ParamCapture &operator=(ParamCapture &&other);
37
38 std::string name;
39 ParamType type;
40 ParamValue value;
41 gl::GLenumGroup enumGroup; // only used for param type GLenum, GLboolean and GLbitfield
42 ParamData data;
43 int dataNElements = 0;
44 int arrayClientPointerIndex = -1;
45 size_t readBufferSizeBytes = 0;
46 };
47
48 class ParamBuffer final : angle::NonCopyable
49 {
50 public:
51 ParamBuffer();
52 ~ParamBuffer();
53
54 ParamBuffer(ParamBuffer &&other);
55 ParamBuffer &operator=(ParamBuffer &&other);
56
57 template <typename T>
58 void addValueParam(const char *paramName, ParamType paramType, T paramValue);
59 template <typename T>
60 void setValueParamAtIndex(const char *paramName, ParamType paramType, T paramValue, int index);
61 template <typename T>
62 void addEnumParam(const char *paramName,
63 gl::GLenumGroup enumGroup,
64 ParamType paramType,
65 T paramValue);
66
67 ParamCapture &getParam(const char *paramName, ParamType paramType, int index);
68 const ParamCapture &getParam(const char *paramName, ParamType paramType, int index) const;
69 ParamCapture &getParamFlexName(const char *paramName1,
70 const char *paramName2,
71 ParamType paramType,
72 int index);
73 const ParamCapture &getParamFlexName(const char *paramName1,
74 const char *paramName2,
75 ParamType paramType,
76 int index) const;
getReturnValue()77 const ParamCapture &getReturnValue() const { return mReturnValueCapture; }
78
79 void addParam(ParamCapture &¶m);
80 void addReturnValue(ParamCapture &&returnValue);
hasClientArrayData()81 bool hasClientArrayData() const { return mClientArrayDataParam != -1; }
82 ParamCapture &getClientArrayPointerParameter();
getReadBufferSize()83 size_t getReadBufferSize() const { return mReadBufferSize; }
84
getParamCaptures()85 const std::vector<ParamCapture> &getParamCaptures() const { return mParamCaptures; }
86
87 // These helpers allow us to track the ID of the buffer that was active when
88 // MapBufferRange was called. We'll use it during replay to track the
89 // buffer's contents, as they can be modified by the host.
setMappedBufferID(gl::BufferID bufferID)90 void setMappedBufferID(gl::BufferID bufferID) { mMappedBufferID = bufferID; }
getMappedBufferID()91 gl::BufferID getMappedBufferID() const { return mMappedBufferID; }
92
93 private:
94 std::vector<ParamCapture> mParamCaptures;
95 ParamCapture mReturnValueCapture;
96 int mClientArrayDataParam = -1;
97 size_t mReadBufferSize = 0;
98 gl::BufferID mMappedBufferID;
99 };
100
101 struct CallCapture
102 {
103 CallCapture(EntryPoint entryPointIn, ParamBuffer &¶msIn);
104 CallCapture(const std::string &customFunctionNameIn, ParamBuffer &¶msIn);
105 ~CallCapture();
106
107 CallCapture(CallCapture &&other);
108 CallCapture &operator=(CallCapture &&other);
109
110 const char *name() const;
111
112 EntryPoint entryPoint;
113 std::string customFunctionName;
114 ParamBuffer params;
115 bool isActive = true;
116 };
117
118 class ReplayContext
119 {
120 public:
121 ReplayContext(size_t readBufferSizebytes, const gl::AttribArray<size_t> &clientArraysSizebytes);
122 ~ReplayContext();
123
124 template <typename T>
getReadBufferPointer(const ParamCapture & param)125 T getReadBufferPointer(const ParamCapture ¶m)
126 {
127 ASSERT(param.readBufferSizeBytes > 0);
128 ASSERT(mReadBuffer.size() >= param.readBufferSizeBytes);
129 return reinterpret_cast<T>(mReadBuffer.data());
130 }
131 template <typename T>
getAsConstPointer(const ParamCapture & param)132 T getAsConstPointer(const ParamCapture ¶m)
133 {
134 if (param.arrayClientPointerIndex != -1)
135 {
136 return reinterpret_cast<T>(mClientArraysBuffer[param.arrayClientPointerIndex].data());
137 }
138
139 if (!param.data.empty())
140 {
141 ASSERT(param.data.size() == 1);
142 return reinterpret_cast<T>(param.data[0].data());
143 }
144
145 return nullptr;
146 }
147
148 template <typename T>
getAsPointerConstPointer(const ParamCapture & param)149 T getAsPointerConstPointer(const ParamCapture ¶m)
150 {
151 static_assert(sizeof(typename std::remove_pointer<T>::type) == sizeof(uint8_t *),
152 "pointer size not match!");
153
154 ASSERT(!param.data.empty());
155 mPointersBuffer.clear();
156 mPointersBuffer.reserve(param.data.size());
157 for (const std::vector<uint8_t> &data : param.data)
158 {
159 mPointersBuffer.emplace_back(data.data());
160 }
161 return reinterpret_cast<T>(mPointersBuffer.data());
162 }
163
getClientArraysBuffer()164 gl::AttribArray<std::vector<uint8_t>> &getClientArraysBuffer() { return mClientArraysBuffer; }
165
166 private:
167 std::vector<uint8_t> mReadBuffer;
168 std::vector<const uint8_t *> mPointersBuffer;
169 gl::AttribArray<std::vector<uint8_t>> mClientArraysBuffer;
170 };
171
172 // Helper to use unique IDs for each local data variable.
173 class DataCounters final : angle::NonCopyable
174 {
175 public:
176 DataCounters();
177 ~DataCounters();
178
179 int getAndIncrement(EntryPoint entryPoint, const std::string ¶mName);
180
181 private:
182 // <CallName, ParamName>
183 using Counter = std::pair<EntryPoint, std::string>;
184 std::map<Counter, int> mData;
185 };
186
187 constexpr int kStringsNotFound = -1;
188 class StringCounters final : angle::NonCopyable
189 {
190 public:
191 StringCounters();
192 ~StringCounters();
193
194 int getStringCounter(const std::vector<std::string> &str);
195 void setStringCounter(const std::vector<std::string> &str, int &counter);
196
197 private:
198 std::map<std::vector<std::string>, int> mStringCounterMap;
199 };
200
201 class DataTracker final : angle::NonCopyable
202 {
203 public:
204 DataTracker();
205 ~DataTracker();
206
getCounters()207 DataCounters &getCounters() { return mCounters; }
getStringCounters()208 StringCounters &getStringCounters() { return mStringCounters; }
209
210 private:
211 DataCounters mCounters;
212 StringCounters mStringCounters;
213 };
214
215 class ReplayWriter final : angle::NonCopyable
216 {
217 public:
218 ReplayWriter();
219 ~ReplayWriter();
220
221 void setSourceFileSizeThreshold(size_t sourceFileSizeThreshold);
222 void setFilenamePattern(const std::string &pattern);
223 void setCaptureLabel(const std::string &label);
224 void setSourcePrologue(const std::string &prologue);
225 void setHeaderPrologue(const std::string &prologue);
226
227 void addPublicFunction(const std::string &functionProto,
228 const std::stringstream &headerStream,
229 const std::stringstream &bodyStream);
230 void addPrivateFunction(const std::string &functionProto,
231 const std::stringstream &headerStream,
232 const std::stringstream &bodyStream);
233 std::string getInlineVariableName(EntryPoint entryPoint, const std::string ¶mName);
234
235 std::string getInlineStringSetVariableName(EntryPoint entryPoint,
236 const std::string ¶mName,
237 const std::vector<std::string> &strings,
238 bool *isNewEntryOut);
239
240 void saveFrame();
241 void saveFrameIfFull();
242 void saveIndexFilesAndHeader();
243 void saveSetupFile();
244
245 std::vector<std::string> getAndResetWrittenFiles();
246
247 private:
248 static std::string GetVarName(EntryPoint entryPoint, const std::string ¶mName, int counter);
249
250 void saveHeader();
251 void writeReplaySource(const std::string &filename);
252 void addWrittenFile(const std::string &filename);
253 size_t getStoredReplaySourceSize() const;
254
255 size_t mSourceFileSizeThreshold;
256 size_t mFrameIndex;
257
258 DataTracker mDataTracker;
259 std::string mFilenamePattern;
260 std::string mCaptureLabel;
261 std::string mSourcePrologue;
262 std::string mHeaderPrologue;
263
264 std::vector<std::string> mReplayHeaders;
265 std::vector<std::string> mGlobalVariableDeclarations;
266
267 std::vector<std::string> mPublicFunctionPrototypes;
268 std::vector<std::string> mPublicFunctions;
269
270 std::vector<std::string> mPrivateFunctionPrototypes;
271 std::vector<std::string> mPrivateFunctions;
272
273 std::vector<std::string> mWrittenFiles;
274 };
275
276 using BufferCalls = std::map<GLuint, std::vector<CallCapture>>;
277
278 // true means mapped, false means unmapped
279 using BufferMapStatusMap = std::map<GLuint, bool>;
280
281 using FenceSyncSet = std::set<GLsync>;
282 using FenceSyncCalls = std::map<GLsync, std::vector<CallCapture>>;
283
284 using ResourceSet = std::set<GLuint>;
285 using ResourceCalls = std::map<GLuint, std::vector<CallCapture>>;
286
287 class TrackedResource final : angle::NonCopyable
288 {
289 public:
290 TrackedResource();
291 ~TrackedResource();
292
getStartingResources()293 const ResourceSet &getStartingResources() const { return mStartingResources; }
getStartingResources()294 ResourceSet &getStartingResources() { return mStartingResources; }
getNewResources()295 const ResourceSet &getNewResources() const { return mNewResources; }
getNewResources()296 ResourceSet &getNewResources() { return mNewResources; }
getResourcesToRegen()297 const ResourceSet &getResourcesToRegen() const { return mResourcesToRegen; }
getResourcesToRegen()298 ResourceSet &getResourcesToRegen() { return mResourcesToRegen; }
getResourcesToRestore()299 const ResourceSet &getResourcesToRestore() const { return mResourcesToRestore; }
getResourcesToRestore()300 ResourceSet &getResourcesToRestore() { return mResourcesToRestore; }
301
302 void setGennedResource(GLuint id);
303 void setDeletedResource(GLuint id);
304 void setModifiedResource(GLuint id);
305 bool resourceIsGenerated(GLuint id);
306
getResourceRegenCalls()307 ResourceCalls &getResourceRegenCalls() { return mResourceRegenCalls; }
getResourceRestoreCalls()308 ResourceCalls &getResourceRestoreCalls() { return mResourceRestoreCalls; }
309
310 private:
311 // Resource regen calls will gen a resource
312 ResourceCalls mResourceRegenCalls;
313 // Resource restore calls will restore the contents of a resource
314 ResourceCalls mResourceRestoreCalls;
315
316 // Resources created during startup
317 ResourceSet mStartingResources;
318
319 // Resources created during the run that need to be deleted
320 ResourceSet mNewResources;
321 // Resources deleted during the run that need to be recreated
322 ResourceSet mResourcesToRegen;
323 // Resources modified during the run that need to be restored
324 ResourceSet mResourcesToRestore;
325 };
326
327 using TrackedResourceArray =
328 std::array<TrackedResource, static_cast<uint32_t>(ResourceIDType::EnumCount)>;
329
330 // Helper to track resource changes during the capture
331 class ResourceTracker final : angle::NonCopyable
332 {
333 public:
334 ResourceTracker();
335 ~ResourceTracker();
336
getBufferMapCalls()337 BufferCalls &getBufferMapCalls() { return mBufferMapCalls; }
getBufferUnmapCalls()338 BufferCalls &getBufferUnmapCalls() { return mBufferUnmapCalls; }
339
getBufferBindingCalls()340 std::vector<CallCapture> &getBufferBindingCalls() { return mBufferBindingCalls; }
341
342 void setBufferMapped(GLuint id);
343 void setBufferUnmapped(GLuint id);
344
345 bool getStartingBuffersMappedCurrent(GLuint id) const;
346 bool getStartingBuffersMappedInitial(GLuint id) const;
347
setStartingBufferMapped(GLuint id,bool mapped)348 void setStartingBufferMapped(GLuint id, bool mapped)
349 {
350 // Track the current state (which will change throughout the trace)
351 mStartingBuffersMappedCurrent[id] = mapped;
352
353 // And the initial state, to compare during frame loop reset
354 mStartingBuffersMappedInitial[id] = mapped;
355 }
356
357 void onShaderProgramAccess(gl::ShaderProgramID shaderProgramID);
getMaxShaderPrograms()358 uint32_t getMaxShaderPrograms() const { return mMaxShaderPrograms; }
359
getStartingFenceSyncs()360 FenceSyncSet &getStartingFenceSyncs() { return mStartingFenceSyncs; }
getFenceSyncRegenCalls()361 FenceSyncCalls &getFenceSyncRegenCalls() { return mFenceSyncRegenCalls; }
getFenceSyncsToRegen()362 FenceSyncSet &getFenceSyncsToRegen() { return mFenceSyncsToRegen; }
363 void setDeletedFenceSync(GLsync sync);
364
getTrackedResource(ResourceIDType type)365 TrackedResource &getTrackedResource(ResourceIDType type)
366 {
367 return mTrackedResources[static_cast<uint32_t>(type)];
368 }
369
370 private:
371 // Buffer map calls will map a buffer with correct offset, length, and access flags
372 BufferCalls mBufferMapCalls;
373 // Buffer unmap calls will bind and unmap a given buffer
374 BufferCalls mBufferUnmapCalls;
375
376 // Buffer binding calls to restore bindings recorded during MEC
377 std::vector<CallCapture> mBufferBindingCalls;
378
379 // Whether a given buffer was mapped at the start of the trace
380 BufferMapStatusMap mStartingBuffersMappedInitial;
381 // The status of buffer mapping throughout the trace, modified with each Map/Unmap call
382 BufferMapStatusMap mStartingBuffersMappedCurrent;
383
384 // Maximum accessed shader program ID.
385 uint32_t mMaxShaderPrograms = 0;
386
387 // Fence sync objects created during MEC setup
388 FenceSyncSet mStartingFenceSyncs;
389 // Fence sync regen calls will create a fence sync objects
390 FenceSyncCalls mFenceSyncRegenCalls;
391 // Fence syncs to regen are a list of starting fence sync objects that were deleted and need to
392 // be regen'ed.
393 FenceSyncSet mFenceSyncsToRegen;
394
395 TrackedResourceArray mTrackedResources;
396 };
397
398 // Used by the CPP replay to filter out unnecessary code.
399 using HasResourceTypeMap = angle::PackedEnumBitSet<ResourceIDType>;
400
401 // Map of ResourceType to IDs and range of setup calls
402 using ResourceIDToSetupCallsMap =
403 PackedEnumMap<ResourceIDType, std::map<GLuint, gl::Range<size_t>>>;
404
405 // Map of buffer ID to offset and size used when mapped
406 using BufferDataMap = std::map<gl::BufferID, std::pair<GLintptr, GLsizeiptr>>;
407
408 // A dictionary of sources indexed by shader type.
409 using ProgramSources = gl::ShaderMap<std::string>;
410
411 // Maps from IDs to sources.
412 using ShaderSourceMap = std::map<gl::ShaderProgramID, std::string>;
413 using ProgramSourceMap = std::map<gl::ShaderProgramID, ProgramSources>;
414
415 // Map from textureID to level and data
416 using TextureLevels = std::map<GLint, std::vector<uint8_t>>;
417 using TextureLevelDataMap = std::map<gl::TextureID, TextureLevels>;
418
419 struct SurfaceParams
420 {
421 gl::Extents extents;
422 egl::ColorSpace colorSpace;
423 };
424
425 // Map from ContextID to SurfaceParams
426 using SurfaceParamsMap = std::map<gl::ContextID, SurfaceParams>;
427
428 using CallVector = std::vector<std::vector<CallCapture> *>;
429
430 class FrameCapture final : angle::NonCopyable
431 {
432 public:
433 FrameCapture();
434 ~FrameCapture();
435
getSetupCalls()436 std::vector<CallCapture> &getSetupCalls() { return mSetupCalls; }
clearSetupCalls()437 void clearSetupCalls() { mSetupCalls.clear(); }
438
439 void reset();
440
441 private:
442 std::vector<CallCapture> mSetupCalls;
443 };
444
445 // Page range inside a coherent buffer
446 struct PageRange
447 {
448 PageRange(size_t start, size_t end);
449 ~PageRange();
450
451 // Relative start page
452 size_t start;
453
454 // First page after the relative end
455 size_t end;
456 };
457
458 // Memory address range defined by start and size
459 struct AddressRange
460 {
461 AddressRange();
462 AddressRange(uintptr_t start, size_t size);
463 ~AddressRange();
464
465 uintptr_t end();
466
467 uintptr_t start;
468 size_t size;
469 };
470
471 // Used to handle protection of buffers that overlap in pages.
472 enum class PageSharingType
473 {
474 NoneShared,
475 FirstShared,
476 LastShared,
477 FirstAndLastShared
478 };
479
480 class CoherentBuffer
481 {
482 public:
483 CoherentBuffer(uintptr_t start, size_t size, size_t pageSize);
484 ~CoherentBuffer();
485
486 // Sets the a range in the buffer clean and protects a selected range
487 void protectPageRange(const PageRange &pageRange);
488
489 // Sets a page dirty state and sets it's protection
490 void setDirty(size_t relativePage, bool dirty);
491
492 // Removes protection
493 void removeProtection(PageSharingType sharingType);
494
495 bool contains(size_t page, size_t *relativePage);
496 bool isDirty();
497
498 // Returns dirty page ranges
499 std::vector<PageRange> getDirtyPageRanges();
500
501 // Calculates address range from page range
502 AddressRange getDirtyAddressRange(const PageRange &dirtyPageRange);
503 AddressRange getRange();
504
505 private:
506 // Actual buffer start and size
507 AddressRange mRange;
508
509 // Start and size of page aligned protected area
510 AddressRange mProtectionRange;
511
512 // Start and end of protection in relative pages, calculated from mProtectionRange.
513 size_t mProtectionStartPage;
514 size_t mProtectionEndPage;
515
516 size_t mPageCount;
517 size_t mPageSize;
518
519 // Clean pages are protected
520 std::vector<bool> mDirtyPages;
521 };
522
523 class CoherentBufferTracker final : angle::NonCopyable
524 {
525 public:
526 CoherentBufferTracker();
527 ~CoherentBufferTracker();
528
529 bool isDirty(gl::BufferID id);
530 void addBuffer(gl::BufferID id, uintptr_t start, size_t size);
531 void removeBuffer(gl::BufferID id);
532 void disable();
533 void enable();
534 void onEndFrame();
535
536 private:
537 // Detect overlapping pages when removing protection
538 PageSharingType doesBufferSharePage(gl::BufferID id);
539
540 // Returns a map to found buffers and the corresponding pages for a given address.
541 // For addresses that are in a page shared by 2 buffers, 2 results are returned.
542 HashMap<std::shared_ptr<CoherentBuffer>, size_t> getBufferPagesForAddress(uintptr_t address);
543 PageFaultHandlerRangeType handleWrite(uintptr_t address);
544 bool haveBuffer(gl::BufferID id);
545
546 public:
547 std::mutex mMutex;
548 HashMap<GLuint, std::shared_ptr<CoherentBuffer>> mBuffers;
549
550 private:
551 bool mEnabled = false;
552 std::unique_ptr<PageFaultHandler> mPageFaultHandler;
553 size_t mPageSize;
554 };
555
556 // Shared class for any items that need to be tracked by FrameCapture across shared contexts
557 class FrameCaptureShared final : angle::NonCopyable
558 {
559 public:
560 FrameCaptureShared();
561 ~FrameCaptureShared();
562
563 void captureCall(const gl::Context *context, CallCapture &&call, bool isCallValid);
564 void checkForCaptureTrigger();
565 void onEndFrame(const gl::Context *context);
566 void onDestroyContext(const gl::Context *context);
567 void onMakeCurrent(const gl::Context *context, const egl::Surface *drawSurface);
enabled()568 bool enabled() const { return mEnabled; }
569
570 bool isCapturing() const;
571 void replay(gl::Context *context);
572 uint32_t getFrameCount() const;
573
574 // Returns a frame index starting from "1" as the first frame.
575 uint32_t getReplayFrameIndex() const;
576
577 void trackBufferMapping(CallCapture *call,
578 gl::BufferID id,
579 gl::Buffer *buffer,
580 GLintptr offset,
581 GLsizeiptr length,
582 bool writable,
583 bool coherent);
584
585 void trackTextureUpdate(const gl::Context *context, const CallCapture &call);
586
587 const std::string &getShaderSource(gl::ShaderProgramID id) const;
588 void setShaderSource(gl::ShaderProgramID id, std::string sources);
589
590 const ProgramSources &getProgramSources(gl::ShaderProgramID id) const;
591 void setProgramSources(gl::ShaderProgramID id, ProgramSources sources);
592
593 // Load data from a previously stored texture level
594 const std::vector<uint8_t> &retrieveCachedTextureLevel(gl::TextureID id,
595 gl::TextureTarget target,
596 GLint level);
597
598 // Create new texture level data and copy the source into it
599 void copyCachedTextureLevel(const gl::Context *context,
600 gl::TextureID srcID,
601 GLint srcLevel,
602 gl::TextureID dstID,
603 GLint dstLevel,
604 const CallCapture &call);
605
606 // Create the location that should be used to cache texture level data
607 std::vector<uint8_t> &getCachedTextureLevelData(gl::Texture *texture,
608 gl::TextureTarget target,
609 GLint level,
610 EntryPoint entryPoint);
611
612 // Capture coherent buffer storages
613 void captureCoherentBufferSnapshot(const gl::Context *context, gl::BufferID bufferID);
614
615 // Remove any cached texture levels on deletion
616 void deleteCachedTextureLevelData(gl::TextureID id);
617
eraseBufferDataMapEntry(const gl::BufferID bufferId)618 void eraseBufferDataMapEntry(const gl::BufferID bufferId)
619 {
620 const auto &bufferDataInfo = mBufferDataMap.find(bufferId);
621 if (bufferDataInfo != mBufferDataMap.end())
622 {
623 mBufferDataMap.erase(bufferDataInfo);
624 }
625 }
626
hasBufferData(gl::BufferID bufferID)627 bool hasBufferData(gl::BufferID bufferID)
628 {
629 const auto &bufferDataInfo = mBufferDataMap.find(bufferID);
630 if (bufferDataInfo != mBufferDataMap.end())
631 {
632 return true;
633 }
634 return false;
635 }
636
getBufferDataOffsetAndLength(gl::BufferID bufferID)637 std::pair<GLintptr, GLsizeiptr> getBufferDataOffsetAndLength(gl::BufferID bufferID)
638 {
639 const auto &bufferDataInfo = mBufferDataMap.find(bufferID);
640 ASSERT(bufferDataInfo != mBufferDataMap.end());
641 return bufferDataInfo->second;
642 }
643
setCaptureActive()644 void setCaptureActive() { mCaptureActive = true; }
setCaptureInactive()645 void setCaptureInactive() { mCaptureActive = false; }
isCaptureActive()646 bool isCaptureActive() { return mCaptureActive; }
usesMidExecutionCapture()647 bool usesMidExecutionCapture() { return mCaptureStartFrame > 1; }
648
getWindowSurfaceContextID()649 gl::ContextID getWindowSurfaceContextID() const { return mWindowSurfaceContextID; }
650
651 void markResourceSetupCallsInactive(std::vector<CallCapture> *setupCalls,
652 ResourceIDType type,
653 GLuint id,
654 gl::Range<size_t> range);
655
updateReadBufferSize(size_t readBufferSize)656 void updateReadBufferSize(size_t readBufferSize)
657 {
658 mReadBufferSize = std::max(mReadBufferSize, readBufferSize);
659 }
660
661 template <typename ResourceType>
handleGennedResource(ResourceType resourceID)662 void handleGennedResource(ResourceType resourceID)
663 {
664 if (isCaptureActive())
665 {
666 ResourceIDType idType = GetResourceIDTypeFromType<ResourceType>::IDType;
667 TrackedResource &tracker = mResourceTracker.getTrackedResource(idType);
668 tracker.setGennedResource(resourceID.value);
669 }
670 }
671
672 template <typename ResourceType>
resourceIsGenerated(ResourceType resourceID)673 bool resourceIsGenerated(ResourceType resourceID)
674 {
675 ResourceIDType idType = GetResourceIDTypeFromType<ResourceType>::IDType;
676 TrackedResource &tracker = mResourceTracker.getTrackedResource(idType);
677 return tracker.resourceIsGenerated(resourceID.value);
678 }
679
680 template <typename ResourceType>
handleDeletedResource(ResourceType resourceID)681 void handleDeletedResource(ResourceType resourceID)
682 {
683 if (isCaptureActive())
684 {
685 ResourceIDType idType = GetResourceIDTypeFromType<ResourceType>::IDType;
686 TrackedResource &tracker = mResourceTracker.getTrackedResource(idType);
687 tracker.setDeletedResource(resourceID.value);
688 }
689 }
690
691 private:
692 void writeJSON(const gl::Context *context);
693 void writeCppReplayIndexFiles(const gl::Context *context, bool writeResetContextCall);
694 void writeMainContextCppReplay(const gl::Context *context,
695 const std::vector<CallCapture> &setupCalls);
696
697 void captureClientArraySnapshot(const gl::Context *context,
698 size_t vertexCount,
699 size_t instanceCount);
700 void captureMappedBufferSnapshot(const gl::Context *context, const CallCapture &call);
701
702 void copyCompressedTextureData(const gl::Context *context, const CallCapture &call);
703 void captureCompressedTextureData(const gl::Context *context, const CallCapture &call);
704
705 void reset();
706 void maybeOverrideEntryPoint(const gl::Context *context,
707 CallCapture &call,
708 std::vector<CallCapture> &newCalls);
709 void maybeCapturePreCallUpdates(const gl::Context *context,
710 CallCapture &call,
711 std::vector<CallCapture> *shareGroupSetupCalls,
712 ResourceIDToSetupCallsMap *resourceIDToSetupCalls);
713 template <typename ParamValueType>
714 void maybeGenResourceOnBind(CallCapture &call);
715 void maybeCapturePostCallUpdates(const gl::Context *context);
716 void maybeCaptureDrawArraysClientData(const gl::Context *context,
717 CallCapture &call,
718 size_t instanceCount);
719 void maybeCaptureDrawElementsClientData(const gl::Context *context,
720 CallCapture &call,
721 size_t instanceCount);
722 void maybeCaptureCoherentBuffers(const gl::Context *context);
723 void updateCopyImageSubData(CallCapture &call);
724 void overrideProgramBinary(const gl::Context *context,
725 CallCapture &call,
726 std::vector<CallCapture> &outCalls);
727 void updateResourceCountsFromParamCapture(const ParamCapture ¶m, ResourceIDType idType);
728 void updateResourceCountsFromCallCapture(const CallCapture &call);
729
730 void runMidExecutionCapture(const gl::Context *context);
731
732 void scanSetupCalls(const gl::Context *context, std::vector<CallCapture> &setupCalls);
733
734 static void ReplayCall(gl::Context *context,
735 ReplayContext *replayContext,
736 const CallCapture &call);
737
738 std::vector<CallCapture> mFrameCalls;
739 gl::ContextID mLastContextId;
740
741 // We save one large buffer of binary data for the whole CPP replay.
742 // This simplifies a lot of file management.
743 std::vector<uint8_t> mBinaryData;
744
745 bool mEnabled;
746 bool mSerializeStateEnabled;
747 std::string mOutDirectory;
748 std::string mCaptureLabel;
749 bool mCompression;
750 gl::AttribArray<int> mClientVertexArrayMap;
751 uint32_t mFrameIndex;
752 uint32_t mCaptureStartFrame;
753 uint32_t mCaptureEndFrame;
754 bool mIsFirstFrame = true;
755 bool mWroteIndexFile = false;
756 SurfaceParamsMap mDrawSurfaceParams;
757 gl::AttribArray<size_t> mClientArraySizes;
758 size_t mReadBufferSize;
759 HasResourceTypeMap mHasResourceType;
760 ResourceIDToSetupCallsMap mResourceIDToSetupCalls;
761 BufferDataMap mBufferDataMap;
762 bool mValidateSerializedState = false;
763 std::string mValidationExpression;
764 bool mTrimEnabled = true;
765 PackedEnumMap<ResourceIDType, uint32_t> mMaxAccessedResourceIDs;
766 CoherentBufferTracker mCoherentBufferTracker;
767
768 ResourceTracker mResourceTracker;
769 ReplayWriter mReplayWriter;
770
771 // If you don't know which frame you want to start capturing at, use the capture trigger.
772 // Initialize it to the number of frames you want to capture, and then clear the value to 0 when
773 // you reach the content you want to capture. Currently only available on Android.
774 uint32_t mCaptureTrigger;
775
776 bool mCaptureActive;
777 std::vector<uint32_t> mActiveFrameIndices;
778
779 bool mMidExecutionCaptureActive;
780
781 // Cache most recently compiled and linked sources.
782 ShaderSourceMap mCachedShaderSource;
783 ProgramSourceMap mCachedProgramSources;
784
785 gl::ContextID mWindowSurfaceContextID;
786
787 std::vector<CallCapture> mShareGroupSetupCalls;
788 };
789
790 template <typename CaptureFuncT, typename... ArgsT>
CaptureCallToFrameCapture(CaptureFuncT captureFunc,bool isCallValid,gl::Context * context,ArgsT...captureParams)791 void CaptureCallToFrameCapture(CaptureFuncT captureFunc,
792 bool isCallValid,
793 gl::Context *context,
794 ArgsT... captureParams)
795 {
796 FrameCaptureShared *frameCaptureShared = context->getShareGroup()->getFrameCaptureShared();
797 if (!frameCaptureShared->isCapturing())
798 {
799 return;
800 }
801
802 CallCapture call = captureFunc(context->getState(), isCallValid, captureParams...);
803
804 frameCaptureShared->captureCall(context, std::move(call), isCallValid);
805 }
806
807 template <typename T>
addValueParam(const char * paramName,ParamType paramType,T paramValue)808 void ParamBuffer::addValueParam(const char *paramName, ParamType paramType, T paramValue)
809 {
810 ParamCapture capture(paramName, paramType);
811 InitParamValue(paramType, paramValue, &capture.value);
812 mParamCaptures.emplace_back(std::move(capture));
813 }
814
815 template <typename T>
setValueParamAtIndex(const char * paramName,ParamType paramType,T paramValue,int index)816 void ParamBuffer::setValueParamAtIndex(const char *paramName,
817 ParamType paramType,
818 T paramValue,
819 int index)
820 {
821 ASSERT(mParamCaptures.size() > static_cast<size_t>(index));
822
823 ParamCapture capture(paramName, paramType);
824 InitParamValue(paramType, paramValue, &capture.value);
825 mParamCaptures[index] = std::move(capture);
826 }
827
828 template <typename T>
addEnumParam(const char * paramName,gl::GLenumGroup enumGroup,ParamType paramType,T paramValue)829 void ParamBuffer::addEnumParam(const char *paramName,
830 gl::GLenumGroup enumGroup,
831 ParamType paramType,
832 T paramValue)
833 {
834 ParamCapture capture(paramName, paramType);
835 InitParamValue(paramType, paramValue, &capture.value);
836 capture.enumGroup = enumGroup;
837 mParamCaptures.emplace_back(std::move(capture));
838 }
839
840 // Pointer capture helpers.
841 void CaptureMemory(const void *source, size_t size, ParamCapture *paramCapture);
842 void CaptureString(const GLchar *str, ParamCapture *paramCapture);
843 void CaptureStringLimit(const GLchar *str, uint32_t limit, ParamCapture *paramCapture);
844 void CaptureVertexPointerGLES1(const gl::State &glState,
845 gl::ClientVertexArrayType type,
846 const void *pointer,
847 ParamCapture *paramCapture);
848
849 gl::Program *GetProgramForCapture(const gl::State &glState, gl::ShaderProgramID handle);
850
851 // For GetIntegerv, GetFloatv, etc.
852 void CaptureGetParameter(const gl::State &glState,
853 GLenum pname,
854 size_t typeSize,
855 ParamCapture *paramCapture);
856
857 void CaptureGetActiveUniformBlockivParameters(const gl::State &glState,
858 gl::ShaderProgramID handle,
859 gl::UniformBlockIndex uniformBlockIndex,
860 GLenum pname,
861 ParamCapture *paramCapture);
862
863 template <typename T>
CaptureClearBufferValue(GLenum buffer,const T * value,ParamCapture * paramCapture)864 void CaptureClearBufferValue(GLenum buffer, const T *value, ParamCapture *paramCapture)
865 {
866 // Per the spec, color buffers have a vec4, the rest a single value
867 uint32_t valueSize = (buffer == GL_COLOR) ? 4 : 1;
868 CaptureMemory(value, valueSize * sizeof(T), paramCapture);
869 }
870
871 void CaptureGenHandlesImpl(GLsizei n, GLuint *handles, ParamCapture *paramCapture);
872
873 template <typename T>
CaptureGenHandles(GLsizei n,T * handles,ParamCapture * paramCapture)874 void CaptureGenHandles(GLsizei n, T *handles, ParamCapture *paramCapture)
875 {
876 paramCapture->dataNElements = n;
877 CaptureGenHandlesImpl(n, reinterpret_cast<GLuint *>(handles), paramCapture);
878 }
879
880 template <typename T>
CaptureArray(T * elements,GLsizei n,ParamCapture * paramCapture)881 void CaptureArray(T *elements, GLsizei n, ParamCapture *paramCapture)
882 {
883 paramCapture->dataNElements = n;
884 CaptureMemory(elements, n * sizeof(T), paramCapture);
885 }
886
887 void CaptureShaderStrings(GLsizei count,
888 const GLchar *const *strings,
889 const GLint *length,
890 ParamCapture *paramCapture);
891
892 template <ParamType ParamT, typename T>
893 void WriteParamValueReplay(std::ostream &os, const CallCapture &call, T value);
894
895 template <>
896 void WriteParamValueReplay<ParamType::TGLboolean>(std::ostream &os,
897 const CallCapture &call,
898 GLboolean value);
899
900 template <>
901 void WriteParamValueReplay<ParamType::TGLbooleanPointer>(std::ostream &os,
902 const CallCapture &call,
903 GLboolean *value);
904
905 template <>
906 void WriteParamValueReplay<ParamType::TvoidConstPointer>(std::ostream &os,
907 const CallCapture &call,
908 const void *value);
909
910 template <>
911 void WriteParamValueReplay<ParamType::TvoidPointer>(std::ostream &os,
912 const CallCapture &call,
913 void *value);
914
915 template <>
916 void WriteParamValueReplay<ParamType::TGLfloatConstPointer>(std::ostream &os,
917 const CallCapture &call,
918 const GLfloat *value);
919
920 template <>
921 void WriteParamValueReplay<ParamType::TGLintConstPointer>(std::ostream &os,
922 const CallCapture &call,
923 const GLint *value);
924
925 template <>
926 void WriteParamValueReplay<ParamType::TGLsizeiPointer>(std::ostream &os,
927 const CallCapture &call,
928 GLsizei *value);
929
930 template <>
931 void WriteParamValueReplay<ParamType::TGLuintConstPointer>(std::ostream &os,
932 const CallCapture &call,
933 const GLuint *value);
934
935 template <>
936 void WriteParamValueReplay<ParamType::TGLDEBUGPROCKHR>(std::ostream &os,
937 const CallCapture &call,
938 GLDEBUGPROCKHR value);
939
940 template <>
941 void WriteParamValueReplay<ParamType::TGLDEBUGPROC>(std::ostream &os,
942 const CallCapture &call,
943 GLDEBUGPROC value);
944
945 template <>
946 void WriteParamValueReplay<ParamType::TBufferID>(std::ostream &os,
947 const CallCapture &call,
948 gl::BufferID value);
949
950 template <>
951 void WriteParamValueReplay<ParamType::TFenceNVID>(std::ostream &os,
952 const CallCapture &call,
953 gl::FenceNVID value);
954
955 template <>
956 void WriteParamValueReplay<ParamType::TFramebufferID>(std::ostream &os,
957 const CallCapture &call,
958 gl::FramebufferID value);
959
960 template <>
961 void WriteParamValueReplay<ParamType::TMemoryObjectID>(std::ostream &os,
962 const CallCapture &call,
963 gl::MemoryObjectID value);
964
965 template <>
966 void WriteParamValueReplay<ParamType::TProgramPipelineID>(std::ostream &os,
967 const CallCapture &call,
968 gl::ProgramPipelineID value);
969
970 template <>
971 void WriteParamValueReplay<ParamType::TQueryID>(std::ostream &os,
972 const CallCapture &call,
973 gl::QueryID value);
974
975 template <>
976 void WriteParamValueReplay<ParamType::TRenderbufferID>(std::ostream &os,
977 const CallCapture &call,
978 gl::RenderbufferID value);
979
980 template <>
981 void WriteParamValueReplay<ParamType::TSamplerID>(std::ostream &os,
982 const CallCapture &call,
983 gl::SamplerID value);
984
985 template <>
986 void WriteParamValueReplay<ParamType::TSemaphoreID>(std::ostream &os,
987 const CallCapture &call,
988 gl::SemaphoreID value);
989
990 template <>
991 void WriteParamValueReplay<ParamType::TShaderProgramID>(std::ostream &os,
992 const CallCapture &call,
993 gl::ShaderProgramID value);
994
995 template <>
996 void WriteParamValueReplay<ParamType::TTextureID>(std::ostream &os,
997 const CallCapture &call,
998 gl::TextureID value);
999
1000 template <>
1001 void WriteParamValueReplay<ParamType::TTransformFeedbackID>(std::ostream &os,
1002 const CallCapture &call,
1003 gl::TransformFeedbackID value);
1004
1005 template <>
1006 void WriteParamValueReplay<ParamType::TVertexArrayID>(std::ostream &os,
1007 const CallCapture &call,
1008 gl::VertexArrayID value);
1009
1010 template <>
1011 void WriteParamValueReplay<ParamType::TUniformLocation>(std::ostream &os,
1012 const CallCapture &call,
1013 gl::UniformLocation value);
1014
1015 template <>
1016 void WriteParamValueReplay<ParamType::TUniformBlockIndex>(std::ostream &os,
1017 const CallCapture &call,
1018 gl::UniformBlockIndex value);
1019
1020 template <>
1021 void WriteParamValueReplay<ParamType::TGLsync>(std::ostream &os,
1022 const CallCapture &call,
1023 GLsync value);
1024
1025 template <>
1026 void WriteParamValueReplay<ParamType::TGLeglImageOES>(std::ostream &os,
1027 const CallCapture &call,
1028 GLeglImageOES value);
1029
1030 template <>
1031 void WriteParamValueReplay<ParamType::TGLubyte>(std::ostream &os,
1032 const CallCapture &call,
1033 GLubyte value);
1034
1035 template <>
1036 void WriteParamValueReplay<ParamType::TEGLContext>(std::ostream &os,
1037 const CallCapture &call,
1038 EGLContext value);
1039
1040 template <>
1041 void WriteParamValueReplay<ParamType::TEGLDisplay>(std::ostream &os,
1042 const CallCapture &call,
1043 EGLContext value);
1044
1045 template <>
1046 void WriteParamValueReplay<ParamType::TEGLSurface>(std::ostream &os,
1047 const CallCapture &call,
1048 EGLContext value);
1049
1050 template <>
1051 void WriteParamValueReplay<ParamType::TEGLDEBUGPROCKHR>(std::ostream &os,
1052 const CallCapture &call,
1053 EGLDEBUGPROCKHR value);
1054
1055 template <>
1056 void WriteParamValueReplay<ParamType::TEGLGetBlobFuncANDROID>(std::ostream &os,
1057 const CallCapture &call,
1058 EGLGetBlobFuncANDROID value);
1059
1060 template <>
1061 void WriteParamValueReplay<ParamType::TEGLSetBlobFuncANDROID>(std::ostream &os,
1062 const CallCapture &call,
1063 EGLSetBlobFuncANDROID value);
1064
1065 // General fallback for any unspecific type.
1066 template <ParamType ParamT, typename T>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,T value)1067 void WriteParamValueReplay(std::ostream &os, const CallCapture &call, T value)
1068 {
1069 os << value;
1070 }
1071 } // namespace angle
1072
1073 template <typename T>
CaptureTextureAndSamplerParameter_params(GLenum pname,const T * param,angle::ParamCapture * paramCapture)1074 void CaptureTextureAndSamplerParameter_params(GLenum pname,
1075 const T *param,
1076 angle::ParamCapture *paramCapture)
1077 {
1078 if (pname == GL_TEXTURE_BORDER_COLOR || pname == GL_TEXTURE_CROP_RECT_OES)
1079 {
1080 CaptureMemory(param, sizeof(T) * 4, paramCapture);
1081 }
1082 else
1083 {
1084 CaptureMemory(param, sizeof(T), paramCapture);
1085 }
1086 }
1087
1088 #endif // LIBANGLE_FRAME_CAPTURE_H_
1089