Edit

kc3-lang/angle/src/libANGLE/FrameCapture.h

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2019-10-31 14:33:27
    Hash : 6c7208f9
    Message : Capture/Replay: Implement mid-execution replay. Mid-execution replay starts the replay from a specific start frame instead of frame 0. Integration tests will then run between the start and end frames. This lets us make much smaller reproduction cases from large benchmarks or applications. We implement mid-execution replay via a cpp "Setup" function. The replay test will run the setup function before the starting frame. Test execution proceeds normally after setup. Currently we do not implement mid-execution capture. We run capture on all frames. Including frames before the start frame. We do this to intercept compiled shaders and programs for easier caching. This could be changed in the future to also start capture mid-execution. Mid- execution capture might require using ProgramBinary calls to capture shader and program data. Many captures are unimplemented. Several comments indicate missing functionality. There's a lot we can add as we explore replaying more complex applications and higher GL versions. We will also need some kind of state reset functionality so we can run the replay in a loop. Bug: angleproject:3611 Change-Id: I51841fc1a64e3622c34e49c85ed8919a9a7c0b20 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1689329 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: Cody Northrop <cnorthrop@google.com>

  • src/libANGLE/FrameCapture.h
  • // 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 inteface.
    //
    
    #ifndef LIBANGLE_FRAME_CAPTURE_H_
    #define LIBANGLE_FRAME_CAPTURE_H_
    
    #include "common/PackedEnums.h"
    #include "libANGLE/Context.h"
    #include "libANGLE/angletypes.h"
    #include "libANGLE/entry_points_utils.h"
    #include "libANGLE/frame_capture_utils_autogen.h"
    
    namespace gl
    {
    enum class GLenumGroup;
    }
    
    namespace angle
    {
    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::GLenumGroup enumGroup;  // only used for param type GLenum, GLboolean and GLbitfield
        std::vector<std::vector<uint8_t>> data;
        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 addEnumParam(const char *paramName,
                          gl::GLenumGroup 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;
        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; }
    
      private:
        std::vector<ParamCapture> mParamCaptures;
        ParamCapture mReturnValueCapture;
        int mClientArrayDataParam = -1;
        size_t mReadBufferSize    = 0;
    };
    
    struct CallCapture
    {
        CallCapture(gl::EntryPoint entryPointIn, ParamBuffer &&paramsIn);
        CallCapture(const std::string &customFunctionNameIn, ParamBuffer &&paramsIn);
        ~CallCapture();
    
        CallCapture(CallCapture &&other);
        CallCapture &operator=(CallCapture &&other);
    
        const char *name() const;
    
        gl::EntryPoint entryPoint;
        std::string customFunctionName;
        ParamBuffer params;
    };
    
    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(gl::EntryPoint entryPoint, const std::string &paramName);
    
      private:
        // <CallName, ParamName>
        using Counter = std::pair<gl::EntryPoint, std::string>;
        std::map<Counter, int> mData;
    };
    
    // Used by the CPP replay to filter out unnecessary code.
    using HasResourceTypeMap = angle::PackedEnumBitSet<ResourceIDType>;
    
    // 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>;
    
    class FrameCapture final : angle::NonCopyable
    {
      public:
        FrameCapture();
        ~FrameCapture();
    
        void captureCall(const gl::Context *context, CallCapture &&call);
        void onEndFrame(const gl::Context *context);
        bool enabled() const;
        void replay(gl::Context *context);
    
      private:
        void captureClientArraySnapshot(const gl::Context *context,
                                        size_t vertexCount,
                                        size_t instanceCount);
    
        void reset();
        void maybeCaptureClientData(const gl::Context *context, const CallCapture &call);
    
        static void ReplayCall(gl::Context *context,
                               ReplayContext *replayContext,
                               const CallCapture &call);
    
        std::vector<CallCapture> mSetupCalls;
        std::vector<CallCapture> mFrameCalls;
        std::vector<CallCapture> mTearDownCalls;
    
        bool mEnabled;
        std::string mOutDirectory;
        gl::AttribArray<int> mClientVertexArrayMap;
        uint32_t mFrameIndex;
        uint32_t mFrameStart;
        uint32_t mFrameEnd;
        gl::AttribArray<size_t> mClientArraySizes;
        size_t mReadBufferSize;
        HasResourceTypeMap mHasResourceType;
    
        // Cache most recently compiled and linked sources.
        ShaderSourceMap mCachedShaderSources;
        ProgramSourceMap mCachedProgramSources;
    };
    
    template <typename CaptureFuncT, typename... ArgsT>
    void CaptureCallToFrameCapture(CaptureFuncT captureFunc,
                                   bool isCallValid,
                                   gl::Context *context,
                                   ArgsT... captureParams)
    {
        FrameCapture *frameCapture = context->getFrameCapture();
        if (!frameCapture->enabled())
            return;
    
        CallCapture call = captureFunc(context, isCallValid, captureParams...);
        frameCapture->captureCall(context, std::move(call));
    }
    
    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::addEnumParam(const char *paramName,
                                   gl::GLenumGroup enumGroup,
                                   ParamType paramType,
                                   T paramValue)
    {
        ParamCapture capture(paramName, paramType);
        InitParamValue(paramType, paramValue, &capture.value);
        capture.enumGroup = enumGroup;
        mParamCaptures.emplace_back(std::move(capture));
    }
    
    std::ostream &operator<<(std::ostream &os, const ParamCapture &capture);
    
    // Pointer capture helpers.
    void CaptureMemory(const void *source, size_t size, ParamCapture *paramCapture);
    void CaptureString(const GLchar *str, ParamCapture *paramCapture);
    
    // For GetIntegerv, GetFloatv, etc.
    void CaptureGetParameter(const gl::Context *context,
                             GLenum pname,
                             size_t typeSize,
                             ParamCapture *paramCapture);
    
    void CaptureGenHandlesImpl(GLsizei n, GLuint *handles, ParamCapture *paramCapture);
    
    template <typename T>
    void CaptureGenHandles(GLsizei n, T *handles, ParamCapture *paramCapture)
    {
        CaptureGenHandlesImpl(n, reinterpret_cast<GLuint *>(handles), paramCapture);
    }
    
    template <ParamType ParamT, typename T>
    void WriteParamValueToStream(std::ostream &os, T value);
    
    template <>
    void WriteParamValueToStream<ParamType::TGLboolean>(std::ostream &os, GLboolean value);
    
    template <>
    void WriteParamValueToStream<ParamType::TvoidConstPointer>(std::ostream &os, const void *value);
    
    template <>
    void WriteParamValueToStream<ParamType::TGLDEBUGPROCKHR>(std::ostream &os, GLDEBUGPROCKHR value);
    
    template <>
    void WriteParamValueToStream<ParamType::TGLDEBUGPROC>(std::ostream &os, GLDEBUGPROC value);
    
    template <>
    void WriteParamValueToStream<ParamType::TBufferID>(std::ostream &os, gl::BufferID value);
    
    template <>
    void WriteParamValueToStream<ParamType::TFenceNVID>(std::ostream &os, gl::FenceNVID value);
    
    template <>
    void WriteParamValueToStream<ParamType::TFramebufferID>(std::ostream &os, gl::FramebufferID value);
    
    template <>
    void WriteParamValueToStream<ParamType::TMemoryObjectID>(std::ostream &os,
                                                             gl::MemoryObjectID value);
    
    template <>
    void WriteParamValueToStream<ParamType::TPathID>(std::ostream &os, gl::PathID value);
    
    template <>
    void WriteParamValueToStream<ParamType::TProgramPipelineID>(std::ostream &os,
                                                                gl::ProgramPipelineID value);
    
    template <>
    void WriteParamValueToStream<ParamType::TQueryID>(std::ostream &os, gl::QueryID value);
    
    template <>
    void WriteParamValueToStream<ParamType::TRenderbufferID>(std::ostream &os,
                                                             gl::RenderbufferID value);
    
    template <>
    void WriteParamValueToStream<ParamType::TSamplerID>(std::ostream &os, gl::SamplerID value);
    
    template <>
    void WriteParamValueToStream<ParamType::TSemaphoreID>(std::ostream &os, gl::SemaphoreID value);
    
    template <>
    void WriteParamValueToStream<ParamType::TShaderProgramID>(std::ostream &os,
                                                              gl::ShaderProgramID value);
    
    template <>
    void WriteParamValueToStream<ParamType::TTextureID>(std::ostream &os, gl::TextureID value);
    
    template <>
    void WriteParamValueToStream<ParamType::TTransformFeedbackID>(std::ostream &os,
                                                                  gl::TransformFeedbackID value);
    
    template <>
    void WriteParamValueToStream<ParamType::TVertexArrayID>(std::ostream &os, gl::VertexArrayID value);
    
    // General fallback for any unspecific type.
    template <ParamType ParamT, typename T>
    void WriteParamValueToStream(std::ostream &os, T value)
    {
        os << value;
    }
    }  // namespace angle
    
    #endif  // LIBANGLE_FRAME_CAPTURE_H_