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