// // Copyright 2020 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. // // frame_capture_test_utils: // Helper functions for capture and replay of traces. // #ifndef UTIL_CAPTURE_FRAME_CAPTURE_TEST_UTILS_H_ #define UTIL_CAPTURE_FRAME_CAPTURE_TEST_UTILS_H_ #include #include #include #include #include #include #include "common/angleutils.h" #include "common/debug.h" #include "common/frame_capture_utils.h" #include "common/system_utils.h" #define USE_SYSTEM_ZLIB #include "compression_utils_portable.h" #define ANGLE_MACRO_STRINGIZE_AUX(a) #a #define ANGLE_MACRO_STRINGIZE(a) ANGLE_MACRO_STRINGIZE_AUX(a) #define ANGLE_MACRO_CONCAT_AUX(a, b) a##b #define ANGLE_MACRO_CONCAT(a, b) ANGLE_MACRO_CONCAT_AUX(a, b) namespace angle { inline uint8_t *DecompressBinaryData(const std::vector &compressedData) { uint32_t uncompressedSize = zlib_internal::GetGzipUncompressedSize(compressedData.data(), compressedData.size()); std::unique_ptr uncompressedData(new uint8_t[uncompressedSize]); uLong destLen = uncompressedSize; int zResult = zlib_internal::GzipUncompressHelper(uncompressedData.get(), &destLen, compressedData.data(), static_cast(compressedData.size())); if (zResult != Z_OK) { std::cerr << "Failure to decompressed binary data: " << zResult << "\n"; return nullptr; } return uncompressedData.release(); } inline void DeleteBinaryData(uint8_t *uncompressedData) { delete[] uncompressedData; } using DecompressCallback = uint8_t *(*)(const std::vector &); using DeleteCallback = void (*)(uint8_t *); using ValidateSerializedStateCallback = void (*)(const char *, const char *, uint32_t); using SetBinaryDataDecompressCallbackFunc = void (*)(DecompressCallback, DeleteCallback); using SetBinaryDataDirFunc = void (*)(const char *); using SetupReplayFunc = void (*)(); using ReplayFrameFunc = void (*)(uint32_t); using ResetReplayFunc = void (*)(); using FinishReplayFunc = void (*)(); using GetSerializedContextStateFunc = const char *(*)(uint32_t); using SetValidateSerializedStateCallbackFunc = void (*)(ValidateSerializedStateCallback); using SetTraceInfoFunc = void (*)(const std::vector &); using SetTraceGzPathFunc = void (*)(const std::string &); struct TraceInfo; class TraceLibrary : angle::NonCopyable { public: TraceLibrary(const std::string &traceName, const TraceInfo &traceInfo); bool valid() const { return (mTraceLibrary != nullptr) && (mTraceLibrary->getNative() != nullptr); } void setBinaryDataDir(const char *dataDir) { callFunc("SetBinaryDataDir", dataDir); } void setBinaryDataDecompressCallback(DecompressCallback decompressCallback, DeleteCallback deleteCallback) { callFunc("SetBinaryDataDecompressCallback", decompressCallback, deleteCallback); } void replayFrame(uint32_t frameIndex) { callFunc("ReplayFrame", frameIndex); } void setupReplay() { callFunc("SetupReplay"); } void resetReplay() { callFunc("ResetReplay"); } void finishReplay() { callFunc("FinishReplay"); } const char *getSerializedContextState(uint32_t frameIndex) { return callFunc("GetSerializedContextState", frameIndex); } void setValidateSerializedStateCallback(ValidateSerializedStateCallback callback) { return callFunc( "SetValidateSerializedStateCallback", callback); } void setTraceGzPath(const std::string &traceGzPath) { callFunc("SetTraceGzPath", traceGzPath); } private: template typename std::invoke_result::type callFunc(const char *funcName, ArgsT... args) { void *untypedFunc = mTraceLibrary->getSymbol(funcName); if (!untypedFunc) { fprintf(stderr, "Error loading function: %s\n", funcName); ASSERT(untypedFunc); } auto typedFunc = reinterpret_cast(untypedFunc); return typedFunc(args...); } std::unique_ptr mTraceLibrary; }; static constexpr size_t kTraceInfoMaxNameLen = 128; struct TraceInfo { char name[kTraceInfoMaxNameLen]; bool initialized = false; uint32_t contextClientMajorVersion; uint32_t contextClientMinorVersion; uint32_t frameStart; uint32_t frameEnd; uint32_t drawSurfaceWidth; uint32_t drawSurfaceHeight; uint32_t drawSurfaceColorSpace; uint32_t displayPlatformType; uint32_t displayDeviceType; int configRedBits; int configBlueBits; int configGreenBits; int configAlphaBits; int configDepthBits; int configStencilBits; bool isBinaryDataCompressed; bool areClientArraysEnabled; bool isBindGeneratesResourcesEnabled; bool isWebGLCompatibilityEnabled; bool isRobustResourceInitEnabled; std::vector traceFiles; int windowSurfaceContextId; std::vector requiredExtensions; std::vector keyFrames; }; bool LoadTraceNamesFromJSON(const std::string jsonFilePath, std::vector *namesOut); bool LoadTraceInfoFromJSON(const std::string &traceName, const std::string &traceJsonPath, TraceInfo *traceInfoOut); using TraceFunction = std::vector; using TraceFunctionMap = std::map; void ReplayTraceFunctionCall(const CallCapture &call, const TraceFunctionMap &customFunctions); void ReplayCustomFunctionCall(const CallCapture &call, const TraceFunctionMap &customFunctions); template struct AssertFalse : std::false_type {}; GLuint GetResourceIDMapValue(ResourceIDType resourceIDType, GLuint key); template T GetParamValue(ParamType type, const ParamValue &value); template <> inline GLuint GetParamValue(ParamType type, const ParamValue &value) { ResourceIDType resourceIDType = GetResourceIDTypeFromParamType(type); if (resourceIDType == ResourceIDType::InvalidEnum) { return value.GLuintVal; } else { return GetResourceIDMapValue(resourceIDType, value.GLuintVal); } } template <> inline GLint GetParamValue(ParamType type, const ParamValue &value) { return value.GLintVal; } template <> inline const void *GetParamValue(ParamType type, const ParamValue &value) { return value.voidConstPointerVal; } template <> inline GLuint64 GetParamValue(ParamType type, const ParamValue &value) { return value.GLuint64Val; } template <> inline GLint64 GetParamValue(ParamType type, const ParamValue &value) { return value.GLint64Val; } template <> inline const char *GetParamValue(ParamType type, const ParamValue &value) { return value.GLcharConstPointerVal; } template <> inline void *GetParamValue(ParamType type, const ParamValue &value) { return value.voidPointerVal; } #if defined(ANGLE_IS_64_BIT_CPU) template <> inline const EGLAttrib *GetParamValue(ParamType type, const ParamValue &value) { return value.EGLAttribConstPointerVal; } #endif // defined(ANGLE_IS_64_BIT_CPU) template <> inline const EGLint *GetParamValue(ParamType type, const ParamValue &value) { return value.EGLintConstPointerVal; } template <> inline const GLchar *const *GetParamValue(ParamType type, const ParamValue &value) { return value.GLcharConstPointerPointerVal; } // On Apple platforms, std::is_same is false despite being both 8 bits. #if defined(ANGLE_PLATFORM_APPLE) || !defined(ANGLE_IS_64_BIT_CPU) template <> inline long GetParamValue(ParamType type, const ParamValue &value) { return static_cast(value.GLint64Val); } template <> inline unsigned long GetParamValue(ParamType type, const ParamValue &value) { return static_cast(value.GLuint64Val); } #endif // defined(ANGLE_PLATFORM_APPLE) template T GetParamValue(ParamType type, const ParamValue &value) { static_assert(AssertFalse::value, "No specialization for type."); } template struct Traits; template struct Traits { static constexpr size_t NArgs = sizeof...(Args); template struct Arg { typedef typename std::tuple_element>::type Type; }; }; template using FnArg = typename Traits::template Arg::Type; template using EnableIfNArgs = typename std::enable_if_t::NArgs == NArgs, int>; template FnArg Arg(const Captures &cap) { ASSERT(Idx < cap.size()); return GetParamValue>(cap[Idx].type, cap[Idx].value); } } // namespace angle #endif // UTIL_CAPTURE_FRAME_CAPTURE_TEST_UTILS_H_