| // | |
| // Copyright 2022 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_utils.cpp: | |
| // ANGLE Frame capture common classes. | |
| // | |
| #include "common/frame_capture_utils.h" | |
| namespace angle | |
| { | |
| namespace | |
| { | |
| // Keep the simplest nullptr string for easy C parsing. | |
| constexpr char kNullPointerString[] = "0"; | |
| } // anonymous namespace | |
| ParamCapture::ParamCapture() : type(ParamType::TGLenum), enumGroup(gl::GLESEnum::AllEnums) {} | |
| ParamCapture::ParamCapture(const char *nameIn, ParamType typeIn) | |
| : name(nameIn), | |
| type(typeIn), | |
| enumGroup(gl::GLESEnum::AllEnums), | |
| bigGLEnum(gl::BigGLEnum::AllEnums) | |
| {} | |
| ParamCapture::~ParamCapture() = default; | |
| ParamCapture::ParamCapture(ParamCapture &&other) | |
| : type(ParamType::TGLenum), | |
| enumGroup(gl::GLESEnum::AllEnums), | |
| bigGLEnum(gl::BigGLEnum::AllEnums) | |
| { | |
| *this = std::move(other); | |
| } | |
| ParamCapture &ParamCapture::operator=(ParamCapture &&other) | |
| { | |
| std::swap(name, other.name); | |
| std::swap(type, other.type); | |
| std::swap(value, other.value); | |
| std::swap(enumGroup, other.enumGroup); | |
| std::swap(bigGLEnum, other.bigGLEnum); | |
| std::swap(data, other.data); | |
| std::swap(arrayClientPointerIndex, other.arrayClientPointerIndex); | |
| std::swap(readBufferSizeBytes, other.readBufferSizeBytes); | |
| std::swap(dataNElements, other.dataNElements); | |
| return *this; | |
| } | |
| ParamBuffer::ParamBuffer() {} | |
| ParamBuffer::~ParamBuffer() = default; | |
| ParamBuffer::ParamBuffer(ParamBuffer &&other) | |
| { | |
| *this = std::move(other); | |
| } | |
| ParamBuffer &ParamBuffer::operator=(ParamBuffer &&other) | |
| { | |
| std::swap(mParamCaptures, other.mParamCaptures); | |
| std::swap(mClientArrayDataParam, other.mClientArrayDataParam); | |
| std::swap(mReadBufferSize, other.mReadBufferSize); | |
| std::swap(mReturnValueCapture, other.mReturnValueCapture); | |
| return *this; | |
| } | |
| ParamCapture &ParamBuffer::getParam(const char *paramName, ParamType paramType, int index) | |
| { | |
| ParamCapture &capture = mParamCaptures[index]; | |
| ASSERT(capture.name == paramName); | |
| ASSERT(capture.type == paramType); | |
| return capture; | |
| } | |
| const ParamCapture &ParamBuffer::getParam(const char *paramName, | |
| ParamType paramType, | |
| int index) const | |
| { | |
| return const_cast<ParamBuffer *>(this)->getParam(paramName, paramType, index); | |
| } | |
| ParamCapture &ParamBuffer::getParamFlexName(const char *paramName1, | |
| const char *paramName2, | |
| ParamType paramType, | |
| int index) | |
| { | |
| ParamCapture &capture = mParamCaptures[index]; | |
| ASSERT(capture.name == paramName1 || capture.name == paramName2); | |
| ASSERT(capture.type == paramType); | |
| return capture; | |
| } | |
| const ParamCapture &ParamBuffer::getParamFlexName(const char *paramName1, | |
| const char *paramName2, | |
| ParamType paramType, | |
| int index) const | |
| { | |
| return const_cast<ParamBuffer *>(this)->getParamFlexName(paramName1, paramName2, paramType, | |
| index); | |
| } | |
| void ParamBuffer::addParam(ParamCapture &¶m) | |
| { | |
| if (param.arrayClientPointerIndex != -1) | |
| { | |
| ASSERT(mClientArrayDataParam == -1); | |
| mClientArrayDataParam = static_cast<int>(mParamCaptures.size()); | |
| } | |
| mReadBufferSize = std::max(param.readBufferSizeBytes, mReadBufferSize); | |
| mParamCaptures.emplace_back(std::move(param)); | |
| } | |
| void ParamBuffer::addReturnValue(ParamCapture &&returnValue) | |
| { | |
| mReturnValueCapture = std::move(returnValue); | |
| } | |
| const char *ParamBuffer::getNextParamName() | |
| { | |
| static const char *kParamNames[] = {"p0", "p1", "p2", "p3", "p4", "p5", "p6", | |
| "p7", "p8", "p9", "p10", "p11", "p12", "p13", | |
| "p14", "p15", "p16", "p17", "p18", "p19", "p20"}; | |
| ASSERT(mParamCaptures.size() < ArraySize(kParamNames)); | |
| return kParamNames[mParamCaptures.size()]; | |
| } | |
| ParamCapture &ParamBuffer::getClientArrayPointerParameter() | |
| { | |
| ASSERT(hasClientArrayData()); | |
| return mParamCaptures[mClientArrayDataParam]; | |
| } | |
| CallCapture::CallCapture(EntryPoint entryPointIn, ParamBuffer &¶msIn) | |
| : entryPoint(entryPointIn), params(std::move(paramsIn)) | |
| {} | |
| CallCapture::CallCapture(const std::string &customFunctionNameIn, ParamBuffer &¶msIn) | |
| : entryPoint(EntryPoint::Invalid), | |
| customFunctionName(customFunctionNameIn), | |
| params(std::move(paramsIn)) | |
| {} | |
| CallCapture::~CallCapture() = default; | |
| CallCapture::CallCapture(CallCapture &&other) | |
| { | |
| *this = std::move(other); | |
| } | |
| CallCapture &CallCapture::operator=(CallCapture &&other) | |
| { | |
| std::swap(entryPoint, other.entryPoint); | |
| std::swap(customFunctionName, other.customFunctionName); | |
| std::swap(params, other.params); | |
| std::swap(isActive, other.isActive); | |
| return *this; | |
| } | |
| const char *CallCapture::name() const | |
| { | |
| if (customFunctionName.empty()) | |
| { | |
| ASSERT(entryPoint != EntryPoint::Invalid); | |
| return angle::GetEntryPointName(entryPoint); | |
| } | |
| else | |
| { | |
| return customFunctionName.c_str(); | |
| } | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TGLboolean>(std::ostream &os, | |
| const CallCapture &call, | |
| GLboolean value) | |
| { | |
| switch (value) | |
| { | |
| case GL_TRUE: | |
| os << "GL_TRUE"; | |
| break; | |
| case GL_FALSE: | |
| os << "GL_FALSE"; | |
| break; | |
| default: | |
| os << "0x" << std::hex << std::uppercase << GLint(value); | |
| } | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TGLbooleanPointer>(std::ostream &os, | |
| const CallCapture &call, | |
| GLboolean *value) | |
| { | |
| if (value == 0) | |
| { | |
| os << kNullPointerString; | |
| } | |
| else | |
| { | |
| os << "(GLboolean *)" << static_cast<int>(reinterpret_cast<uintptr_t>(value)); | |
| } | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TvoidConstPointer>(std::ostream &os, | |
| const CallCapture &call, | |
| const void *value) | |
| { | |
| if (value == 0) | |
| { | |
| os << kNullPointerString; | |
| } | |
| else | |
| { | |
| os << "(const void *)" << static_cast<int>(reinterpret_cast<uintptr_t>(value)); | |
| } | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TvoidPointer>(std::ostream &os, | |
| const CallCapture &call, | |
| void *value) | |
| { | |
| if (value == 0) | |
| { | |
| os << kNullPointerString; | |
| } | |
| else | |
| { | |
| os << "(void *)" << static_cast<int>(reinterpret_cast<uintptr_t>(value)); | |
| } | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TGLfloatConstPointer>(std::ostream &os, | |
| const CallCapture &call, | |
| const GLfloat *value) | |
| { | |
| if (value == 0) | |
| { | |
| os << kNullPointerString; | |
| } | |
| else | |
| { | |
| os << "(const GLfloat *)" << static_cast<int>(reinterpret_cast<uintptr_t>(value)); | |
| } | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TGLintConstPointer>(std::ostream &os, | |
| const CallCapture &call, | |
| const GLint *value) | |
| { | |
| if (value == 0) | |
| { | |
| os << kNullPointerString; | |
| } | |
| else | |
| { | |
| os << "(const GLint *)" << static_cast<int>(reinterpret_cast<intptr_t>(value)); | |
| } | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TGLsizeiPointer>(std::ostream &os, | |
| const CallCapture &call, | |
| GLsizei *value) | |
| { | |
| if (value == 0) | |
| { | |
| os << kNullPointerString; | |
| } | |
| else | |
| { | |
| os << "(GLsizei *)" << static_cast<int>(reinterpret_cast<intptr_t>(value)); | |
| } | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TGLuintConstPointer>(std::ostream &os, | |
| const CallCapture &call, | |
| const GLuint *value) | |
| { | |
| if (value == 0) | |
| { | |
| os << kNullPointerString; | |
| } | |
| else | |
| { | |
| os << "(const GLuint *)" << static_cast<int>(reinterpret_cast<uintptr_t>(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) | |
| { | |
| os << "gBufferMap[" << value.value << "]"; | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TFenceNVID>(std::ostream &os, | |
| const CallCapture &call, | |
| gl::FenceNVID value) | |
| { | |
| os << "gFenceNVMap[" << value.value << "]"; | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TFramebufferID>(std::ostream &os, | |
| const CallCapture &call, | |
| gl::FramebufferID value) | |
| { | |
| os << "gFramebufferMap[" << value.value << "]"; | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TMemoryObjectID>(std::ostream &os, | |
| const CallCapture &call, | |
| gl::MemoryObjectID value) | |
| { | |
| os << "gMemoryObjectMap[" << value.value << "]"; | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TProgramPipelineID>(std::ostream &os, | |
| const CallCapture &call, | |
| gl::ProgramPipelineID value) | |
| { | |
| os << "gProgramPipelineMap[" << value.value << "]"; | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TQueryID>(std::ostream &os, | |
| const CallCapture &call, | |
| gl::QueryID value) | |
| { | |
| os << "gQueryMap[" << value.value << "]"; | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TRenderbufferID>(std::ostream &os, | |
| const CallCapture &call, | |
| gl::RenderbufferID value) | |
| { | |
| os << "gRenderbufferMap[" << value.value << "]"; | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TSamplerID>(std::ostream &os, | |
| const CallCapture &call, | |
| gl::SamplerID value) | |
| { | |
| os << "gSamplerMap[" << value.value << "]"; | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TSemaphoreID>(std::ostream &os, | |
| const CallCapture &call, | |
| gl::SemaphoreID value) | |
| { | |
| os << "gSemaphoreMap[" << value.value << "]"; | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TShaderProgramID>(std::ostream &os, | |
| const CallCapture &call, | |
| gl::ShaderProgramID value) | |
| { | |
| os << "gShaderProgramMap[" << value.value << "]"; | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TGLsync>(std::ostream &os, | |
| const CallCapture &call, | |
| GLsync value) | |
| { | |
| os << "gSyncMap[" << FmtPointerIndex(value) << "]"; | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TTextureID>(std::ostream &os, | |
| const CallCapture &call, | |
| gl::TextureID value) | |
| { | |
| os << "gTextureMap[" << value.value << "]"; | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TTransformFeedbackID>(std::ostream &os, | |
| const CallCapture &call, | |
| gl::TransformFeedbackID value) | |
| { | |
| os << "gTransformFeedbackMap[" << value.value << "]"; | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TVertexArrayID>(std::ostream &os, | |
| const CallCapture &call, | |
| gl::VertexArrayID value) | |
| { | |
| os << "gVertexArrayMap[" << value.value << "]"; | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TUniformLocation>(std::ostream &os, | |
| const CallCapture &call, | |
| gl::UniformLocation value) | |
| { | |
| if (value.value == -1) | |
| { | |
| os << "-1"; | |
| return; | |
| } | |
| os << "gUniformLocations["; | |
| // Find the program from the call parameters. | |
| std::vector<gl::ShaderProgramID> programIDs; | |
| if (FindShaderProgramIDsInCall(call, programIDs)) | |
| { | |
| ASSERT(programIDs.size() == 1); | |
| os << programIDs[0].value; | |
| } | |
| else | |
| { | |
| os << "gCurrentProgram"; | |
| } | |
| os << "][" << value.value << "]"; | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TUniformBlockIndex>(std::ostream &os, | |
| const CallCapture &call, | |
| gl::UniformBlockIndex value) | |
| { | |
| // We do not support directly using uniform block indexes due to their multiple indirections. | |
| // Use CaptureCustomUniformBlockBinding if you end up hitting this assertion. | |
| UNREACHABLE(); | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TGLubyte>(std::ostream &os, | |
| const CallCapture &call, | |
| GLubyte value) | |
| { | |
| const int v = value; | |
| os << v; | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TEGLDEBUGPROCKHR>(std::ostream &os, | |
| const CallCapture &call, | |
| EGLDEBUGPROCKHR value) | |
| { | |
| // It's not necessary to implement correct capture for these types. | |
| os << "0"; | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TEGLGetBlobFuncANDROID>(std::ostream &os, | |
| const CallCapture &call, | |
| EGLGetBlobFuncANDROID value) | |
| { | |
| // It's not necessary to implement correct capture for these types. | |
| os << "0"; | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TEGLSetBlobFuncANDROID>(std::ostream &os, | |
| const CallCapture &call, | |
| EGLSetBlobFuncANDROID value) | |
| { | |
| // It's not necessary to implement correct capture for these types. | |
| os << "0"; | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::Tegl_ConfigPointer>(std::ostream &os, | |
| const CallCapture &call, | |
| egl::Config *value) | |
| { | |
| os << "EGL_NO_CONFIG_KHR"; | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TSurfaceID>(std::ostream &os, | |
| const CallCapture &call, | |
| egl::SurfaceID value) | |
| { | |
| os << "gSurfaceMap2[" << value.value << "]"; | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TContextID>(std::ostream &os, | |
| const CallCapture &call, | |
| gl::ContextID value) | |
| { | |
| os << "gContextMap2[" << value.value << "]"; | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::Tegl_DisplayPointer>(std::ostream &os, | |
| const CallCapture &call, | |
| egl::Display *value) | |
| { | |
| os << "EGL_NO_DISPLAY"; | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TImageID>(std::ostream &os, | |
| const CallCapture &call, | |
| egl::ImageID value) | |
| { | |
| os << "gEGLImageMap2[" << value.value << "]"; | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TEGLClientBuffer>(std::ostream &os, | |
| const CallCapture &call, | |
| EGLClientBuffer value) | |
| { | |
| os << value; | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::Tegl_SyncPointer>(std::ostream &os, | |
| const CallCapture &call, | |
| egl::Sync *value) | |
| { | |
| os << "EGL_NO_SYNC_KHR"; | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TEGLAttribPointer>(std::ostream &os, | |
| const CallCapture &call, | |
| const EGLAttrib *value) | |
| { | |
| if (value == 0) | |
| { | |
| os << kNullPointerString; | |
| } | |
| else | |
| { | |
| os << "(const EGLAttrib *)" << static_cast<int>(reinterpret_cast<uintptr_t>(value)); | |
| } | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TEGLintConstPointer>(std::ostream &os, | |
| const CallCapture &call, | |
| const EGLint *value) | |
| { | |
| if (value == 0) | |
| { | |
| os << kNullPointerString; | |
| } | |
| else | |
| { | |
| os << "(const EGLint *)" << static_cast<int>(reinterpret_cast<uintptr_t>(value)); | |
| } | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TEGLintPointer>(std::ostream &os, | |
| const CallCapture &call, | |
| EGLint *value) | |
| { | |
| if (value == 0) | |
| { | |
| os << kNullPointerString; | |
| } | |
| else | |
| { | |
| os << "(const EGLint *)" << static_cast<int>(reinterpret_cast<uintptr_t>(value)); | |
| } | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TEGLTime>(std::ostream &os, | |
| const CallCapture &call, | |
| EGLTime value) | |
| { | |
| os << value << "ul"; | |
| } | |
| template <> | |
| void WriteParamValueReplay<ParamType::TEGLTimeKHR>(std::ostream &os, | |
| const CallCapture &call, | |
| EGLTimeKHR value) | |
| { | |
| os << value << "ul"; | |
| } | |
| bool FindShaderProgramIDsInCall(const CallCapture &call, std::vector<gl::ShaderProgramID> &idsOut) | |
| { | |
| for (const ParamCapture ¶m : call.params.getParamCaptures()) | |
| { | |
| // Only checking for programs right now, but could be expanded to all ResourceTypes | |
| if (param.type == ParamType::TShaderProgramID) | |
| { | |
| idsOut.push_back(param.value.ShaderProgramIDVal); | |
| } | |
| } | |
| return !idsOut.empty(); | |
| } | |
| } // namespace angle |