tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 &&param);
     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 &&paramsIn);
    111    CallCapture(const std::string &customFunctionNameIn, ParamBuffer &&paramsIn);
    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 &param)
    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 &param)
    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 &param)
    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 &paramName);
    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 &paramName);
    241 
    242    std::string getInlineStringSetVariableName(EntryPoint entryPoint,
    243                                               const std::string &paramName,
    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 &paramName, 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 &param, 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_