summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/libANGLE/capture/FrameCapture.h
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/checkout/src/libANGLE/capture/FrameCapture.h')
-rw-r--r--gfx/angle/checkout/src/libANGLE/capture/FrameCapture.h1208
1 files changed, 1208 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/libANGLE/capture/FrameCapture.h b/gfx/angle/checkout/src/libANGLE/capture/FrameCapture.h
new file mode 100644
index 0000000000..a9b0348b6a
--- /dev/null
+++ b/gfx/angle/checkout/src/libANGLE/capture/FrameCapture.h
@@ -0,0 +1,1208 @@
+//
+// Copyright 2019 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// FrameCapture.h:
+// ANGLE Frame capture interface.
+//
+
+#ifndef LIBANGLE_FRAME_CAPTURE_H_
+#define LIBANGLE_FRAME_CAPTURE_H_
+
+#include "common/PackedEnums.h"
+#include "common/system_utils.h"
+#include "libANGLE/Context.h"
+#include "libANGLE/angletypes.h"
+#include "libANGLE/capture/frame_capture_utils_autogen.h"
+#include "libANGLE/entry_points_utils.h"
+
+namespace gl
+{
+enum class BigGLEnum;
+enum class GLESEnum;
+} // namespace gl
+
+namespace angle
+{
+
+using ParamData = std::vector<std::vector<uint8_t>>;
+struct ParamCapture : angle::NonCopyable
+{
+ ParamCapture();
+ ParamCapture(const char *nameIn, ParamType typeIn);
+ ~ParamCapture();
+
+ ParamCapture(ParamCapture &&other);
+ ParamCapture &operator=(ParamCapture &&other);
+
+ std::string name;
+ ParamType type;
+ ParamValue value;
+ gl::GLESEnum enumGroup; // only used for param type GLenum, GLboolean and GLbitfield
+ gl::BigGLEnum bigGLEnum; // only used for param type GLenum, GLboolean and GLbitfield
+ ParamData data;
+ int dataNElements = 0;
+ int arrayClientPointerIndex = -1;
+ size_t readBufferSizeBytes = 0;
+};
+
+class ParamBuffer final : angle::NonCopyable
+{
+ public:
+ ParamBuffer();
+ ~ParamBuffer();
+
+ ParamBuffer(ParamBuffer &&other);
+ ParamBuffer &operator=(ParamBuffer &&other);
+
+ template <typename T>
+ void addValueParam(const char *paramName, ParamType paramType, T paramValue);
+ template <typename T>
+ void setValueParamAtIndex(const char *paramName, ParamType paramType, T paramValue, int index);
+ template <typename T>
+ void addEnumParam(const char *paramName,
+ gl::GLESEnum enumGroup,
+ ParamType paramType,
+ T paramValue);
+ template <typename T>
+ void addEnumParam(const char *paramName,
+ gl::BigGLEnum enumGroup,
+ ParamType paramType,
+ T paramValue);
+
+ ParamCapture &getParam(const char *paramName, ParamType paramType, int index);
+ const ParamCapture &getParam(const char *paramName, ParamType paramType, int index) const;
+ ParamCapture &getParamFlexName(const char *paramName1,
+ const char *paramName2,
+ ParamType paramType,
+ int index);
+ const ParamCapture &getParamFlexName(const char *paramName1,
+ const char *paramName2,
+ ParamType paramType,
+ int index) const;
+ const ParamCapture &getReturnValue() const { return mReturnValueCapture; }
+
+ void addParam(ParamCapture &&param);
+ void addReturnValue(ParamCapture &&returnValue);
+ bool hasClientArrayData() const { return mClientArrayDataParam != -1; }
+ ParamCapture &getClientArrayPointerParameter();
+ size_t getReadBufferSize() const { return mReadBufferSize; }
+
+ const std::vector<ParamCapture> &getParamCaptures() const { return mParamCaptures; }
+
+ // These helpers allow us to track the ID of the buffer that was active when
+ // MapBufferRange was called. We'll use it during replay to track the
+ // buffer's contents, as they can be modified by the host.
+ void setMappedBufferID(gl::BufferID bufferID) { mMappedBufferID = bufferID; }
+ gl::BufferID getMappedBufferID() const { return mMappedBufferID; }
+
+ private:
+ std::vector<ParamCapture> mParamCaptures;
+ ParamCapture mReturnValueCapture;
+ int mClientArrayDataParam = -1;
+ size_t mReadBufferSize = 0;
+ gl::BufferID mMappedBufferID;
+};
+
+struct CallCapture
+{
+ CallCapture(EntryPoint entryPointIn, ParamBuffer &&paramsIn);
+ CallCapture(const std::string &customFunctionNameIn, ParamBuffer &&paramsIn);
+ ~CallCapture();
+
+ CallCapture(CallCapture &&other);
+ CallCapture &operator=(CallCapture &&other);
+
+ const char *name() const;
+
+ EntryPoint entryPoint;
+ std::string customFunctionName;
+ ParamBuffer params;
+ bool isActive = true;
+};
+
+class ReplayContext
+{
+ public:
+ ReplayContext(size_t readBufferSizebytes, const gl::AttribArray<size_t> &clientArraysSizebytes);
+ ~ReplayContext();
+
+ template <typename T>
+ T getReadBufferPointer(const ParamCapture &param)
+ {
+ ASSERT(param.readBufferSizeBytes > 0);
+ ASSERT(mReadBuffer.size() >= param.readBufferSizeBytes);
+ return reinterpret_cast<T>(mReadBuffer.data());
+ }
+ template <typename T>
+ T getAsConstPointer(const ParamCapture &param)
+ {
+ if (param.arrayClientPointerIndex != -1)
+ {
+ return reinterpret_cast<T>(mClientArraysBuffer[param.arrayClientPointerIndex].data());
+ }
+
+ if (!param.data.empty())
+ {
+ ASSERT(param.data.size() == 1);
+ return reinterpret_cast<T>(param.data[0].data());
+ }
+
+ return nullptr;
+ }
+
+ template <typename T>
+ T getAsPointerConstPointer(const ParamCapture &param)
+ {
+ static_assert(sizeof(typename std::remove_pointer<T>::type) == sizeof(uint8_t *),
+ "pointer size not match!");
+
+ ASSERT(!param.data.empty());
+ mPointersBuffer.clear();
+ mPointersBuffer.reserve(param.data.size());
+ for (const std::vector<uint8_t> &data : param.data)
+ {
+ mPointersBuffer.emplace_back(data.data());
+ }
+ return reinterpret_cast<T>(mPointersBuffer.data());
+ }
+
+ gl::AttribArray<std::vector<uint8_t>> &getClientArraysBuffer() { return mClientArraysBuffer; }
+
+ private:
+ std::vector<uint8_t> mReadBuffer;
+ std::vector<const uint8_t *> mPointersBuffer;
+ gl::AttribArray<std::vector<uint8_t>> mClientArraysBuffer;
+};
+
+// Helper to use unique IDs for each local data variable.
+class DataCounters final : angle::NonCopyable
+{
+ public:
+ DataCounters();
+ ~DataCounters();
+
+ int getAndIncrement(EntryPoint entryPoint, const std::string &paramName);
+
+ private:
+ // <CallName, ParamName>
+ using Counter = std::pair<EntryPoint, std::string>;
+ std::map<Counter, int> mData;
+};
+
+constexpr int kStringsNotFound = -1;
+class StringCounters final : angle::NonCopyable
+{
+ public:
+ StringCounters();
+ ~StringCounters();
+
+ int getStringCounter(const std::vector<std::string> &str);
+ void setStringCounter(const std::vector<std::string> &str, int &counter);
+
+ private:
+ std::map<std::vector<std::string>, int> mStringCounterMap;
+};
+
+class DataTracker final : angle::NonCopyable
+{
+ public:
+ DataTracker();
+ ~DataTracker();
+
+ DataCounters &getCounters() { return mCounters; }
+ StringCounters &getStringCounters() { return mStringCounters; }
+
+ private:
+ DataCounters mCounters;
+ StringCounters mStringCounters;
+};
+
+class ReplayWriter final : angle::NonCopyable
+{
+ public:
+ ReplayWriter();
+ ~ReplayWriter();
+
+ void setSourceFileSizeThreshold(size_t sourceFileSizeThreshold);
+ void setFilenamePattern(const std::string &pattern);
+ void setCaptureLabel(const std::string &label);
+ void setSourcePrologue(const std::string &prologue);
+ void setHeaderPrologue(const std::string &prologue);
+
+ void addPublicFunction(const std::string &functionProto,
+ const std::stringstream &headerStream,
+ const std::stringstream &bodyStream);
+ void addPrivateFunction(const std::string &functionProto,
+ const std::stringstream &headerStream,
+ const std::stringstream &bodyStream);
+ std::string getInlineVariableName(EntryPoint entryPoint, const std::string &paramName);
+
+ std::string getInlineStringSetVariableName(EntryPoint entryPoint,
+ const std::string &paramName,
+ const std::vector<std::string> &strings,
+ bool *isNewEntryOut);
+
+ void saveFrame();
+ void saveFrameIfFull();
+ void saveIndexFilesAndHeader();
+ void saveSetupFile();
+
+ std::vector<std::string> getAndResetWrittenFiles();
+
+ private:
+ static std::string GetVarName(EntryPoint entryPoint, const std::string &paramName, int counter);
+
+ void saveHeader();
+ void writeReplaySource(const std::string &filename);
+ void addWrittenFile(const std::string &filename);
+ size_t getStoredReplaySourceSize() const;
+
+ size_t mSourceFileSizeThreshold;
+ size_t mFrameIndex;
+
+ DataTracker mDataTracker;
+ std::string mFilenamePattern;
+ std::string mCaptureLabel;
+ std::string mSourcePrologue;
+ std::string mHeaderPrologue;
+
+ std::vector<std::string> mReplayHeaders;
+ std::vector<std::string> mGlobalVariableDeclarations;
+
+ std::vector<std::string> mPublicFunctionPrototypes;
+ std::vector<std::string> mPublicFunctions;
+
+ std::vector<std::string> mPrivateFunctionPrototypes;
+ std::vector<std::string> mPrivateFunctions;
+
+ std::vector<std::string> mWrittenFiles;
+};
+
+using BufferCalls = std::map<GLuint, std::vector<CallCapture>>;
+
+// true means mapped, false means unmapped
+using BufferMapStatusMap = std::map<GLuint, bool>;
+
+using FenceSyncSet = std::set<GLsync>;
+using FenceSyncCalls = std::map<GLsync, std::vector<CallCapture>>;
+
+// For default uniforms, we need to track which ones are dirty, and the series of calls to reset.
+// Each program has unique default uniforms, and each uniform has one or more locations in the
+// default buffer. For reset efficiency, we track only the uniforms dirty by location, per program.
+
+// A set of all default uniforms (per program) that were modified during the run
+using DefaultUniformLocationsSet = std::set<gl::UniformLocation>;
+using DefaultUniformLocationsPerProgramMap =
+ std::map<gl::ShaderProgramID, DefaultUniformLocationsSet>;
+
+// A map of programs which maps to locations and their reset calls
+using DefaultUniformCallsPerLocationMap = std::map<gl::UniformLocation, std::vector<CallCapture>>;
+using DefaultUniformCallsPerProgramMap =
+ std::map<gl::ShaderProgramID, DefaultUniformCallsPerLocationMap>;
+
+using DefaultUniformBaseLocationMap =
+ std::map<std::pair<gl::ShaderProgramID, gl::UniformLocation>, gl::UniformLocation>;
+
+using ResourceSet = std::set<GLuint>;
+using ResourceCalls = std::map<GLuint, std::vector<CallCapture>>;
+
+class TrackedResource final : angle::NonCopyable
+{
+ public:
+ TrackedResource();
+ ~TrackedResource();
+
+ const ResourceSet &getStartingResources() const { return mStartingResources; }
+ ResourceSet &getStartingResources() { return mStartingResources; }
+ const ResourceSet &getNewResources() const { return mNewResources; }
+ ResourceSet &getNewResources() { return mNewResources; }
+ const ResourceSet &getResourcesToRegen() const { return mResourcesToRegen; }
+ ResourceSet &getResourcesToRegen() { return mResourcesToRegen; }
+ const ResourceSet &getResourcesToRestore() const { return mResourcesToRestore; }
+ ResourceSet &getResourcesToRestore() { return mResourcesToRestore; }
+
+ void setGennedResource(GLuint id);
+ void setDeletedResource(GLuint id);
+ void setModifiedResource(GLuint id);
+ bool resourceIsGenerated(GLuint id);
+
+ ResourceCalls &getResourceRegenCalls() { return mResourceRegenCalls; }
+ ResourceCalls &getResourceRestoreCalls() { return mResourceRestoreCalls; }
+
+ private:
+ // Resource regen calls will gen a resource
+ ResourceCalls mResourceRegenCalls;
+ // Resource restore calls will restore the contents of a resource
+ ResourceCalls mResourceRestoreCalls;
+
+ // Resources created during startup
+ ResourceSet mStartingResources;
+
+ // Resources created during the run that need to be deleted
+ ResourceSet mNewResources;
+ // Resources deleted during the run that need to be recreated
+ ResourceSet mResourcesToRegen;
+ // Resources modified during the run that need to be restored
+ ResourceSet mResourcesToRestore;
+};
+
+using TrackedResourceArray =
+ std::array<TrackedResource, static_cast<uint32_t>(ResourceIDType::EnumCount)>;
+
+// Helper to track resource changes during the capture
+class ResourceTracker final : angle::NonCopyable
+{
+ public:
+ ResourceTracker();
+ ~ResourceTracker();
+
+ BufferCalls &getBufferMapCalls() { return mBufferMapCalls; }
+ BufferCalls &getBufferUnmapCalls() { return mBufferUnmapCalls; }
+
+ std::vector<CallCapture> &getBufferBindingCalls() { return mBufferBindingCalls; }
+
+ void setBufferMapped(gl::ContextID contextID, GLuint id);
+ void setBufferUnmapped(gl::ContextID contextID, GLuint id);
+
+ bool getStartingBuffersMappedCurrent(GLuint id) const;
+ bool getStartingBuffersMappedInitial(GLuint id) const;
+
+ void setStartingBufferMapped(GLuint id, bool mapped)
+ {
+ // Track the current state (which will change throughout the trace)
+ mStartingBuffersMappedCurrent[id] = mapped;
+
+ // And the initial state, to compare during frame loop reset
+ mStartingBuffersMappedInitial[id] = mapped;
+ }
+
+ void onShaderProgramAccess(gl::ShaderProgramID shaderProgramID);
+ uint32_t getMaxShaderPrograms() const { return mMaxShaderPrograms; }
+
+ FenceSyncSet &getStartingFenceSyncs() { return mStartingFenceSyncs; }
+ FenceSyncCalls &getFenceSyncRegenCalls() { return mFenceSyncRegenCalls; }
+ FenceSyncSet &getFenceSyncsToRegen() { return mFenceSyncsToRegen; }
+ void setDeletedFenceSync(GLsync sync);
+
+ DefaultUniformLocationsPerProgramMap &getDefaultUniformsToReset()
+ {
+ return mDefaultUniformsToReset;
+ }
+ DefaultUniformCallsPerLocationMap &getDefaultUniformResetCalls(gl::ShaderProgramID id)
+ {
+ return mDefaultUniformResetCalls[id];
+ }
+ void setModifiedDefaultUniform(gl::ShaderProgramID programID, gl::UniformLocation location);
+ void setDefaultUniformBaseLocation(gl::ShaderProgramID programID,
+ gl::UniformLocation location,
+ gl::UniformLocation baseLocation);
+ gl::UniformLocation getDefaultUniformBaseLocation(gl::ShaderProgramID programID,
+ gl::UniformLocation location)
+ {
+ ASSERT(mDefaultUniformBaseLocations.find({programID, location}) !=
+ mDefaultUniformBaseLocations.end());
+ return mDefaultUniformBaseLocations[{programID, location}];
+ }
+
+ TrackedResource &getTrackedResource(gl::ContextID contextID, ResourceIDType type);
+
+ void getContextIDs(std::set<gl::ContextID> &idsOut);
+
+ std::map<void *, egl::AttributeMap> &getImageToAttribTable() { return mMatchImageToAttribs; }
+
+ std::map<GLuint, void *> &getTextureIDToImageTable() { return mMatchTextureIDToImage; }
+
+ private:
+ // Buffer map calls will map a buffer with correct offset, length, and access flags
+ BufferCalls mBufferMapCalls;
+ // Buffer unmap calls will bind and unmap a given buffer
+ BufferCalls mBufferUnmapCalls;
+
+ // Buffer binding calls to restore bindings recorded during MEC
+ std::vector<CallCapture> mBufferBindingCalls;
+
+ // Whether a given buffer was mapped at the start of the trace
+ BufferMapStatusMap mStartingBuffersMappedInitial;
+ // The status of buffer mapping throughout the trace, modified with each Map/Unmap call
+ BufferMapStatusMap mStartingBuffersMappedCurrent;
+
+ // Maximum accessed shader program ID.
+ uint32_t mMaxShaderPrograms = 0;
+
+ // Fence sync objects created during MEC setup
+ FenceSyncSet mStartingFenceSyncs;
+ // Fence sync regen calls will create a fence sync objects
+ FenceSyncCalls mFenceSyncRegenCalls;
+ // Fence syncs to regen are a list of starting fence sync objects that were deleted and need to
+ // be regen'ed.
+ FenceSyncSet mFenceSyncsToRegen;
+
+ // Default uniforms that were modified during the run
+ DefaultUniformLocationsPerProgramMap mDefaultUniformsToReset;
+ // Calls per default uniform to return to original state
+ DefaultUniformCallsPerProgramMap mDefaultUniformResetCalls;
+
+ // Base location of arrayed uniforms
+ DefaultUniformBaseLocationMap mDefaultUniformBaseLocations;
+
+ // Tracked resources per context
+ TrackedResourceArray mTrackedResourcesShared;
+ std::map<gl::ContextID, TrackedResourceArray> mTrackedResourcesPerContext;
+
+ std::map<void *, egl::AttributeMap> mMatchImageToAttribs;
+ std::map<GLuint, void *> mMatchTextureIDToImage;
+};
+
+// Used by the CPP replay to filter out unnecessary code.
+using HasResourceTypeMap = angle::PackedEnumBitSet<ResourceIDType>;
+
+// Map of ResourceType to IDs and range of setup calls
+using ResourceIDToSetupCallsMap =
+ PackedEnumMap<ResourceIDType, std::map<GLuint, gl::Range<size_t>>>;
+
+// Map of buffer ID to offset and size used when mapped
+using BufferDataMap = std::map<gl::BufferID, std::pair<GLintptr, GLsizeiptr>>;
+
+// A dictionary of sources indexed by shader type.
+using ProgramSources = gl::ShaderMap<std::string>;
+
+// Maps from IDs to sources.
+using ShaderSourceMap = std::map<gl::ShaderProgramID, std::string>;
+using ProgramSourceMap = std::map<gl::ShaderProgramID, ProgramSources>;
+
+// Map from textureID to level and data
+using TextureLevels = std::map<GLint, std::vector<uint8_t>>;
+using TextureLevelDataMap = std::map<gl::TextureID, TextureLevels>;
+
+struct SurfaceParams
+{
+ gl::Extents extents;
+ egl::ColorSpace colorSpace;
+};
+
+// Map from ContextID to SurfaceParams
+using SurfaceParamsMap = std::map<gl::ContextID, SurfaceParams>;
+
+using CallVector = std::vector<std::vector<CallCapture> *>;
+
+// A map from API entry point to calls
+using CallResetMap = std::map<angle::EntryPoint, std::vector<CallCapture>>;
+
+// StateResetHelper provides a simple way to track whether an entry point has been called during the
+// trace, along with the reset calls to get it back to starting state. This is useful for things
+// that are one dimensional, like context bindings or context state.
+class StateResetHelper final : angle::NonCopyable
+{
+ public:
+ StateResetHelper();
+ ~StateResetHelper();
+
+ const std::set<angle::EntryPoint> &getDirtyEntryPoints() const { return mDirtyEntryPoints; }
+ void setEntryPointDirty(EntryPoint entryPoint) { mDirtyEntryPoints.insert(entryPoint); }
+
+ CallResetMap &getResetCalls() { return mResetCalls; }
+ const CallResetMap &getResetCalls() const { return mResetCalls; }
+
+ void setDefaultResetCalls(const gl::Context *context, angle::EntryPoint);
+
+ private:
+ // Dirty state per entry point
+ std::set<angle::EntryPoint> mDirtyEntryPoints;
+
+ // Reset calls per API entry point
+ CallResetMap mResetCalls;
+};
+
+class FrameCapture final : angle::NonCopyable
+{
+ public:
+ FrameCapture();
+ ~FrameCapture();
+
+ std::vector<CallCapture> &getSetupCalls() { return mSetupCalls; }
+ void clearSetupCalls() { mSetupCalls.clear(); }
+
+ StateResetHelper &getStateResetHelper() { return mStateResetHelper; }
+
+ void reset();
+
+ private:
+ std::vector<CallCapture> mSetupCalls;
+
+ StateResetHelper mStateResetHelper;
+};
+
+// Page range inside a coherent buffer
+struct PageRange
+{
+ PageRange(size_t start, size_t end);
+ ~PageRange();
+
+ // Relative start page
+ size_t start;
+
+ // First page after the relative end
+ size_t end;
+};
+
+// Memory address range defined by start and size
+struct AddressRange
+{
+ AddressRange();
+ AddressRange(uintptr_t start, size_t size);
+ ~AddressRange();
+
+ uintptr_t end();
+
+ uintptr_t start;
+ size_t size;
+};
+
+// Used to handle protection of buffers that overlap in pages.
+enum class PageSharingType
+{
+ NoneShared,
+ FirstShared,
+ LastShared,
+ FirstAndLastShared
+};
+
+class CoherentBuffer
+{
+ public:
+ CoherentBuffer(uintptr_t start, size_t size, size_t pageSize);
+ ~CoherentBuffer();
+
+ // Sets the a range in the buffer clean and protects a selected range
+ void protectPageRange(const PageRange &pageRange);
+
+ // Sets a page dirty state and sets it's protection
+ void setDirty(size_t relativePage, bool dirty);
+
+ // Removes protection
+ void removeProtection(PageSharingType sharingType);
+
+ bool contains(size_t page, size_t *relativePage);
+ bool isDirty();
+
+ // Returns dirty page ranges
+ std::vector<PageRange> getDirtyPageRanges();
+
+ // Calculates address range from page range
+ AddressRange getDirtyAddressRange(const PageRange &dirtyPageRange);
+ AddressRange getRange();
+
+ private:
+ // Actual buffer start and size
+ AddressRange mRange;
+
+ // Start and size of page aligned protected area
+ AddressRange mProtectionRange;
+
+ // Start and end of protection in relative pages, calculated from mProtectionRange.
+ size_t mProtectionStartPage;
+ size_t mProtectionEndPage;
+
+ size_t mPageCount;
+ size_t mPageSize;
+
+ // Clean pages are protected
+ std::vector<bool> mDirtyPages;
+};
+
+class CoherentBufferTracker final : angle::NonCopyable
+{
+ public:
+ CoherentBufferTracker();
+ ~CoherentBufferTracker();
+
+ bool isDirty(gl::BufferID id);
+ void addBuffer(gl::BufferID id, uintptr_t start, size_t size);
+ void removeBuffer(gl::BufferID id);
+ void disable();
+ void enable();
+ void onEndFrame();
+
+ private:
+ // Detect overlapping pages when removing protection
+ PageSharingType doesBufferSharePage(gl::BufferID id);
+
+ // Returns a map to found buffers and the corresponding pages for a given address.
+ // For addresses that are in a page shared by 2 buffers, 2 results are returned.
+ HashMap<std::shared_ptr<CoherentBuffer>, size_t> getBufferPagesForAddress(uintptr_t address);
+ PageFaultHandlerRangeType handleWrite(uintptr_t address);
+ bool haveBuffer(gl::BufferID id);
+
+ public:
+ std::mutex mMutex;
+ HashMap<GLuint, std::shared_ptr<CoherentBuffer>> mBuffers;
+
+ private:
+ bool mEnabled = false;
+ std::unique_ptr<PageFaultHandler> mPageFaultHandler;
+ size_t mPageSize;
+};
+
+// Shared class for any items that need to be tracked by FrameCapture across shared contexts
+class FrameCaptureShared final : angle::NonCopyable
+{
+ public:
+ FrameCaptureShared();
+ ~FrameCaptureShared();
+
+ void captureCall(const gl::Context *context, CallCapture &&call, bool isCallValid);
+ void checkForCaptureTrigger();
+ void onEndFrame(const gl::Context *context);
+ void onDestroyContext(const gl::Context *context);
+ void onMakeCurrent(const gl::Context *context, const egl::Surface *drawSurface);
+ bool enabled() const { return mEnabled; }
+
+ bool isCapturing() const;
+ void replay(gl::Context *context);
+ uint32_t getFrameCount() const;
+
+ // Returns a frame index starting from "1" as the first frame.
+ uint32_t getReplayFrameIndex() const;
+
+ void trackBufferMapping(const gl::Context *context,
+ CallCapture *call,
+ gl::BufferID id,
+ gl::Buffer *buffer,
+ GLintptr offset,
+ GLsizeiptr length,
+ bool writable,
+ bool coherent);
+
+ void trackTextureUpdate(const gl::Context *context, const CallCapture &call);
+ void trackDefaultUniformUpdate(const gl::Context *context, const CallCapture &call);
+ void trackVertexArrayUpdate(const gl::Context *context, const CallCapture &call);
+
+ const std::string &getShaderSource(gl::ShaderProgramID id) const;
+ void setShaderSource(gl::ShaderProgramID id, std::string sources);
+
+ const ProgramSources &getProgramSources(gl::ShaderProgramID id) const;
+ void setProgramSources(gl::ShaderProgramID id, ProgramSources sources);
+
+ // Load data from a previously stored texture level
+ const std::vector<uint8_t> &retrieveCachedTextureLevel(gl::TextureID id,
+ gl::TextureTarget target,
+ GLint level);
+
+ // Create new texture level data and copy the source into it
+ void copyCachedTextureLevel(const gl::Context *context,
+ gl::TextureID srcID,
+ GLint srcLevel,
+ gl::TextureID dstID,
+ GLint dstLevel,
+ const CallCapture &call);
+
+ // Create the location that should be used to cache texture level data
+ std::vector<uint8_t> &getCachedTextureLevelData(gl::Texture *texture,
+ gl::TextureTarget target,
+ GLint level,
+ EntryPoint entryPoint);
+
+ // Capture coherent buffer storages
+ void captureCoherentBufferSnapshot(const gl::Context *context, gl::BufferID bufferID);
+
+ // Remove any cached texture levels on deletion
+ void deleteCachedTextureLevelData(gl::TextureID id);
+
+ void eraseBufferDataMapEntry(const gl::BufferID bufferId)
+ {
+ const auto &bufferDataInfo = mBufferDataMap.find(bufferId);
+ if (bufferDataInfo != mBufferDataMap.end())
+ {
+ mBufferDataMap.erase(bufferDataInfo);
+ }
+ }
+
+ bool hasBufferData(gl::BufferID bufferID)
+ {
+ const auto &bufferDataInfo = mBufferDataMap.find(bufferID);
+ if (bufferDataInfo != mBufferDataMap.end())
+ {
+ return true;
+ }
+ return false;
+ }
+
+ std::pair<GLintptr, GLsizeiptr> getBufferDataOffsetAndLength(gl::BufferID bufferID)
+ {
+ const auto &bufferDataInfo = mBufferDataMap.find(bufferID);
+ ASSERT(bufferDataInfo != mBufferDataMap.end());
+ return bufferDataInfo->second;
+ }
+
+ void setCaptureActive() { mCaptureActive = true; }
+ void setCaptureInactive() { mCaptureActive = false; }
+ bool isCaptureActive() { return mCaptureActive; }
+ bool usesMidExecutionCapture() { return mCaptureStartFrame > 1; }
+
+ gl::ContextID getWindowSurfaceContextID() const { return mWindowSurfaceContextID; }
+
+ void markResourceSetupCallsInactive(std::vector<CallCapture> *setupCalls,
+ ResourceIDType type,
+ GLuint id,
+ gl::Range<size_t> range);
+
+ void updateReadBufferSize(size_t readBufferSize)
+ {
+ mReadBufferSize = std::max(mReadBufferSize, readBufferSize);
+ }
+
+ template <typename ResourceType>
+ void handleGennedResource(const gl::Context *context, ResourceType resourceID)
+ {
+ if (isCaptureActive())
+ {
+ ResourceIDType idType = GetResourceIDTypeFromType<ResourceType>::IDType;
+ TrackedResource &tracker = mResourceTracker.getTrackedResource(context->id(), idType);
+ tracker.setGennedResource(resourceID.value);
+ }
+ }
+
+ template <typename ResourceType>
+ bool resourceIsGenerated(const gl::Context *context, ResourceType resourceID)
+ {
+ ResourceIDType idType = GetResourceIDTypeFromType<ResourceType>::IDType;
+ TrackedResource &tracker = mResourceTracker.getTrackedResource(context->id(), idType);
+ return tracker.resourceIsGenerated(resourceID.value);
+ }
+
+ template <typename ResourceType>
+ void handleDeletedResource(const gl::Context *context, ResourceType resourceID)
+ {
+ if (isCaptureActive())
+ {
+ ResourceIDType idType = GetResourceIDTypeFromType<ResourceType>::IDType;
+ TrackedResource &tracker = mResourceTracker.getTrackedResource(context->id(), idType);
+ tracker.setDeletedResource(resourceID.value);
+ }
+ }
+
+ private:
+ void writeJSON(const gl::Context *context);
+ void writeCppReplayIndexFiles(const gl::Context *context, bool writeResetContextCall);
+ void writeMainContextCppReplay(const gl::Context *context,
+ const std::vector<CallCapture> &setupCalls,
+ StateResetHelper &StateResetHelper);
+
+ void captureClientArraySnapshot(const gl::Context *context,
+ size_t vertexCount,
+ size_t instanceCount);
+ void captureMappedBufferSnapshot(const gl::Context *context, const CallCapture &call);
+
+ void copyCompressedTextureData(const gl::Context *context, const CallCapture &call);
+ void captureCompressedTextureData(const gl::Context *context, const CallCapture &call);
+
+ void reset();
+ void maybeOverrideEntryPoint(const gl::Context *context,
+ CallCapture &call,
+ std::vector<CallCapture> &newCalls);
+ void maybeCapturePreCallUpdates(const gl::Context *context,
+ CallCapture &call,
+ std::vector<CallCapture> *shareGroupSetupCalls,
+ ResourceIDToSetupCallsMap *resourceIDToSetupCalls);
+ template <typename ParamValueType>
+ void maybeGenResourceOnBind(const gl::Context *context, CallCapture &call);
+ void maybeCapturePostCallUpdates(const gl::Context *context);
+ void maybeCaptureDrawArraysClientData(const gl::Context *context,
+ CallCapture &call,
+ size_t instanceCount);
+ void maybeCaptureDrawElementsClientData(const gl::Context *context,
+ CallCapture &call,
+ size_t instanceCount);
+ void maybeCaptureCoherentBuffers(const gl::Context *context);
+ void updateCopyImageSubData(CallCapture &call);
+ void overrideProgramBinary(const gl::Context *context,
+ CallCapture &call,
+ std::vector<CallCapture> &outCalls);
+ void updateResourceCountsFromParamCapture(const ParamCapture &param, ResourceIDType idType);
+ void updateResourceCountsFromCallCapture(const CallCapture &call);
+
+ void runMidExecutionCapture(const gl::Context *context);
+
+ void scanSetupCalls(const gl::Context *context, std::vector<CallCapture> &setupCalls);
+
+ static void ReplayCall(gl::Context *context,
+ ReplayContext *replayContext,
+ const CallCapture &call);
+
+ std::vector<CallCapture> mFrameCalls;
+ gl::ContextID mLastContextId;
+
+ // We save one large buffer of binary data for the whole CPP replay.
+ // This simplifies a lot of file management.
+ std::vector<uint8_t> mBinaryData;
+
+ bool mEnabled;
+ bool mSerializeStateEnabled;
+ std::string mOutDirectory;
+ std::string mCaptureLabel;
+ bool mCompression;
+ gl::AttribArray<int> mClientVertexArrayMap;
+ uint32_t mFrameIndex;
+ uint32_t mCaptureStartFrame;
+ uint32_t mCaptureEndFrame;
+ bool mIsFirstFrame = true;
+ bool mWroteIndexFile = false;
+ SurfaceParamsMap mDrawSurfaceParams;
+ gl::AttribArray<size_t> mClientArraySizes;
+ size_t mReadBufferSize;
+ HasResourceTypeMap mHasResourceType;
+ ResourceIDToSetupCallsMap mResourceIDToSetupCalls;
+ BufferDataMap mBufferDataMap;
+ bool mValidateSerializedState = false;
+ std::string mValidationExpression;
+ bool mTrimEnabled = true;
+ PackedEnumMap<ResourceIDType, uint32_t> mMaxAccessedResourceIDs;
+ CoherentBufferTracker mCoherentBufferTracker;
+
+ ResourceTracker mResourceTracker;
+ ReplayWriter mReplayWriter;
+
+ // If you don't know which frame you want to start capturing at, use the capture trigger.
+ // Initialize it to the number of frames you want to capture, and then clear the value to 0 when
+ // you reach the content you want to capture. Currently only available on Android.
+ uint32_t mCaptureTrigger;
+
+ bool mCaptureActive;
+ std::vector<uint32_t> mActiveFrameIndices;
+
+ // Cache most recently compiled and linked sources.
+ ShaderSourceMap mCachedShaderSource;
+ ProgramSourceMap mCachedProgramSources;
+
+ gl::ContextID mWindowSurfaceContextID;
+
+ std::vector<CallCapture> mShareGroupSetupCalls;
+};
+
+template <typename CaptureFuncT, typename... ArgsT>
+void CaptureCallToFrameCapture(CaptureFuncT captureFunc,
+ bool isCallValid,
+ gl::Context *context,
+ ArgsT... captureParams)
+{
+ FrameCaptureShared *frameCaptureShared = context->getShareGroup()->getFrameCaptureShared();
+ if (!frameCaptureShared->isCapturing())
+ {
+ return;
+ }
+
+ CallCapture call = captureFunc(context->getState(), isCallValid, captureParams...);
+
+ frameCaptureShared->captureCall(context, std::move(call), isCallValid);
+}
+
+template <typename T>
+void ParamBuffer::addValueParam(const char *paramName, ParamType paramType, T paramValue)
+{
+ ParamCapture capture(paramName, paramType);
+ InitParamValue(paramType, paramValue, &capture.value);
+ mParamCaptures.emplace_back(std::move(capture));
+}
+
+template <typename T>
+void ParamBuffer::setValueParamAtIndex(const char *paramName,
+ ParamType paramType,
+ T paramValue,
+ int index)
+{
+ ASSERT(mParamCaptures.size() > static_cast<size_t>(index));
+
+ ParamCapture capture(paramName, paramType);
+ InitParamValue(paramType, paramValue, &capture.value);
+ mParamCaptures[index] = std::move(capture);
+}
+
+template <typename T>
+void ParamBuffer::addEnumParam(const char *paramName,
+ gl::GLESEnum enumGroup,
+ ParamType paramType,
+ T paramValue)
+{
+ ParamCapture capture(paramName, paramType);
+ InitParamValue(paramType, paramValue, &capture.value);
+ capture.enumGroup = enumGroup;
+ mParamCaptures.emplace_back(std::move(capture));
+}
+
+template <typename T>
+void ParamBuffer::addEnumParam(const char *paramName,
+ gl::BigGLEnum enumGroup,
+ ParamType paramType,
+ T paramValue)
+{
+ ParamCapture capture(paramName, paramType);
+ InitParamValue(paramType, paramValue, &capture.value);
+ capture.bigGLEnum = enumGroup;
+ mParamCaptures.emplace_back(std::move(capture));
+}
+
+// Pointer capture helpers.
+void CaptureMemory(const void *source, size_t size, ParamCapture *paramCapture);
+void CaptureString(const GLchar *str, ParamCapture *paramCapture);
+void CaptureStringLimit(const GLchar *str, uint32_t limit, ParamCapture *paramCapture);
+void CaptureVertexPointerGLES1(const gl::State &glState,
+ gl::ClientVertexArrayType type,
+ const void *pointer,
+ ParamCapture *paramCapture);
+
+gl::Program *GetProgramForCapture(const gl::State &glState, gl::ShaderProgramID handle);
+
+// For GetIntegerv, GetFloatv, etc.
+void CaptureGetParameter(const gl::State &glState,
+ GLenum pname,
+ size_t typeSize,
+ ParamCapture *paramCapture);
+
+void CaptureGetActiveUniformBlockivParameters(const gl::State &glState,
+ gl::ShaderProgramID handle,
+ gl::UniformBlockIndex uniformBlockIndex,
+ GLenum pname,
+ ParamCapture *paramCapture);
+
+template <typename T>
+void CaptureClearBufferValue(GLenum buffer, const T *value, ParamCapture *paramCapture)
+{
+ // Per the spec, color buffers have a vec4, the rest a single value
+ uint32_t valueSize = (buffer == GL_COLOR) ? 4 : 1;
+ CaptureMemory(value, valueSize * sizeof(T), paramCapture);
+}
+
+void CaptureGenHandlesImpl(GLsizei n, GLuint *handles, ParamCapture *paramCapture);
+
+template <typename T>
+void CaptureGenHandles(GLsizei n, T *handles, ParamCapture *paramCapture)
+{
+ paramCapture->dataNElements = n;
+ CaptureGenHandlesImpl(n, reinterpret_cast<GLuint *>(handles), paramCapture);
+}
+
+template <typename T>
+void CaptureArray(T *elements, GLsizei n, ParamCapture *paramCapture)
+{
+ paramCapture->dataNElements = n;
+ CaptureMemory(elements, n * sizeof(T), paramCapture);
+}
+
+void CaptureShaderStrings(GLsizei count,
+ const GLchar *const *strings,
+ const GLint *length,
+ ParamCapture *paramCapture);
+
+template <ParamType ParamT, typename T>
+void WriteParamValueReplay(std::ostream &os, const CallCapture &call, T value);
+
+template <>
+void WriteParamValueReplay<ParamType::TGLboolean>(std::ostream &os,
+ const CallCapture &call,
+ GLboolean value);
+
+template <>
+void WriteParamValueReplay<ParamType::TGLbooleanPointer>(std::ostream &os,
+ const CallCapture &call,
+ GLboolean *value);
+
+template <>
+void WriteParamValueReplay<ParamType::TvoidConstPointer>(std::ostream &os,
+ const CallCapture &call,
+ const void *value);
+
+template <>
+void WriteParamValueReplay<ParamType::TvoidPointer>(std::ostream &os,
+ const CallCapture &call,
+ void *value);
+
+template <>
+void WriteParamValueReplay<ParamType::TGLfloatConstPointer>(std::ostream &os,
+ const CallCapture &call,
+ const GLfloat *value);
+
+template <>
+void WriteParamValueReplay<ParamType::TGLintConstPointer>(std::ostream &os,
+ const CallCapture &call,
+ const GLint *value);
+
+template <>
+void WriteParamValueReplay<ParamType::TGLsizeiPointer>(std::ostream &os,
+ const CallCapture &call,
+ GLsizei *value);
+
+template <>
+void WriteParamValueReplay<ParamType::TGLuintConstPointer>(std::ostream &os,
+ const CallCapture &call,
+ const GLuint *value);
+
+template <>
+void WriteParamValueReplay<ParamType::TGLDEBUGPROCKHR>(std::ostream &os,
+ const CallCapture &call,
+ GLDEBUGPROCKHR value);
+
+template <>
+void WriteParamValueReplay<ParamType::TGLDEBUGPROC>(std::ostream &os,
+ const CallCapture &call,
+ GLDEBUGPROC value);
+
+template <>
+void WriteParamValueReplay<ParamType::TBufferID>(std::ostream &os,
+ const CallCapture &call,
+ gl::BufferID value);
+
+template <>
+void WriteParamValueReplay<ParamType::TFenceNVID>(std::ostream &os,
+ const CallCapture &call,
+ gl::FenceNVID value);
+
+template <>
+void WriteParamValueReplay<ParamType::TFramebufferID>(std::ostream &os,
+ const CallCapture &call,
+ gl::FramebufferID value);
+
+template <>
+void WriteParamValueReplay<ParamType::TMemoryObjectID>(std::ostream &os,
+ const CallCapture &call,
+ gl::MemoryObjectID value);
+
+template <>
+void WriteParamValueReplay<ParamType::TProgramPipelineID>(std::ostream &os,
+ const CallCapture &call,
+ gl::ProgramPipelineID value);
+
+template <>
+void WriteParamValueReplay<ParamType::TQueryID>(std::ostream &os,
+ const CallCapture &call,
+ gl::QueryID value);
+
+template <>
+void WriteParamValueReplay<ParamType::TRenderbufferID>(std::ostream &os,
+ const CallCapture &call,
+ gl::RenderbufferID value);
+
+template <>
+void WriteParamValueReplay<ParamType::TSamplerID>(std::ostream &os,
+ const CallCapture &call,
+ gl::SamplerID value);
+
+template <>
+void WriteParamValueReplay<ParamType::TSemaphoreID>(std::ostream &os,
+ const CallCapture &call,
+ gl::SemaphoreID value);
+
+template <>
+void WriteParamValueReplay<ParamType::TShaderProgramID>(std::ostream &os,
+ const CallCapture &call,
+ gl::ShaderProgramID value);
+
+template <>
+void WriteParamValueReplay<ParamType::TTextureID>(std::ostream &os,
+ const CallCapture &call,
+ gl::TextureID value);
+
+template <>
+void WriteParamValueReplay<ParamType::TTransformFeedbackID>(std::ostream &os,
+ const CallCapture &call,
+ gl::TransformFeedbackID value);
+
+template <>
+void WriteParamValueReplay<ParamType::TVertexArrayID>(std::ostream &os,
+ const CallCapture &call,
+ gl::VertexArrayID value);
+
+template <>
+void WriteParamValueReplay<ParamType::TUniformLocation>(std::ostream &os,
+ const CallCapture &call,
+ gl::UniformLocation value);
+
+template <>
+void WriteParamValueReplay<ParamType::TUniformBlockIndex>(std::ostream &os,
+ const CallCapture &call,
+ gl::UniformBlockIndex value);
+
+template <>
+void WriteParamValueReplay<ParamType::TGLsync>(std::ostream &os,
+ const CallCapture &call,
+ GLsync value);
+
+template <>
+void WriteParamValueReplay<ParamType::TGLeglImageOES>(std::ostream &os,
+ const CallCapture &call,
+ GLeglImageOES value);
+
+template <>
+void WriteParamValueReplay<ParamType::TGLubyte>(std::ostream &os,
+ const CallCapture &call,
+ GLubyte value);
+
+template <>
+void WriteParamValueReplay<ParamType::TEGLContext>(std::ostream &os,
+ const CallCapture &call,
+ EGLContext value);
+
+template <>
+void WriteParamValueReplay<ParamType::TEGLDisplay>(std::ostream &os,
+ const CallCapture &call,
+ EGLContext value);
+
+template <>
+void WriteParamValueReplay<ParamType::TEGLSurface>(std::ostream &os,
+ const CallCapture &call,
+ EGLContext value);
+
+template <>
+void WriteParamValueReplay<ParamType::TEGLDEBUGPROCKHR>(std::ostream &os,
+ const CallCapture &call,
+ EGLDEBUGPROCKHR value);
+
+template <>
+void WriteParamValueReplay<ParamType::TEGLGetBlobFuncANDROID>(std::ostream &os,
+ const CallCapture &call,
+ EGLGetBlobFuncANDROID value);
+
+template <>
+void WriteParamValueReplay<ParamType::TEGLSetBlobFuncANDROID>(std::ostream &os,
+ const CallCapture &call,
+ EGLSetBlobFuncANDROID value);
+template <>
+void WriteParamValueReplay<ParamType::TEGLClientBuffer>(std::ostream &os,
+ const CallCapture &call,
+ EGLClientBuffer value);
+
+template <>
+void WriteParamValueReplay<ParamType::TEGLConfig>(std::ostream &os,
+ const CallCapture &call,
+ EGLConfig value);
+
+template <>
+void WriteParamValueReplay<ParamType::TEGLSurface>(std::ostream &os,
+ const CallCapture &call,
+ EGLSurface value);
+
+// General fallback for any unspecific type.
+template <ParamType ParamT, typename T>
+void WriteParamValueReplay(std::ostream &os, const CallCapture &call, T value)
+{
+ os << value;
+}
+} // namespace angle
+
+template <typename T>
+void CaptureTextureAndSamplerParameter_params(GLenum pname,
+ const T *param,
+ angle::ParamCapture *paramCapture)
+{
+ if (pname == GL_TEXTURE_BORDER_COLOR || pname == GL_TEXTURE_CROP_RECT_OES)
+ {
+ CaptureMemory(param, sizeof(T) * 4, paramCapture);
+ }
+ else
+ {
+ CaptureMemory(param, sizeof(T), paramCapture);
+ }
+}
+
+#endif // LIBANGLE_FRAME_CAPTURE_H_