| // |
| // 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", "p21", "p22"}; |
| 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); |
| std::swap(contextID, other.contextID); |
| std::swap(isSyncPoint, other.isSyncPoint); |
| 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::TSyncID>(std::ostream &os, |
| const CallCapture &call, |
| gl::SyncID value) |
| { |
| os << "gSyncMap2[" << value.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> shaderProgramIDs; |
| if (FindResourceIDsInCall<gl::ShaderProgramID>(call, shaderProgramIDs)) |
| { |
| ASSERT(shaderProgramIDs.size() == 1); |
| os << shaderProgramIDs[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 << "gEGLDisplay"; |
| } |
| |
| 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_SyncID>(std::ostream &os, |
| const CallCapture &call, |
| egl::SyncID value) |
| { |
| os << "gEGLSyncMap[" << value.value << "]"; |
| } |
| |
| 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"; |
| } |
| |
| template <typename ParamValueType> |
| bool FindResourceIDsInCall(const CallCapture &call, std::vector<ParamValueType> &idsOut) |
| { |
| const ParamType paramType = ParamValueTrait<ParamValueType>::typeID; |
| for (const ParamCapture ¶m : call.params.getParamCaptures()) |
| { |
| if (param.type == paramType) |
| { |
| const ParamValueType id = AccessParamValue<ParamValueType>(paramType, param.value); |
| idsOut.push_back(id); |
| } |
| } |
| |
| return !idsOut.empty(); |
| } |
| |
| // Explicit instantiation |
| template bool FindResourceIDsInCall<gl::TextureID>(const CallCapture &call, |
| std::vector<gl::TextureID> &idsOut); |
| template bool FindResourceIDsInCall<gl::ShaderProgramID>(const CallCapture &call, |
| std::vector<gl::ShaderProgramID> &idsOut); |
| } // namespace angle |